diff options
318 files changed, 7213 insertions, 3674 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index aa6b412d73b..f8baf317e72 100644 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -6,6 +6,7 @@ fi just_print= just_configure= +full_debug= while test $# -gt 0 do case "$1" in @@ -21,6 +22,7 @@ Any other options will be passed directly to configure. Note: this script is intended for internal use by MySQL developers. EOF + --with-debug=full ) full_debug="=full"; shift ;; * ) break ;; esac done @@ -48,7 +50,8 @@ fast_cflags="-O3 -fno-omit-frame-pointer" # this is one is for someone who thinks 1% speedup is worth not being # able to backtrace reckless_cflags="-O3 -fomit-frame-pointer " -debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX -O1 -Wuninitialized" + +debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX" base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" @@ -62,7 +65,11 @@ sparc_configs="" # and unset local_infile_configs local_infile_configs="--enable-local-infile" -debug_configs="--with-debug" +debug_configs="--with-debug$full_debug" +if [ -z "$full_debug" ] +then + debug_cflags="$debug_cflags -O1 -Wuninitialized" +fi if gmake --version > /dev/null 2>&1 then diff --git a/client/client_priv.h b/client/client_priv.h index 328c051905c..f16ec0e802b 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -45,5 +45,5 @@ enum options_client OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS, OPT_START_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, - OPT_SIGINT_IGNORE + OPT_SIGINT_IGNORE, OPT_HEXBLOB }; diff --git a/client/mysqldump.c b/client/mysqldump.c index 56505afd235..1686278096b 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -81,7 +81,8 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1, opt_alldbs=0,opt_create_db=0,opt_first_slave=0,opt_set_charset, opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, opt_delete_master_logs=0, tty_password=0, - opt_single_transaction=0, opt_comments= 0, opt_compact= 0; + opt_single_transaction=0, opt_comments= 0, opt_compact= 0, + opt_hex_blob=0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, @@ -316,6 +317,8 @@ static struct my_option my_long_options[] = {"comments", 'i', "Write additional information.", (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"hex-blob", OPT_HEXBLOB, "Dump BLOBs in HEX. this mode does not work with extended-insert", + (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1507,6 +1510,7 @@ static void dumpTable(uint numFields, char *table) for (i = 0; i < mysql_num_fields(res); i++) { + int is_blob; if (!(field = mysql_fetch_field(res))) { sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", @@ -1515,6 +1519,17 @@ static void dumpTable(uint numFields, char *table) error= EX_CONSCHECK; goto err; } + + /* + 63 is my_charset_bin. If charsetnr is not 63, + we have not a BLOB but a TEXT column. + we'll dump it in hex only BLOB columns. + */ + is_blob= (opt_hex_blob && field->charsetnr == 63 && + (field->type == FIELD_TYPE_BLOB || + field->type == FIELD_TYPE_LONG_BLOB || + field->type == FIELD_TYPE_MEDIUM_BLOB || + field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0; if (extended_insert) { ulong length = lengths[i]; @@ -1535,12 +1550,28 @@ static void dumpTable(uint numFields, char *table) error= EX_EOM; goto err; } - dynstr_append(&extended_row,"'"); - extended_row.length += - mysql_real_escape_string(&mysql_connection, - &extended_row.str[extended_row.length],row[i],length); - extended_row.str[extended_row.length]='\0'; - dynstr_append(&extended_row,"'"); + if (opt_hex_blob && is_blob) + { + ulong counter; + unsigned char *ptr= row[i]; + dynstr_append(&extended_row, "0x"); + for (counter = 0; counter < lengths[i]; counter++) + { + char xx[3]; + sprintf(xx, "%02X", ptr[counter]); + dynstr_append(&extended_row, xx); + } + } + else + { + dynstr_append(&extended_row,"'"); + extended_row.length += + mysql_real_escape_string(&mysql_connection, + &extended_row.str[extended_row.length], + row[i],length); + extended_row.str[extended_row.length]='\0'; + dynstr_append(&extended_row,"'"); + } } else { @@ -1591,8 +1622,20 @@ static void dumpTable(uint numFields, char *table) print_quoted_xml(md_result_file, row[i], lengths[i]); fputs("</field>\n", md_result_file); } - else - unescape(md_result_file, row[i], lengths[i]); + else if (opt_hex_blob && is_blob) + { /* sakaik got this idea. */ + ulong counter; + char xx[4]; + unsigned char *ptr= row[i]; + fputs("0x", md_result_file); + for (counter = 0; counter < lengths[i]; counter++) + { + sprintf(xx, "%02X", ptr[counter]); + fputs(xx, md_result_file); + } + } + else + unescape(md_result_file, row[i], lengths[i]); } else { diff --git a/client/mysqltest.c b/client/mysqltest.c index d2d110c7954..7a42cd54ca6 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -58,13 +58,6 @@ #include <stdarg.h> #include <sys/stat.h> #include <violite.h> -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif - -#ifndef MAXPATHLEN -#define MAXPATHLEN 256 -#endif #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 @@ -102,6 +95,38 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER}; +/* ************************************************************************ */ +/* + A line that starts with !$ or $S, and the list of error codes to + --error are stored in an internal array of structs. This struct can + hold numeric SQL error codes or SQLSTATE codes as strings. The + element next to the last active element in the list is set to type + ERR_EMPTY. When an SQL statement return an error we use this list to + check if this is an expected error. +*/ + +enum match_err_type +{ + ERR_EMPTY= 0, + ERR_ERRNO, + ERR_SQLSTATE +}; + +typedef struct +{ + enum match_err_type type; + union + { + uint errnum; + char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */ + } code; +} match_err; + +static match_err global_expected_errno[MAX_EXPECTED_ERRORS]; +static uint global_expected_errors; + +/* ************************************************************************ */ + static int record = 0, opt_sleep=0; static char *db = 0, *pass=0; const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; @@ -131,8 +156,8 @@ static int *cur_block, *block_stack_end; static int block_stack[BLOCK_STACK_DEPTH]; static int block_ok_stack[BLOCK_STACK_DEPTH]; -static uint global_expected_errno[MAX_EXPECTED_ERRORS], global_expected_errors; -static CHARSET_INFO *charset_info= &my_charset_latin1; +static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ +static char *charset_name = "latin1"; /* Default character set name */ static int embedded_server_arg_count=0; static char *embedded_server_args[MAX_SERVER_ARGS]; @@ -245,6 +270,7 @@ Q_EXEC, Q_DELIMITER, Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_START_TIMER, Q_END_TIMER, +Q_CHARACTER_SET, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -257,7 +283,7 @@ struct st_query char *query, *query_buf,*first_argument,*end; int first_word_len; my_bool abort_on_error, require_file; - uint expected_errno[MAX_EXPECTED_ERRORS]; + match_err expected_errno[MAX_EXPECTED_ERRORS]; uint expected_errors; char record_file[FN_REFLEN]; enum enum_commands type; @@ -325,6 +351,7 @@ const char *command_names[]= "query_horizontal", "start_timer", "end_timer", + "character_set", 0 }; @@ -346,6 +373,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); void reject_dump(const char *record_file, char *buf, int size); int close_connection(struct st_query* q); +static void set_charset(struct st_query*); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); int eval_expr(VAR* v, const char *p, const char** p_end); @@ -1246,25 +1274,58 @@ static void get_file_name(char *filename, struct st_query* q) p[0]=0; } +static void set_charset(struct st_query* q) +{ + char* charset_name= q->first_argument; + char* tmp; + + if (!charset_name || !*charset_name) + die("Missing charset name in 'character_set'\n"); + /* Remove end space */ + tmp= charset_name; + while (*tmp && !my_isspace(charset_info,*tmp)) + tmp++; + *tmp= 0; -static uint get_ints(uint *to,struct st_query* q) + charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); + if (!charset_info) + abort_not_supported_test(); +} + +static uint get_errcodes(match_err *to,struct st_query* q) { - char* p=q->first_argument; - long val; - uint count=0; - DBUG_ENTER("get_ints"); + char* p= q->first_argument; + uint count= 0; + DBUG_ENTER("get_errcodes"); if (!*p) die("Missing argument in %s\n", q->query); - for (; (p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val)) ; p++) + do { + if (*p == 'S') + { + /* SQLSTATE string */ + int i; + p++; + for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++) + to[count].code.sqlstate[i]= *p; + to[count].code.sqlstate[i]= '\0'; + to[count].type= ERR_SQLSTATE; + } + else + { + long val; + p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val); + if (p == NULL) + die("Invalid argument in %s\n", q->query); + to[count].code.errnum= (uint) val; + to[count].type= ERR_ERRNO; + } count++; - *to++= (uint) val; - if (*p != ',') - break; - } - *to++=0; /* End of data */ + } while (*(p++) == ','); + + to[count].type= ERR_EMPTY; /* End of data */ DBUG_RETURN(count); } @@ -1590,7 +1651,7 @@ int do_connect(struct st_query* q) if (opt_compress) mysql_options(&next_con->mysql,MYSQL_OPT_COMPRESS,NullS); mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, "latin1"); + mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); #ifdef HAVE_OPENSSL if (opt_use_ssl) @@ -1736,6 +1797,7 @@ int read_line(char* buf, int size) c= my_getc(*cur_file); if (feof(*cur_file)) { + found_eof: if ((*cur_file) != stdin) my_fclose(*cur_file, MYF(0)); cur_file--; @@ -1845,7 +1907,39 @@ int read_line(char* buf, int size) } if (!no_save) - *p++= c; + { + /* Could be a multibyte character */ + /* This code is based on the code in "sql_load.cc" */ +#ifdef USE_MB + int charlen = my_mbcharlen(charset_info, c); + /* We give up if multibyte character is started but not */ + /* completed before we pass buf_end */ + if ((charlen > 1) && (p + charlen) <= buf_end) + { + int i; + char* mb_start = p; + + *p++ = c; + + for (i= 1; i < charlen; i++) + { + if (feof(*cur_file)) + goto found_eof; /* FIXME: could we just break here?! */ + c= my_getc(*cur_file); + *p++ = c; + } + if (! my_ismbchar(charset_info, mb_start, p)) + { + /* It was not a multiline char, push back the characters */ + /* We leave first 'c', i.e. pretend it was a normal char */ + while (p > mb_start) + my_ungetc(*--p); + } + } + else +#endif + *p++= c; + } } *p= 0; /* Always end with \0 */ DBUG_RETURN(feof(*cur_file)); @@ -1857,7 +1951,6 @@ static char read_query_buf[MAX_QUERY]; int read_query(struct st_query** q_ptr) { char *p = read_query_buf, * p1 ; - int expected_errno; struct st_query* q; DBUG_ENTER("read_query"); @@ -1907,13 +2000,25 @@ int read_query(struct st_query** q_ptr) p++; if (*p == '$') { - expected_errno= 0; - p++; - for (; my_isdigit(charset_info, *p); p++) - expected_errno = expected_errno * 10 + *p - '0'; - q->expected_errno[0] = expected_errno; - q->expected_errno[1] = 0; - q->expected_errors=1; + int expected_errno= 0; + p++; + for (; my_isdigit(charset_info, *p); p++) + expected_errno = expected_errno * 10 + *p - '0'; + q->expected_errno[0].code.errnum = expected_errno; + q->expected_errno[0].type= ERR_ERRNO; + q->expected_errno[1].type= ERR_EMPTY; + q->expected_errors=1; + } + else if (*p == 'S') /* SQLSTATE */ + { + int i; + p++; + for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++) + q->expected_errno[0].code.sqlstate[i]= *p; + q->expected_errno[0].code.sqlstate[i]= '\0'; + q->expected_errno[0].type= ERR_SQLSTATE; + q->expected_errno[1].type= ERR_EMPTY; + q->expected_errors=1; } } @@ -2105,10 +2210,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), embedded_server_arg_count=1; embedded_server_args[0]= (char*) ""; } - embedded_server_args[embedded_server_arg_count++]= - my_strdup(argument, MYF(MY_FAE)); - if (embedded_server_arg_count == MAX_SERVER_ARGS || - !embedded_server_args[embedded_server_arg_count-1]) + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) { die("Can't use server argument"); } @@ -2166,7 +2270,7 @@ char* safe_str_append(char* buf, const char* str, int size) void str_to_file(const char* fname, char* str, int size) { int fd; - char buff[MAXPATHLEN]; + char buff[FN_REFLEN]; if (!test_if_hard_path(fname)) { strxmov(buff, opt_basedir, fname, NullS); @@ -2300,7 +2404,7 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) if (flags & QUERY_SEND) { got_error_on_send= mysql_send_query(mysql, query, query_len); - if (got_error_on_send && !q->expected_errno[0]) + if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) die("At line %u: unable to send query '%s' (mysql_errno=%d , errno=%d)", start_lineno, query, mysql_errno(mysql), errno); } @@ -2332,7 +2436,10 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) { for (i=0 ; (uint) i < q->expected_errors ; i++) { - if ((q->expected_errno[i] == mysql_errno(mysql))) + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0))) { if (i == 0 && q->expected_errors == 1) { @@ -2346,7 +2453,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) dynstr_append_mem(ds,"\n",1); } /* Don't log error if we may not get an error */ - else if (q->expected_errno[0] != 0) + else if (q->expected_errno[0].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) dynstr_append(ds,"Got one of the listed errors\n"); goto end; /* Ok */ } @@ -2362,8 +2471,12 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) dynstr_append_mem(ds,"\n",1); if (i) { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), q->expected_errno[0]); + if (q->expected_errno[0].type == ERR_ERRNO) + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum); + else + verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate); error= 1; goto end; } @@ -2383,11 +2496,22 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) }*/ } - if (q->expected_errno[0]) + if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) { - error = 1; + /* Error code we wanted was != 0, i.e. not an expected success */ verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0]); + q->query, q->expected_errno[0].code.errnum); + error = 1; + goto end; + } + else if (q->expected_errno[0].type == ERR_SQLSTATE && + strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + { + /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ + verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); + error = 1; goto end; } @@ -2678,7 +2802,7 @@ int main(int argc, char **argv) if (opt_compress) mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS); mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, "latin1"); + mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); #ifdef HAVE_OPENSSL if (opt_use_ssl) @@ -2818,7 +2942,7 @@ int main(int argc, char **argv) require_file=0; break; case Q_ERROR: - global_expected_errors=get_ints(global_expected_errno,q); + global_expected_errors=get_errcodes(global_expected_errno,q); break; case Q_REQUIRE: get_file_name(save_file,q); @@ -2863,6 +2987,9 @@ int main(int argc, char **argv) timer_output(); got_end_timer= TRUE; break; + case Q_CHARACTER_SET: + set_charset(q); + break; default: processed = 0; break; } } @@ -2979,10 +3106,10 @@ static void timer_output(void) { if (timer_file) { - char buf[1024]; + char buf[32], *end; ulonglong timer= timer_now() - timer_start; - sprintf(buf,"%llu",timer); - str_to_file(timer_file,buf,strlen(buf)); + end= longlong2str(timer, buf, 10); + str_to_file(timer_file,buf, (int) (end-buf)); } } diff --git a/cmd-line-utils/libedit/np/vis.c b/cmd-line-utils/libedit/np/vis.c index db42443800b..e8f5c195f10 100644 --- a/cmd-line-utils/libedit/np/vis.c +++ b/cmd-line-utils/libedit/np/vis.c @@ -63,7 +63,7 @@ __weak_alias(vis,_vis) #include <limits.h> #include <stdio.h> #include <string.h> - +#include <assert.h> #undef BELL #if defined(__STDC__) #define BELL '\a' @@ -79,22 +79,24 @@ __weak_alias(vis,_vis) #define MAXEXTRAS 5 -#define MAKEEXTRALIST(flag, extra, orig) \ -do { \ - const char *o = orig; \ - char *e; \ - while (*o++) \ - continue; \ - extra = alloca((size_t)((o - orig) + MAXEXTRAS)); \ - for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ - continue; \ - e--; \ - if (flag & VIS_SP) *e++ = ' '; \ - if (flag & VIS_TAB) *e++ = '\t'; \ - if (flag & VIS_NL) *e++ = '\n'; \ - if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ - *e = '\0'; \ -} while (/*CONSTCOND*/0) +char *MAKEEXTRALIST(unsigned int flag, const char *orig) +{ + const char *o = orig; + char *e, *extra; + while (*o++) + continue; + extra = (char*) malloc((size_t)((o - orig) + MAXEXTRAS)); + assert(extra); + for (o = orig, e = extra; (*e++ = *o++) != '\0';) + continue; + e--; + if (flag & VIS_SP) *e++ = ' '; + if (flag & VIS_TAB) *e++ = '\t'; + if (flag & VIS_NL) *e++ = '\n'; + if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; + *e = '\0'; + return extra; +} /* @@ -198,15 +200,16 @@ svis(dst, c, flag, nextc, extra) int c, flag, nextc; const char *extra; { - char *nextra; + char *nextra, *to_be_freed; _DIAGASSERT(dst != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra= to_be_freed= MAKEEXTRALIST(flag, extra); if (flag & VIS_HTTPSTYLE) HVIS(dst, c, flag, nextc, nextra); else SVIS(dst, c, flag, nextc, nextra); *dst = '\0'; + free(to_be_freed); return(dst); } @@ -235,12 +238,12 @@ strsvis(dst, src, flag, extra) { char c; char *start; - char *nextra; + char *nextra, *to_be_freed; _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra= to_be_freed= MAKEEXTRALIST(flag, extra); if (flag & VIS_HTTPSTYLE) { for (start = dst; (c = *src++) != '\0'; /* empty */) HVIS(dst, c, flag, *src, nextra); @@ -249,6 +252,7 @@ strsvis(dst, src, flag, extra) SVIS(dst, c, flag, *src, nextra); } *dst = '\0'; + free(to_be_freed); return (dst - start); } @@ -263,12 +267,12 @@ strsvisx(dst, src, len, flag, extra) { char c; char *start; - char *nextra; + char *nextra, *to_be_freed; _DIAGASSERT(dst != NULL); _DIAGASSERT(src != NULL); _DIAGASSERT(extra != NULL); - MAKEEXTRALIST(flag, nextra, extra); + nextra= to_be_freed= MAKEEXTRALIST(flag, extra); if (flag & VIS_HTTPSTYLE) { for (start = dst; len > 0; len--) { @@ -282,6 +286,7 @@ strsvisx(dst, src, len, flag, extra) } } *dst = '\0'; + free(to_be_freed); return (dst - start); } @@ -295,16 +300,18 @@ vis(dst, c, flag, nextc) int c, flag, nextc; { - char *extra; + char *extra, *to_be_freed; _DIAGASSERT(dst != NULL); - MAKEEXTRALIST(flag, extra, ""); + extra= to_be_freed= MAKEEXTRALIST(flag, ""); + if (flag & VIS_HTTPSTYLE) HVIS(dst, c, flag, nextc, extra); else SVIS(dst, c, flag, nextc, extra); *dst = '\0'; + free(to_be_freed); return (dst); } @@ -326,9 +333,12 @@ strvis(dst, src, flag) int flag; { char *extra; + int tmp; - MAKEEXTRALIST(flag, extra, ""); - return (strsvis(dst, src, flag, extra)); + extra= MAKEEXTRALIST(flag, ""); + tmp= strsvis(dst, src, flag, extra); + free(extra); + return tmp; } @@ -340,8 +350,11 @@ strvisx(dst, src, len, flag) int flag; { char *extra; + int tmp; - MAKEEXTRALIST(flag, extra, ""); - return (strsvisx(dst, src, len, flag, extra)); + extra= MAKEEXTRALIST(flag, ""); + tmp= strsvisx(dst, src, len, flag, extra); + free(extra); + return tmp; } #endif diff --git a/configure.in b/configure.in index b06fc35b23f..810f6c31c49 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ SHARED_LIB_VERSION=14:0:0 # ndb version NDB_VERSION_MAJOR=3 NDB_VERSION_MINOR=5 -NDB_VERSION_BUILD=2 +NDB_VERSION_BUILD=3 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? @@ -44,12 +44,12 @@ do case $host_os in netware* | modesto*) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err.linux -C\$(srcdir)/charsets/ \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err.linux -C\$(srcdir)/charsets/ $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; *) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err -C\$(srcdir)/charsets/ \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err -C\$(srcdir)/charsets/ $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; esac @@ -967,12 +967,16 @@ esac MAX_C_OPTIMIZE="-O3" MAX_CXX_OPTIMIZE="-O3" -# workaround for Sun Forte/x86 see BUG#4681 case $SYSTEM_TYPE-$MACHINE_TYPE-$ac_cv_prog_gcc in +# workaround for Sun Forte/x86 see BUG#4681 *solaris*-i?86-no) CFLAGS="$CFLAGS -DBIG_TABLES" CXXFLAGS="$CXXFLAGS -DBIG_TABLES" ;; +# workaround for Sun Forte compile problem for ndb + *solaris2.10*-sparc-no) + ndb_cxxflags_fix="$ndb_cxxflags_fix -instances=static" + ;; *) ;; esac @@ -1140,6 +1144,7 @@ dnl Is this the right match for DEC OSF on alpha? # gethostbyname_r is deprecated and doesn't work ok on OSF1 CFLAGS="$CFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R" CXXFLAGS="$CXXFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R" + ndb_cxxflags_fix="$ndb_cxxflags_fix -I/usr/include.dtk" ;; *netware*) # No need for curses library so set it to null diff --git a/include/m_ctype.h b/include/m_ctype.h index 1f42b514a1b..ddc21070547 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -365,6 +365,11 @@ uint my_instr_mb(struct charset_info_st *, const char *s, uint s_length, my_match_t *match, uint nmatch); +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str, const char *str_end, + const char *wildstr, const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights); extern my_bool my_parse_charset_xml(const char *bug, uint len, int (*add)(CHARSET_INFO *cs)); diff --git a/include/my_sys.h b/include/my_sys.h index 271e0ea0bcb..01a7482e4d0 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -726,7 +726,7 @@ extern void my_free_lock(byte *ptr,myf flags); #endif #define alloc_root_inited(A) ((A)->min_malloc != 0) #define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) -#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; } while(0) +#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; (A)->min_malloc=0;} while(0) extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size); extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); diff --git a/include/my_time.h b/include/my_time.h index d4dbe459c3b..dab17904b2d 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -60,6 +60,20 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap) void set_zero_time(MYSQL_TIME *tm); +/* + Required buffer length for my_time_to_str, my_date_to_str, + my_datetime_to_str and TIME_to_string functions. Note, that the + caller is still responsible to check that given TIME structure + has values in valid ranges, otherwise size of the buffer could + be not enough. +*/ +#define MAX_DATE_STRING_REP_LENGTH 30 + +int my_time_to_str(const MYSQL_TIME *l_time, char *to); +int my_date_to_str(const MYSQL_TIME *l_time, char *to); +int my_datetime_to_str(const MYSQL_TIME *l_time, char *to); +int my_TIME_to_str(const MYSQL_TIME *l_time, char *to); + C_MODE_END #endif /* _my_time_h_ */ diff --git a/include/mysql.h b/include/mysql.h index cf5af6ce189..1c886020fdb 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -506,6 +506,7 @@ char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, unsigned long *length)); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); +my_bool STDCALL mysql_embedded(void); MYSQL_MANAGER* STDCALL mysql_manager_init(MYSQL_MANAGER* con); MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, const char* host, diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index fd98538d2ad..c3d0d8d9ac1 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -53,6 +53,30 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve /* Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; +/********************************************************************** +Compares NUL-terminated UTF-8 strings case insensitively. + +NOTE: the prototype of this function is copied from ha_innodb.cc! If you change +this function, you MUST change also the prototype here! */ +extern +int +innobase_strcasecmp( +/*================*/ + /* out: 0 if a=b, <0 if a<b, >1 if a>b */ + const char* a, /* in: first string to compare */ + const char* b); /* in: second string to compare */ + +/********************************************************************** +Makes all characters in a NUL-terminated UTF-8 string lower case. + +NOTE: the prototype of this function is copied from ha_innodb.cc! If you change +this function, you MUST change also the prototype here! */ +extern +void +innobase_casedn_str( +/*================*/ + char* a); /* in/out: string to put in lower case */ + /************************************************************************** Adds a column to the data dictionary hash table. */ static @@ -2066,7 +2090,7 @@ dict_foreign_find_index( break; } - if (0 != ut_cmp_in_lower_case(columns[i], + if (0 != innobase_strcasecmp(columns[i], col_name)) { break; } @@ -2244,7 +2268,7 @@ dict_foreign_add_to_cache( Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity. Stops also at '\0'. */ -static + const char* dict_scan_to( /*=========*/ @@ -2436,7 +2460,7 @@ dict_scan_col( col = dict_table_get_nth_col(table, i); - if (0 == ut_cmp_in_lower_case(col->name, *name)) { + if (0 == innobase_strcasecmp(col->name, *name)) { /* Found */ *success = TRUE; @@ -2528,30 +2552,19 @@ dict_scan_table_name( table_name_len = strlen(table_name); + /* Copy database_name, '/', table_name, '\0' */ ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2); - -#ifdef __WIN__ - ut_cpy_in_lower_case(ref, database_name, database_name_len); -#else + memcpy(ref, database_name, database_name_len); + ref[database_name_len] = '/'; + memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); +#ifndef __WIN__ if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(ref, database_name, database_name_len); - } else { - memcpy(ref, database_name, database_name_len); +#endif /* !__WIN__ */ + /* The table name is always put to lower case on Windows. */ + innobase_casedn_str(ref); +#ifndef __WIN__ } -#endif - (ref)[database_name_len] = '/'; - -#ifdef __WIN__ - ut_cpy_in_lower_case(ref + database_name_len + 1, - table_name, table_name_len + 1); -#else - if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(ref + database_name_len + 1, - table_name, table_name_len + 1); - } else { - strcpy(ref + database_name_len + 1, table_name); - } -#endif +#endif /* !__WIN__ */ *success = TRUE; *ref_name = ref; diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 4dbbd5b4886..ca632691450 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -891,6 +891,18 @@ dict_tables_have_same_db( const char* name2); /* in: table name in the form dbname '/' tablename */ +/************************************************************************* +Scans from pointer onwards. Stops if is at the start of a copy of +'string' where characters are compared without case sensitivity. Stops +also at '\0'. */ + +const char* +dict_scan_to( +/*=========*/ + /* out: scanned up to this */ + const char* ptr, /* in: scan from */ + const char* string);/* in: look for this */ + /* Buffers for storing detailed information about the latest foreign key and unique key errors */ extern FILE* dict_foreign_err_file; diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index f1647c47bce..d1439faf29f 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -14,6 +14,7 @@ Created 10/21/1995 Heikki Tuuri #ifndef __WIN__ #include <dirent.h> #include <sys/stat.h> +#include <time.h> #endif extern ibool os_do_not_call_flush_at_each_write; @@ -142,12 +143,15 @@ bigger than 4000 bytes */ #define OS_FILE_MAX_PATH 4000 /* Struct used in fetching information of a file in a directory */ -typedef struct os_file_stat_struct os_file_stat_t; struct os_file_stat_struct{ - char name[OS_FILE_MAX_PATH]; /* path to a file */ - os_file_type_t type; /* file type */ - ib_longlong size; /* file size */ + char name[OS_FILE_MAX_PATH]; /* path to a file */ + os_file_type_t type; /* file type */ + ib_longlong size; /* file size */ + time_t ctime; /* creation time */ + time_t mtime; /* modification time */ + time_t atime; /* access time */ }; +typedef struct os_file_stat_struct os_file_stat_t; #ifdef __WIN__ typedef HANDLE os_file_dir_t; /* directory stream */ @@ -686,5 +690,14 @@ no pending io operations. */ ibool os_aio_all_slots_free(void); /*=======================*/ - /* out: TRUE if all free */ + +/*********************************************************************** +This function returns information about the specified file */ +ibool +os_file_get_status( +/*===============*/ + /* out: TRUE if stat information found */ + const char* path, /* in: pathname of the file */ + os_file_stat_t* stat_info); /* information of a file in a directory */ + #endif diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index 92691d5fdd9..fecd910683e 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -97,9 +97,11 @@ sync_arr_wake_threads_if_sema_free(void); /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void); /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ /************************************************************************ Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/innobase/include/ut0byte.h b/innobase/include/ut0byte.h index fed6a23d144..a62c2e2e318 100644 --- a/innobase/include/ut0byte.h +++ b/innobase/include/ut0byte.h @@ -229,25 +229,6 @@ ut_bit_set_nth( ulint a, /* in: ulint */ ulint n, /* in: nth bit requested */ ibool val); /* in: value for the bit to set */ -/**************************************************************** -Copies a string to a memory location, setting characters to lower case. */ - -void -ut_cpy_in_lower_case( -/*=================*/ - char* dest, /* in: destination */ - const char* source, /* in: source */ - ulint len); /* in: string length */ -/**************************************************************** -Compares two strings when converted to lower case. */ - -int -ut_cmp_in_lower_case( -/*=================*/ - /* out: -1, 0, 1 if str1 < str2, str1 == str2, - str1 > str2, respectively */ - const char* str1, /* in: string1 */ - const char* str2); /* in: string2 */ #ifndef UNIV_NONINL #include "ut0byte.ic" diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 1040283f85e..3276aaddca2 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -2010,6 +2010,11 @@ try_again: return(TRUE); } + + fprintf(stderr, +"InnoDB: Error: tried to read %lu bytes at offset %lu %lu.\n" +"InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high, + (ulong)offset, (long)ret); #endif #ifdef __WIN__ error_handling: @@ -2354,6 +2359,83 @@ os_file_status( #endif } +/*********************************************************************** +This function returns information about the specified file */ + +ibool +os_file_get_status( +/*===========*/ + /* out: TRUE if stat information found */ + const char* path, /* in: pathname of the file */ + os_file_stat_t* stat_info) /* information of a file in a directory */ +{ +#ifdef __WIN__ + int ret; + struct _stat statinfo; + + ret = _stat(path, &statinfo); + if (ret && (errno == ENOENT || errno == ENOTDIR)) { + /* file does not exist */ + + return(FALSE); + } else if (ret) { + /* file exists, but stat call failed */ + + os_file_handle_error_no_exit(0, path, "stat"); + + return(FALSE); + } + if (_S_IFDIR & statinfo.st_mode) { + stat_info->type = OS_FILE_TYPE_DIR; + } else if (_S_IFREG & statinfo.st_mode) { + stat_info->type = OS_FILE_TYPE_FILE; + } else { + stat_info_>type = OS_FILE_TYPE_UNKNOWN; + } + + stat_info->ctime = statinfo.st_ctime; + stat_info->atime = statinfo.st_atime; + stat_info->mtime = statinfo.st_mtime; + stat_info->size = statinfo.st_size; + + return(TRUE); +#else + int ret; + struct stat statinfo; + + ret = stat(path, &statinfo); + + if (ret && (errno == ENOENT || errno == ENOTDIR)) { + /* file does not exist */ + + return(FALSE); + } else if (ret) { + /* file exists, but stat call failed */ + + os_file_handle_error_no_exit(0, path, "stat"); + + return(FALSE); + } + + if (S_ISDIR(statinfo.st_mode)) { + stat_info->type = OS_FILE_TYPE_DIR; + } else if (S_ISLNK(statinfo.st_mode)) { + stat_info->type = OS_FILE_TYPE_LINK; + } else if (S_ISREG(statinfo.st_mode)) { + stat_info->type = OS_FILE_TYPE_FILE; + } else { + stat_info->type = OS_FILE_TYPE_UNKNOWN; + } + + stat_info->ctime = statinfo.st_ctime; + stat_info->atime = statinfo.st_atime; + stat_info->mtime = statinfo.st_mtime; + stat_info->size = statinfo.st_size; + + return(TRUE); +#endif +} + /* path name separator character */ #ifdef __WIN__ # define OS_FILE_PATH_SEPARATOR '\\' diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 7b0beb9d183..c9c784403c8 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -50,6 +50,15 @@ innobase_invalidate_query_cache( ulint full_name_len); /* in: full name length where also the null chars count */ +/********************************************************************** +This function returns true if SQL-query in the current thread +is either REPLACE or LOAD DATA INFILE REPLACE. +NOTE that /mysql/innobase/row/row0ins.c must contain the +prototype for this function ! */ + +ibool +innobase_query_is_replace(void); +/*===========================*/ /************************************************************************* Creates an insert node struct. */ @@ -1482,9 +1491,9 @@ row_ins_scan_sec_index_for_duplicate( ulint err = DB_SUCCESS; ibool moved; mtr_t mtr; - trx_t *trx; - ibool success; - + trx_t* trx; + const char* ptr; + n_unique = dict_index_get_n_unique(index); /* If the secondary index is unique, but one of the fields in the @@ -1523,9 +1532,8 @@ row_ins_scan_sec_index_for_duplicate( trx = thr_get_trx(thr); ut_ad(trx); - dict_accept(*trx->mysql_query_str, "REPLACE", &success); - if (success) { + if (innobase_query_is_replace()) { /* The manual defines the REPLACE semantics that it is either an INSERT or DELETE(s) for duplicate key @@ -1605,7 +1613,7 @@ row_ins_duplicate_error_in_clust( page_t* page; ulint n_unique; trx_t* trx = thr_get_trx(thr); - ibool success; + const char* ptr; UT_NOT_USED(mtr); @@ -1639,10 +1647,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - dict_accept(*trx->mysql_query_str, "REPLACE", - &success); - - if (success) { + if (innobase_query_is_replace()) { /* The manual defines the REPLACE semantics that it is either an INSERT or DELETE(s) @@ -1683,15 +1688,9 @@ row_ins_duplicate_error_in_clust( /* The manual defines the REPLACE semantics that it is either an INSERT or DELETE(s) for duplicate key + INSERT. Therefore, we should take X-lock for - duplicates. - */ - - /* Is the first word in MySQL query REPLACE ? */ - - dict_accept(*trx->mysql_query_str, "REPLACE", - &success); + duplicates. */ - if (success) { + if (innobase_query_is_replace()) { err = row_ins_set_exclusive_rec_lock( LOCK_REC_NOT_GAP, diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 3ff94c8f238..740241fa210 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2794,7 +2794,7 @@ row_search_for_mysql( rec_t* index_rec; rec_t* clust_rec; rec_t* old_vers; - ulint err; + ulint err = DB_SUCCESS; ibool moved; ibool cons_read_requires_clust_rec; ibool was_lock_wait; @@ -3203,26 +3203,20 @@ rec_loop: if (prebuilt->select_lock_type != LOCK_NONE && set_also_gap_locks) { - /* Try to place a lock on the index record */ + /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e. next-key locking is - not used. - */ - if ( srv_locks_unsafe_for_binlog ) - { - err = sel_set_rec_lock(rec, index, - prebuilt->select_lock_type, - LOCK_REC_NOT_GAP, thr); - } - else + /* If innodb_locks_unsafe_for_binlog option is used, + we do not lock gaps. Supremum record is really + a gap and therefore we do not set locks there. */ + + if ( srv_locks_unsafe_for_binlog == FALSE ) { - err = sel_set_rec_lock(rec, index, + err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_ORDINARY, thr); } - - if (err != DB_SUCCESS) { + + if (err != DB_SUCCESS) { goto lock_wait_or_error; } diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index d913d77fdfc..b8d03cfab5f 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -951,7 +951,13 @@ retry: trx->op_info = "sleeping before joining InnoDB queue"; - os_thread_sleep(50000); + /* Peter Zaitsev suggested that we take the sleep away + altogether. But the sleep may be good in pathological + situations of lots of thread switches. Simply put some + threads aside for a while to reduce the number of thread + switches. */ + + os_thread_sleep(10000); trx->op_info = ""; @@ -1814,7 +1820,8 @@ srv_error_monitor_thread( /* in: a dummy parameter required by os_thread_create */ { - ulint cnt = 0; + /* number of successive fatal timeouts observed */ + ulint fatal_cnt = 0; dulint old_lsn; dulint new_lsn; @@ -1827,8 +1834,6 @@ srv_error_monitor_thread( loop: srv_error_monitor_active = TRUE; - cnt++; - /* Try to track a strange bug reported by Harald Fuchs and others, where the lsn seems to decrease at times */ @@ -1855,7 +1860,20 @@ loop: srv_refresh_innodb_monitor_stats(); } - sync_array_print_long_waits(); + if (sync_array_print_long_waits()) { + fatal_cnt++; + if (fatal_cnt > 5) { + + fprintf(stderr, +"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" +"InnoDB: We intentionally crash the server, because it appears to be hung.\n", + srv_fatal_semaphore_wait_threshold); + + ut_error; + } + } else { + fatal_cnt = 0; + } /* Flush stderr so that a database user gets the output to possible MySQL error file */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 8e48034e09c..9709f5235de 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -95,6 +95,19 @@ static char* srv_monitor_file_name; #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 + +/* Avoid warnings when using purify */ + +#ifdef HAVE_purify +static int inno_bcmp(register const char *s1, register const char *s2, + register uint len) +{ + while (len-- != 0 && *s1++ == *s2++) ; + return len+1; +} +#define memcmp(A,B,C) inno_bcmp((A),(B),(C)) +#endif + /************************************************************************* Reads the data files and their sizes from a character string given in the .cnf file. */ diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index e5285cb7ebf..198ef49ca9f 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -894,15 +894,18 @@ sync_arr_wake_threads_if_sema_free(void) /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void) /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ { sync_cell_t* cell; ibool old_val; ibool noticed = FALSE; ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; + ibool fatal = FALSE; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { @@ -919,13 +922,7 @@ sync_array_print_long_waits(void) if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { - - fprintf(stderr, -"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" -"InnoDB: We intentionally crash the server, because it appears to be hung.\n", - fatal_timeout); - - ut_error; + fatal = TRUE; } } @@ -953,6 +950,8 @@ sync_array_print_long_waits(void) fprintf(stderr, "InnoDB: ###### Diagnostic info printed to the standard error stream\n"); } + + return(fatal); } /************************************************************************** diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index ba93c6de2bd..fe429d1cc62 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -1258,7 +1258,7 @@ trx_undo_prev_version_build( ibool dummy_extern; byte* buf; ulint err; - ulint i; + #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ @@ -1363,7 +1363,18 @@ trx_undo_prev_version_build( } if (row_upd_changes_field_size_or_external(rec, index, update)) { - + ulint* ext_vect; + ulint n_ext_vect; + + /* We have to set the appropriate extern storage bits in the + old version of the record: the extern bits in rec for those + fields that update does NOT update, as well as the the bits for + those fields that update updates to become externally stored + fields. Store the info to ext_vect: */ + + ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec)); + n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, + update); entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals(entry, index, update, heap); @@ -1371,6 +1382,11 @@ trx_undo_prev_version_build( buf = mem_heap_alloc(heap, rec_get_converted_size(entry)); *old_vers = rec_convert_dtuple_to_rec(buf, entry); + + /* Now set the extern bits in the old version of the record */ + rec_set_field_extern_bits(*old_vers, ext_vect, n_ext_vect, + NULL); + mem_free(ext_vect); } else { buf = mem_heap_alloc(heap, rec_get_size(rec)); @@ -1379,15 +1395,5 @@ trx_undo_prev_version_build( row_upd_rec_in_place(*old_vers, update); } - for (i = 0; i < upd_get_n_fields(update); i++) { - - if (upd_get_nth_field(update, i)->extern_storage) { - - rec_set_nth_field_extern_bit(*old_vers, - upd_get_nth_field(update, i)->field_no, - TRUE, NULL); - } - } - return(DB_SUCCESS); } diff --git a/innobase/ut/ut0byte.c b/innobase/ut/ut0byte.c index 8764103dc36..cc83aacc90b 100644 --- a/innobase/ut/ut0byte.c +++ b/innobase/ut/ut0byte.c @@ -29,51 +29,3 @@ ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high) UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high, ut_dulint_cmp); } - -/**************************************************************** -Copies a string to a memory location, setting characters to lower case. */ - -void -ut_cpy_in_lower_case( -/*=================*/ - char* dest, /* in: destination */ - const char* source, /* in: source */ - ulint len) /* in: string length */ -{ - ulint i; - - for (i = 0; i < len; i++) { - dest[i] = tolower(source[i]); - } -} - -/**************************************************************** -Compares two strings when converted to lower case. */ - -int -ut_cmp_in_lower_case( -/*=================*/ - /* out: -1, 0, 1 if str1 < str2, str1 == str2, - str1 > str2, respectively */ - const char* str1, /* in: string1 */ - const char* str2) /* in: string2 */ -{ - for (;;) { - int c1, c2; - if (!*str1) { - return(*str2 ? -1 : 0); - } else if (!*str2) { - return 1; - } - c1 = tolower(*str1++); - c2 = tolower(*str2++); - if (c1 < c2) { - return(-1); - } - if (c1 > c2) { - return(1); - } - } - - return(0); -} diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index ef926e2f93d..6a67697169a 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1516,6 +1516,16 @@ uint STDCALL mysql_thread_safe(void) #endif } + +my_bool STDCALL mysql_embedded(void) +{ +#ifdef EMBEDDED_LIBRARY + return 1; +#else + return 0; +#endif +} + /**************************************************************************** Some support functions ****************************************************************************/ @@ -1534,6 +1544,40 @@ void my_net_local_init(NET *net) } /* + This function is used to create HEX string that you + can use in a SQL statement in of the either ways: + INSERT INTO blob_column VALUES (0xAABBCC); (any MySQL version) + INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher) + + The string in "from" is encoded to a HEX string. + The result is placed in "to" and a terminating null byte is appended. + + The string pointed to by "from" must be "length" bytes long. + You must allocate the "to" buffer to be at least length*2+1 bytes long. + Each character needs two bytes, and you need room for the terminating + null byte. When mysql_hex_string() returns, the contents of "to" will + be a null-terminated string. The return value is the length of the + encoded string, not including the terminating null character. + + The return value does not contain any leading 0x or a leading X' and + trailing '. The caller must supply whichever of those is desired. +*/ + +ulong mysql_hex_string(char *to, const char *from, ulong length) +{ + char *to0= to; + const char *end; + + for (end= from + length; from < end; from++) + { + *to++= _dig_vec_upper[((unsigned char) *from) >> 4]; + *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F]; + } + *to= '\0'; + return (ulong) (to-to0); +} + +/* Add escape characters to a string (blob?) to make it suitable for a insert to should at least have place for length*2+1 chars Returns the length of the to string @@ -3221,12 +3265,12 @@ static void read_binary_time(MYSQL_TIME *tm, uchar **pos) tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0; tm->year= tm->month= 0; - tm->time_type= MYSQL_TIMESTAMP_TIME; *pos+= length; } else set_zero_time(tm); + tm->time_type= MYSQL_TIMESTAMP_TIME; } static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) @@ -3251,12 +3295,12 @@ static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) else tm->hour= tm->minute= tm->second= 0; tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0; - tm->time_type= MYSQL_TIMESTAMP_DATETIME; *pos+= length; } else set_zero_time(tm); + tm->time_type= MYSQL_TIMESTAMP_DATETIME; } static void read_binary_date(MYSQL_TIME *tm, uchar **pos) @@ -3273,12 +3317,12 @@ static void read_binary_date(MYSQL_TIME *tm, uchar **pos) tm->hour= tm->minute= tm->second= 0; tm->second_part= 0; tm->neg= 0; - tm->time_type= MYSQL_TIMESTAMP_DATE; *pos+= length; } else set_zero_time(tm); + tm->time_type= MYSQL_TIMESTAMP_DATE; } @@ -3556,28 +3600,8 @@ static void fetch_datetime_with_conversion(MYSQL_BIND *param, Convert time value to string and delegate the rest to fetch_string_with_conversion: */ - char buff[25]; - uint length; - - switch (time->time_type) { - case MYSQL_TIMESTAMP_DATE: - length= my_sprintf(buff,(buff, "%04d-%02d-%02d", - time->year, time->month, time->day)); - break; - case MYSQL_TIMESTAMP_DATETIME: - length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", - time->year, time->month, time->day, - time->hour, time->minute, time->second)); - break; - case MYSQL_TIMESTAMP_TIME: - length= my_sprintf(buff, (buff, "%02d:%02d:%02d", - time->hour, time->minute, time->second)); - break; - default: - length= 0; - buff[0]='\0'; - break; - } + char buff[MAX_DATE_STRING_REP_LENGTH]; + uint length= my_TIME_to_str(time, buff); /* Resort to string conversion */ fetch_string_with_conversion(param, (char *)buff, length); break; diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 38ac9505e4b..bc91e90a41c 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -144,3 +144,4 @@ EXPORTS mysql_rpl_probe mysql_rpl_query_type mysql_slave_query + mysql_embedded diff --git a/libmysql/manager.c b/libmysql/manager.c index f030eb17889..631bfa26cb2 100644 --- a/libmysql/manager.c +++ b/libmysql/manager.c @@ -237,7 +237,7 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, char* res_buf, char* res_buf_end=res_buf+res_buf_size; char* net_buf=(char*) con->net.read_pos, *net_buf_end; int res_buf_shift=RES_BUF_SHIFT; - uint num_bytes; + ulong num_bytes; if (res_buf_size<RES_BUF_SHIFT) { diff --git a/myisam/myisam_ftdump.c b/myisam/myisam_ftdump.c index 8219c19848a..54b2cc77965 100644 --- a/myisam/myisam_ftdump.c +++ b/myisam/myisam_ftdump.c @@ -68,7 +68,7 @@ int main(int argc,char *argv[]) struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ MY_INIT(argv[0]); - if (error=handle_options(&argc, &argv, my_long_options, get_one_option)) + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(error); if (count || dump) verbose=0; diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 9a2fde8fb89..648e29e1e9e 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -1695,7 +1695,7 @@ err: static my_bool not_killed= 0; -volatile my_bool *killed_ptr(MI_CHECK *param) +volatile my_bool *killed_ptr(MI_CHECK *param __attribute__((unused))) { return ¬_killed; /* always NULL */ } diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 0bbf2721cb3..b4b4169965d 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -111,6 +111,8 @@ typedef struct st_isam_mrg { uint ref_length; uint max_blob_length; my_off_t records; + /* true if at least one source file has at least one disabled index */ + my_bool src_file_has_indexes_disabled; } PACK_MRG_INFO; @@ -413,10 +415,15 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) mrg->current=0; mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE)); mrg->free_file=1; + mrg->src_file_has_indexes_disabled= 0; for (i=0; i < count ; i++) { if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY))) goto error; + + mrg->src_file_has_indexes_disabled|= ((mrg->file[i]->s->state.key_map != + (((ulonglong) 1) << + mrg->file[i]->s->base. keys) - 1)); } /* Check that files are identical */ for (j=0 ; j < count-1 ; j++) @@ -2043,12 +2050,21 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.dellink= HA_OFFSET_ERROR; share->state.split=(ha_rows) mrg->records; share->state.version=(ulong) time((time_t*) 0); - share->state.key_map=0; + if (share->state.key_map != (1ULL << share->base.keys) - 1) + { + /* + Some indexes are disabled, cannot use current key_file_length value + as an estimate of upper bound of index file size. Use packed data file + size instead. + */ + share->state.state.key_file_length= new_length; + } /* - Don't save key_file_length here, keep key_file_length of original file - so "myisamchk -rq" can use this value (this is necessary because index - size cannot be easily calculated for fulltext keys) + If there are no disabled indexes, keep key_file_length value from + original file so "myisamchk -rq" can use this value (this is necessary + because index size cannot be easily calculated for fulltext keys) */ + share->state.key_map=0; for (key=0 ; key < share->base.keys ; key++) share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) @@ -2057,8 +2073,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->changed=1; /* Force write of header */ share->state.open_count=0; share->global_changed=0; - VOID(my_chsize(share->kfile, share->state.state.key_file_length, 0, - MYF(0))); + VOID(my_chsize(share->kfile, share->base.keystart, 0, MYF(0))); if (share->base.keys) isamchk_neaded=1; DBUG_RETURN(mi_state_info_write(share->kfile,&share->state,1+2)); @@ -2081,7 +2096,12 @@ static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length, state.state.del=0; state.state.empty=0; state.state.records=state.split=(ha_rows) mrg->records; - state.state.key_file_length=isam_file->s->base.keystart; + /* See comment above in save_state about key_file_length handling. */ + if (mrg->src_file_has_indexes_disabled) + { + isam_file->s->state.state.key_file_length= + max(isam_file->s->state.state.key_file_length, new_length); + } state.dellink= HA_OFFSET_ERROR; state.version=(ulong) time((time_t*) 0); state.key_map=0; diff --git a/myisam/rt_test.c b/myisam/rt_test.c index 5e883e223b3..4f04aa11fce 100644 --- a/myisam/rt_test.c +++ b/myisam/rt_test.c @@ -425,6 +425,7 @@ static void create_record1(char *record,uint rownr) } } +#ifdef NOT_USED static void create_record0(char *record,uint rownr) { @@ -447,6 +448,8 @@ static void create_record0(char *record,uint rownr) } } +#endif + static void create_record(char *record,uint rownr) { int i; diff --git a/mysql-test/ndb/ndb_range_bounds.pl b/mysql-test/ndb/ndb_range_bounds.pl new file mode 100644 index 00000000000..75b7f8a33e1 --- /dev/null +++ b/mysql-test/ndb/ndb_range_bounds.pl @@ -0,0 +1,138 @@ +# +# test range scan bounds +# output to mysql-test/t/ndb_range_bounds.test +# +# give option --all to generate all cases +# + +use strict; +use integer; +use Getopt::Long; + +my $opt_all = 0; +my $opt_cnt = 5; +GetOptions("all" => \$opt_all, "cnt=i" => \$opt_cnt) + or die "options are: --all --cnt=N"; + +my $table = 't'; + +print <<EOF; +--source include/have_ndb.inc + +--disable_warnings +drop table if exists $table; +--enable_warnings + +# test range scan bounds +# generated by mysql-test/ndb/ndb_range_bounds.pl +# all selects must return 0 + +EOF + +sub cut ($$@) { + my($op, $key, @v) = @_; + $op = '==' if $op eq '='; + my(@w); + eval "\@w = grep(\$_ $op $key, \@v)"; + $@ and die $@; + return @w; +} + +sub mkdummy (\@) { + my ($val) = @_; + return { + 'dummy' => 1, + 'exp' => '9 = 9', + 'cnt' => scalar @$val, + }; +} + +sub mkone ($$$\@) { + my($col, $op, $key, $val) = @_; + my $cnt = scalar cut($op, $key, @$val); + return { + 'exp' => "$col $op $key", + 'cnt' => $cnt, + }; +} + +sub mktwo ($$$$$\@) { + my($col, $op1, $key1, $op2, $key2, $val) = @_; + my $cnt = scalar cut($op2, $key2, cut($op1, $key1, @$val)); + return { + 'exp' => "$col $op1 $key1 and $col $op2 $key2", + 'cnt' => $cnt, + }; +} + +sub mkall ($$$\@) { + my($col, $key1, $key2, $val) = @_; + my @a = (); + my $p = mkdummy(@$val); + push(@a, $p) if $opt_all; + my @ops = qw(< <= = >= >); + for my $op (@ops) { + my $p = mkone($col, $op, $key1, @$val); + push(@a, $p) if $opt_all || $p->{cnt} != 0; + } + my @ops1 = $opt_all ? @ops : qw(= >= >); + my @ops2 = $opt_all ? @ops : qw(<= <); + for my $op1 (@ops1) { + for my $op2 (@ops2) { + my $p = mktwo($col, $op1, $key1, $op2, $key2, @$val); + push(@a, $p) if $opt_all || $p->{cnt} != 0; + } + } + return \@a; +} + +for my $nn ("bcd", "") { + my %nn; + for my $x (qw(b c d)) { + $nn{$x} = $nn =~ /$x/ ? "not null" : "null"; + } + print <<EOF; +create table $table ( + a int primary key, + b int $nn{b}, + c int $nn{c}, + d int $nn{d}, + index (b, c, d) +) engine=ndb; +EOF + my @val = (0..($opt_cnt-1)); + my $v0 = 0; + for my $v1 (@val) { + for my $v2 (@val) { + for my $v3 (@val) { + print "insert into $table values($v0, $v1, $v2, $v3);\n"; + $v0++; + } + } + } + my $key1 = 1; + my $key2 = 3; + my $a1 = mkall('b', $key1, $key2, @val); + my $a2 = mkall('c', $key1, $key2, @val); + my $a3 = mkall('d', $key1, $key2, @val); + for my $p1 (@$a1) { + my $cnt1 = $p1->{cnt} * @val * @val; + print "select count(*) - $cnt1 from $table"; + print " where $p1->{exp};\n"; + for my $p2 (@$a2) { + my $cnt2 = $p1->{cnt} * $p2->{cnt} * @val; + print "select count(*) - $cnt2 from $table"; + print " where $p1->{exp} and $p2->{exp};\n"; + for my $p3 (@$a3) { + my $cnt3 = $p1->{cnt} * $p2->{cnt} * $p3->{cnt}; + print "select count(*) - $cnt3 from $table"; + print " where $p1->{exp} and $p2->{exp} and $p3->{exp};\n"; + } + } + } + print <<EOF; +drop table $table; +EOF +} + +# vim: set sw=2: diff --git a/mysql-test/ndb/ndbcluster.sh b/mysql-test/ndb/ndbcluster.sh index 7485e42923e..294d32ac4be 100644 --- a/mysql-test/ndb/ndbcluster.sh +++ b/mysql-test/ndb/ndbcluster.sh @@ -205,7 +205,7 @@ if [ -f "$fs_ndb/$pidfile" ] ; then fi done kill_pids=$new_kill_pid - if [ "$kill_pids" == "" ] ; then + if [ -z "$kill_pids" ] ; then break fi sleep 1 diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result index 1e3e28784a5..26a45dd28e8 100644 --- a/mysql-test/r/ctype_sjis.result +++ b/mysql-test/r/ctype_sjis.result @@ -41,3 +41,9 @@ C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF select hex(CONVERT(@utf84 USING sjis)); hex(CONVERT(@utf84 USING sjis)) D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF +create table t1 (a char(10) character set sjis); +insert into t1 values (0x878A); +select hex(a) from t1; +hex(a) +878A +drop table t1; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 7e4a03e96cc..90681795513 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -1,5 +1,35 @@ DROP TABLE IF EXISTS t1; set names utf8; +set collation_connection=utf8_unicode_ci; +select 'a' = 'a', 'a' = 'a ', 'a ' = 'a'; +'a' = 'a' 'a' = 'a ' 'a ' = 'a' +1 1 1 +select 'a\t' = 'a' , 'a\t' < 'a' , 'a\t' > 'a'; +'a\t' = 'a' 'a\t' < 'a' 'a\t' > 'a' +0 1 0 +select 'a\t' = 'a ', 'a\t' < 'a ', 'a\t' > 'a '; +'a\t' = 'a ' 'a\t' < 'a ' 'a\t' > 'a ' +0 1 0 +select 'a' = 'a\t', 'a' < 'a\t', 'a' > 'a\t'; +'a' = 'a\t' 'a' < 'a\t' 'a' > 'a\t' +0 0 1 +select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; +'a ' = 'a\t' 'a ' < 'a\t' 'a ' > 'a\t' +0 0 1 +select 'a a' > 'a', 'a \t' < 'a'; +'a a' > 'a' 'a \t' < 'a' +1 1 +CREATE TABLE t ( +c char(20) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +INSERT INTO t VALUES ('a'),('ab'),('aba'); +ALTER TABLE t ADD INDEX (c); +SELECT c FROM t WHERE c LIKE 'a%'; +c +a +ab +aba +DROP TABLE t; create table t1 (c1 char(10) character set utf8 collate utf8_bin); insert into t1 values ('A'),('a'); insert into t1 values ('B'),('b'); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 2e8bbc8fa92..e65eb96cb68 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -63,6 +63,15 @@ select 'A' like 'a' collate utf8_bin; select _utf8 0xD0B0D0B1D0B2 like concat(_utf8'%',_utf8 0xD0B1,_utf8 '%'); _utf8 0xD0B0D0B1D0B2 like concat(_utf8'%',_utf8 0xD0B1,_utf8 '%') 1 +select convert(_latin1'Günter André' using utf8) like CONVERT(_latin1'GÜNTER%' USING utf8); +convert(_latin1'Günter André' using utf8) like CONVERT(_latin1'GÜNTER%' USING utf8) +1 +select CONVERT(_koi8r'×ÁÓÑ' USING utf8) LIKE CONVERT(_koi8r'÷áóñ' USING utf8); +CONVERT(_koi8r'×ÁÓÑ' USING utf8) LIKE CONVERT(_koi8r'÷áóñ' USING utf8) +1 +select CONVERT(_koi8r'÷áóñ' USING utf8) LIKE CONVERT(_koi8r'×ÁÓÑ' USING utf8); +CONVERT(_koi8r'÷áóñ' USING utf8) LIKE CONVERT(_koi8r'×ÁÓÑ' USING utf8) +1 SELECT 'a' = 'a '; 'a' = 'a ' 1 diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index c3fe1de15db..8a28312b348 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -174,3 +174,12 @@ SELECT GREATEST(d,d) FROM t1 WHERE k=2; GREATEST(d,d) NULL DROP TABLE t1; +select 1197.90 mod 50; +1197.90 mod 50 +47.90 +select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; +5.1 mod 3 5.1 mod -3 -5.1 mod 3 -5.1 mod -3 +2.1 2.1 -2.1 -2.1 +select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; +5 mod 3 5 mod -3 -5 mod 3 -5 mod -3 +2 2 -2 -2 diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 31e506d2679..a31fa2ac3dc 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -1,6 +1,9 @@ SET NAMES binary; +drop database if exists mysqltest; delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; flush privileges; grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option; select current_user(); @@ -25,3 +28,27 @@ ERROR 42000: There is no such grant defined for user 'mysqltest_3' on host 'loca delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; flush privileges; +create database mysqltest; +grant INSERT, SELECT on mysqltest.* to mysqltest_1@localhost; +flush privileges; +use mysqltest; +create table t1 (id int primary key, data varchar(255)); +show grants for current_user(); +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +use mysqltest; +insert into t1 values (1, 'I can''t change it!'); +update t1 set data='I can change it!' where id = 1; +ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest' +insert into t1 values (1, 'XXX') on duplicate key update data= 'I can change it!'; +ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest' +select * from t1; +id data +1 I can't change it! +drop table t1; +drop database mysqltest; +use test; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +flush privileges; diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/r/innodb-lock.result index cf00adb30ae..407a85ed038 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/r/innodb-lock.result @@ -1,4 +1,8 @@ +select @@innodb_table_locks; +@@innodb_table_locks +1 drop table if exists t1; +set @@innodb_table_locks=1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); set autocommit=0; @@ -20,3 +24,33 @@ id x 0 2 commit; drop table t1; +set @@innodb_table_locks=0; +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; +SELECT * from t1 where id = 0 FOR UPDATE; +id x +0 0 +set autocommit=0; +set @@innodb_table_locks=0; +lock table t1 write; +update t1 set x=10 where id = 2; +SELECT * from t1 where id = 2; +id x +2 2 +UPDATE t1 set x=3 where id = 2; +commit; +SELECT * from t1; +id x +0 0 +1 1 +2 3 +commit; +unlock tables; +commit; +select * from t1; +id x +0 0 +1 1 +2 10 +drop table t1; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result new file mode 100644 index 00000000000..4e30d5bc110 --- /dev/null +++ b/mysql-test/r/mysqltest.result @@ -0,0 +1,23 @@ +select otto from (select 1 as otto) as t1; +otto +1 +select otto from (select 1 as otto) as t1; +otto +1 +select otto from (select 1 as otto) as t1; +otto +1 +select friedrich from (select 1 as otto) as t1; +ERROR 42S22: Unknown column 'friedrich' in 'field list' +select friedrich from (select 1 as otto) as t1; +ERROR 42S22: Unknown column 'friedrich' in 'field list' +select otto from (select 1 as otto) as t1; +otto +1 +select otto from (select 1 as otto) as t1; +otto +1 +select friedrich from (select 1 as otto) as t1; +ERROR 42S22: Unknown column 'friedrich' in 'field list' +select friedrich from (select 1 as otto) as t1; +ERROR 42S22: Unknown column 'friedrich' in 'field list' diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index 9f8dcf3610a..abe1b98b536 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -395,3 +395,22 @@ b attr1 9413 9412 drop table test.t1, t2; drop database mysqltest; +use test; +create table t1 (a int primary key, b char(0)); +insert into t1 values (1,""); +insert into t1 values (2,NULL); +select * from t1 order by a; +a b +1 +2 NULL +select * from t1 order by b; +a b +2 NULL +1 +select * from t1 where b IS NULL; +a b +2 NULL +select * from t1 where b IS NOT NULL; +a b +1 +drop table t1; diff --git a/mysql-test/r/ndb_index_ordered.result b/mysql-test/r/ndb_index_ordered.result index 2a3050e5dea..2dc260ec43d 100644 --- a/mysql-test/r/ndb_index_ordered.result +++ b/mysql-test/r/ndb_index_ordered.result @@ -37,6 +37,24 @@ a b c 1 2 3 2 3 5 3 4 6 +select tt1.* from t1 as tt1, t1 as tt2 use index(b) where tt1.b = tt2.b order by tt1.b; +a b c +1 2 3 +2 3 5 +3 4 6 +4 5 8 +5 6 2 +6 7 2 +select a, b, c from t1 where a!=2 and c=6; +a b c +3 4 6 +select a, b, c from t1 where a!=2 order by a; +a b c +1 2 3 +3 4 6 +4 5 8 +5 6 2 +6 7 2 update t1 set c = 3 where b = 3; select * from t1 order by a; a b c diff --git a/mysql-test/r/ndb_lock.result b/mysql-test/r/ndb_lock.result index 56661913e22..b8c2c58aac4 100644 --- a/mysql-test/r/ndb_lock.result +++ b/mysql-test/r/ndb_lock.result @@ -28,3 +28,38 @@ x y 2 two 3 three commit; +drop table t1; +create table t1 (pk integer not null primary key, u int not null, o int not null, +unique(u), key(o)) engine = ndb; +insert into t1 values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5); +lock tables t1 write; +delete from t1 where pk = 1; +unlock tables; +select * from t1 order by pk; +pk u o +2 2 2 +3 3 3 +4 4 4 +5 5 5 +insert into t1 values (1,1,1); +lock tables t1 write; +delete from t1 where u = 1; +unlock tables; +select * from t1 order by pk; +pk u o +2 2 2 +3 3 3 +4 4 4 +5 5 5 +insert into t1 values (1,1,1); +lock tables t1 write; +delete from t1 where o = 1; +unlock tables; +select * from t1 order by pk; +pk u o +2 2 2 +3 3 3 +4 4 4 +5 5 5 +insert into t1 values (1,1,1); +drop table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 0aba0c4672e..0950a066e64 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -375,3 +375,38 @@ rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as - 9647622201 3845601374 6211931236 drop table t1; deallocate prepare stmt; +create database mysqltest1; +create table t1 (a int); +create table mysqltest1.t1 (a int); +select * from t1, mysqltest1.t1; +a a +prepare stmt from "select * from t1, mysqltest1.t1"; +execute stmt; +a a +execute stmt; +a a +execute stmt; +a a +drop table t1; +drop table mysqltest1.t1; +drop database mysqltest1; +deallocate prepare stmt; +select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; +a a +1.1 1.2 +2.1 2.2 +prepare stmt from +"select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; +execute stmt; +a a +1.1 1.2 +2.1 2.2 +execute stmt; +a a +1.1 1.2 +2.1 2.2 +execute stmt; +a a +1.1 1.2 +2.1 2.2 +deallocate prepare stmt; diff --git a/mysql-test/r/ps_10nestset.result b/mysql-test/r/ps_10nestset.result index 10f0a741b54..68f58a03674 100644 --- a/mysql-test/r/ps_10nestset.result +++ b/mysql-test/r/ps_10nestset.result @@ -1,14 +1,11 @@ -use test; -drop table if exists personnel; -Warnings: -Note 1051 Unknown table 'personnel' -create table personnel ( +drop table if exists t1; +create table t1 ( id INTEGER AUTO_INCREMENT PRIMARY KEY, emp CHAR(10) NOT NULL, salary DECIMAL(6,2) NOT NULL, l INTEGER NOT NULL, r INTEGER NOT NULL); -prepare st_ins from 'insert into personnel set emp = ?, salary = ?, l = ?, r = ?'; +prepare st_ins from 'insert into t1 set emp = ?, salary = ?, l = ?, r = ?'; set @arg_nam= 'Jerry'; set @arg_sal= 1000; set @arg_l= 1; @@ -39,7 +36,7 @@ set @arg_sal= 600; set @arg_l= 9; set @arg_r= 10; execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; -select * from personnel; +select * from t1; id emp salary l r 1 Jerry 1000.00 1 12 2 Bert 900.00 2 3 @@ -47,8 +44,8 @@ id emp salary l r 4 Donna 800.00 5 6 5 Eddie 700.00 7 8 6 Fred 600.00 9 10 -prepare st_raise_base from 'update personnel set salary = salary * ( 1 + ? ) where r - l = 1'; -prepare st_raise_mgr from 'update personnel set salary = salary + ? where r - l > 1'; +prepare st_raise_base from 'update t1 set salary = salary * ( 1 + ? ) where r - l = 1'; +prepare st_raise_mgr from 'update t1 set salary = salary + ? where r - l > 1'; set @arg_percent= .10; set @arg_amount= 100; execute st_raise_base using @arg_percent; @@ -57,7 +54,7 @@ execute st_raise_base using @arg_percent; execute st_raise_mgr using @arg_amount; execute st_raise_base using @arg_percent; execute st_raise_mgr using @arg_amount; -select * from personnel; +select * from t1; id emp salary l r 1 Jerry 1300.00 1 12 2 Bert 1197.90 2 3 @@ -65,4 +62,4 @@ id emp salary l r 4 Donna 1064.80 5 6 5 Eddie 931.70 7 8 6 Fred 798.60 9 10 -drop table personnel; +drop table t1; diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 6dcdb0feab1..ccf2945d488 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -184,7 +184,7 @@ f3 int ); insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); execute stmt2 ; -ERROR 42S22: Unknown column 't5.a' in 'field list' +ERROR 42S22: Unknown column 'test.t5.a' in 'field list' drop table t5 ; prepare stmt1 from ' select * from t1 where a <= 2 ' ; execute stmt1 ; diff --git a/mysql-test/r/rpl_commit_after_flush.result b/mysql-test/r/rpl_commit_after_flush.result new file mode 100644 index 00000000000..d3aba779219 --- /dev/null +++ b/mysql-test/r/rpl_commit_after_flush.result @@ -0,0 +1,13 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +create table t1 (a int) engine=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +unlock tables; +drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index fbd4f8e11dc..7820cd1d6ff 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1033,3 +1033,81 @@ a No aaa,bbb drop table t1,t2,t3,t4; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` char(4) NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +1 +drop table t1; +create table t1 as +(select _latin1'test' collate latin1_bin) union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `_latin1'test' collate latin1_bin` char(4) character set latin1 collate latin1_bin NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST' collate latin1_bin) union +(select _latin1'TeST'); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` char(4) character set latin1 collate latin1_bin NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST' collate latin1_bin); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `test` char(4) character set latin1 collate latin1_bin NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select count(*) from t1; +count(*) +3 +drop table t1; +create table t2 ( +a char character set latin1 collate latin1_swedish_ci, +b char character set latin1 collate latin1_bin); +create table t1 as +(select a from t2) union +(select b from t2); +ERROR HY000: Illegal mix of collations for operation 'UNION' +create table t1 as +(select a collate latin1_german1_ci from t2) union +(select b from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a collate latin1_german1_ci` char(1) character set latin1 collate latin1_german1_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 as +(select a from t2) union +(select b collate latin1_german1_ci from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(1) character set latin1 collate latin1_german1_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +drop table t2; diff --git a/mysql-test/t/ctype_sjis.test b/mysql-test/t/ctype_sjis.test index 1dd363c4910..68f4f7010e0 100644 --- a/mysql-test/t/ctype_sjis.test +++ b/mysql-test/t/ctype_sjis.test @@ -32,3 +32,12 @@ select hex(CONVERT(@utf81 USING sjis)); select hex(CONVERT(@utf82 USING sjis)); select hex(CONVERT(@utf83 USING sjis)); select hex(CONVERT(@utf84 USING sjis)); + +# +# Allow to insert extra CP932 characters +# into a SJIS column +# +create table t1 (a char(10) character set sjis); +insert into t1 values (0x878A); +select hex(a) from t1; +drop table t1; diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index cbb2bd7ba4b..708a31d637e 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -7,8 +7,35 @@ DROP TABLE IF EXISTS t1; # # Test Unicode collations. # - set names utf8; + +# +# Check trailing spaces +# +set collation_connection=utf8_unicode_ci; + +select 'a' = 'a', 'a' = 'a ', 'a ' = 'a'; + +select 'a\t' = 'a' , 'a\t' < 'a' , 'a\t' > 'a'; +select 'a\t' = 'a ', 'a\t' < 'a ', 'a\t' > 'a '; + +select 'a' = 'a\t', 'a' < 'a\t', 'a' > 'a\t'; +select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; + +select 'a a' > 'a', 'a \t' < 'a'; + +# +# Bug #5679 utf8_unicode_ci LIKE--trailing % doesn't equal zero characters +# +CREATE TABLE t ( + c char(20) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +INSERT INTO t VALUES ('a'),('ab'),('aba'); +ALTER TABLE t ADD INDEX (c); +SELECT c FROM t WHERE c LIKE 'a%'; +#should find 3 rows but only found 2 +DROP TABLE t; + create table t1 (c1 char(10) character set utf8 collate utf8_bin); # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index fc6eb88ad68..238cd6daef3 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -33,6 +33,14 @@ select 'A' like 'a'; select 'A' like 'a' collate utf8_bin; select _utf8 0xD0B0D0B1D0B2 like concat(_utf8'%',_utf8 0xD0B1,_utf8 '%'); +# Bug #6040: can't retrieve records with umlaut +# characters in case insensitive manner. +# Case insensitive search LIKE comparison +# was broken for multibyte characters: +select convert(_latin1'Günter André' using utf8) like CONVERT(_latin1'GÜNTER%' USING utf8); +select CONVERT(_koi8r'×ÁÓÑ' USING utf8) LIKE CONVERT(_koi8r'÷áóñ' USING utf8); +select CONVERT(_koi8r'÷áóñ' USING utf8) LIKE CONVERT(_koi8r'×ÁÓÑ' USING utf8); + # # Check the following: # "a" == "a " @@ -568,6 +576,7 @@ DROP TABLE t1; # # Bug #5723: length(<varchar utf8 field>) returns varying results # +--disable_warnings SET NAMES utf8; --disable_warnings CREATE TABLE t1 ( diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index e7bcd81a15e..eb506a58870 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -94,3 +94,16 @@ CREATE TABLE t1 (d varchar(6), k int); INSERT INTO t1 VALUES (NULL, 2); SELECT GREATEST(d,d) FROM t1 WHERE k=2; DROP TABLE t1; + +# +# Bug #6138: mod and doubles +# + +select 1197.90 mod 50; +select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; + +# +# Test for mod and signed integers +# + +select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 3a9afa7453b..f86be0c95b9 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -6,13 +6,21 @@ SET NAMES binary; # +# prepare playground before tests +--disable_warnings +drop database if exists mysqltest; +--enable_warnings +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; + + # # wild_compare fun # -delete from mysql.user where user like 'mysqltest\_%'; -delete from mysql.db where user like 'mysqltest\_%'; -flush privileges; grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option; connect (user1,localhost,mysqltest_1,,); connection user1; @@ -31,3 +39,33 @@ delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; flush privileges; + +# +# Bug #6173: One can circumvent missing UPDATE privilege if he has SELECT +# and INSERT privilege for table with primary key +# +create database mysqltest; +grant INSERT, SELECT on mysqltest.* to mysqltest_1@localhost; +flush privileges; +use mysqltest; +create table t1 (id int primary key, data varchar(255)); + +connect (mrbad, localhost, mysqltest_1,,); +connection mrbad; +show grants for current_user(); +use mysqltest; +insert into t1 values (1, 'I can''t change it!'); +--error 1044 +update t1 set data='I can change it!' where id = 1; +# This should not be allowed since it too require UPDATE privilege. +--error 1044 +insert into t1 values (1, 'XXX') on duplicate key update data= 'I can change it!'; +select * from t1; + +connection default; +drop table t1; +drop database mysqltest; +use test; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +flush privileges; diff --git a/mysql-test/t/innodb-lock-master.opt b/mysql-test/t/innodb-lock-master.opt new file mode 100644 index 00000000000..403fcde87ed --- /dev/null +++ b/mysql-test/t/innodb-lock-master.opt @@ -0,0 +1 @@ +--innodb-table-lock=1 diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 33baec32549..2bbbac82ad5 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -1,5 +1,15 @@ -- source include/have_innodb.inc +# +# Check and select innodb lock type +# + +select @@innodb_table_locks; + +# +# Testing of explicit table locks with enforced table locks +# + connect (con1,localhost,root,,); connect (con2,localhost,root,,); @@ -8,9 +18,11 @@ drop table if exists t1; --enable_warnings # -# Testing of explicit table locks +# Testing of explicit table locks with enforced table locks # +set @@innodb_table_locks=1; + connection con1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); @@ -41,3 +53,46 @@ select * from t1; commit; drop table t1; + +# +# Try with old lock method (where LOCK TABLE is ignored by InnoDB) +# + +set @@innodb_table_locks=0; + +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; +SELECT * from t1 where id = 0 FOR UPDATE; + +connection con2; +set autocommit=0; +set @@innodb_table_locks=0; + +# The following statement should work becase innodb doesn't check table locks +lock table t1 write; + +connection con1; + +# This will be locked by MySQL +--send +update t1 set x=10 where id = 2; +--sleep 2 + +connection con2; + +# Note that we will get a deadlock if we try to select any rows marked +# for update by con1 ! + +SELECT * from t1 where id = 2; +UPDATE t1 set x=3 where id = 2; +commit; +SELECT * from t1; +commit; +unlock tables; + +connection con1; +reap; +commit; +select * from t1; +drop table t1; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test new file mode 100644 index 00000000000..c18dfe1e25c --- /dev/null +++ b/mysql-test/t/mysqltest.test @@ -0,0 +1,78 @@ + +# ============================================================================ +# +# Test of mysqltest itself +# +# ============================================================================ + +# ---------------------------------------------------------------------------- +# Positive case(statement) +# ---------------------------------------------------------------------------- + +select otto from (select 1 as otto) as t1; +# expectation = response +!$0 select otto from (select 1 as otto) as t1; +--error 0 +select otto from (select 1 as otto) as t1; + +# expectation <> response +-- // !$1054 select otto from (select 1 as otto) as t1; +-- // --error 1054 +-- // select otto from (select 1 as otto) as t1; + + +# ---------------------------------------------------------------------------- +# Negative case(statement): +# The dervied table t1 does not contain a column named 'friedrich' . +# --> ERROR 42S22: Unknown column 'friedrich' in 'field list and +# --> 1054: Unknown column 'friedrich' in 'field list' +# ---------------------------------------------------------------------------- + +# expectation <> response +#!$0 select friedrich from (select 1 as otto) as t1; +#--error 0 +#select friedrich from (select 1 as otto) as t1; + +# expectation = response +!$1054 select friedrich from (select 1 as otto) as t1; +--error 1054 +select friedrich from (select 1 as otto) as t1; + +# The following unmasked unsuccessful statement must give +# 1. mysqltest gives a 'failed' +# 2. does not produce a r/<test case>.reject file !!! +# PLEASE uncomment it and check it's effect +#select friedrich from (select 1 as otto) as t1; + + +# ---------------------------------------------------------------------------- +# Tests for the new feature - SQLSTATE error code matching +# Positive case(statement) +# ---------------------------------------------------------------------------- + +# expectation = response +!S00000 select otto from (select 1 as otto) as t1; + +--error S00000 +select otto from (select 1 as otto) as t1; + +# expectation <> response +#!S42S22 select otto from (select 1 as otto) as t1; +#--error S42S22 +#select otto from (select 1 as otto) as t1; + + +# ---------------------------------------------------------------------------- +# Negative case(statement) +# ---------------------------------------------------------------------------- + +# expectation = response +!S42S22 select friedrich from (select 1 as otto) as t1; +--error S42S22 +select friedrich from (select 1 as otto) as t1; + +# expectation !=response +#!S00000 select friedrich from (select 1 as otto) as t1; +#--error S00000 +#select friedrich from (select 1 as otto) as t1; + diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test index 5f32a8016bf..e79815bbeb1 100644 --- a/mysql-test/t/ndb_basic.test +++ b/mysql-test/t/ndb_basic.test @@ -358,3 +358,16 @@ select b,test.t1.attr1 from test.t1, t2 where test.t1.pk1 < a; drop table test.t1, t2; drop database mysqltest; +# +# test support of char(0) +# + +use test; +create table t1 (a int primary key, b char(0)); +insert into t1 values (1,""); +insert into t1 values (2,NULL); +select * from t1 order by a; +select * from t1 order by b; +select * from t1 where b IS NULL; +select * from t1 where b IS NOT NULL; +drop table t1; diff --git a/mysql-test/t/ndb_index_ordered.test b/mysql-test/t/ndb_index_ordered.test index 2a94475df13..64291c8ab97 100644 --- a/mysql-test/t/ndb_index_ordered.test +++ b/mysql-test/t/ndb_index_ordered.test @@ -23,6 +23,11 @@ select * from t1 where b > 4 order by b; select * from t1 where b < 4 order by b; select * from t1 where b <= 4 order by b; +# Test of reset_bounds +select tt1.* from t1 as tt1, t1 as tt2 use index(b) where tt1.b = tt2.b order by tt1.b; +select a, b, c from t1 where a!=2 and c=6; +select a, b, c from t1 where a!=2 order by a; + # # Here we should add some "explain select" to verify that the ordered index is # used for these queries. diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index c0389dced44..39a8655b972 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -39,3 +39,32 @@ commit; connection con2; select * from t1 order by x; commit; + +drop table t1; + +### +# Bug#6020 +create table t1 (pk integer not null primary key, u int not null, o int not null, + unique(u), key(o)) engine = ndb; +insert into t1 values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5); + +lock tables t1 write; +delete from t1 where pk = 1; +unlock tables; +select * from t1 order by pk; +insert into t1 values (1,1,1); + +lock tables t1 write; +delete from t1 where u = 1; +unlock tables; +select * from t1 order by pk; +insert into t1 values (1,1,1); + +lock tables t1 write; +delete from t1 where o = 1; +unlock tables; +select * from t1 order by pk; +insert into t1 values (1,1,1); + +drop table t1; + diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 7cbcd50245f..04ab8aa62a8 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -390,3 +390,28 @@ set @var=3; execute stmt using @var; drop table t1; deallocate prepare stmt; + +# +# A test case for Bug#6050 "EXECUTE stmt reports ambiguous fieldnames with +# identical tables from different schemata" +# Check that field name resolving in prepared statements works OK. +# +create database mysqltest1; +create table t1 (a int); +create table mysqltest1.t1 (a int); +select * from t1, mysqltest1.t1; +prepare stmt from "select * from t1, mysqltest1.t1"; +execute stmt; +execute stmt; +execute stmt; +drop table t1; +drop table mysqltest1.t1; +drop database mysqltest1; +deallocate prepare stmt; +select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; +prepare stmt from +"select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; +execute stmt; +execute stmt; +execute stmt; +deallocate prepare stmt; diff --git a/mysql-test/t/ps_10nestset.test b/mysql-test/t/ps_10nestset.test index 2c6009af9de..d2adaca689e 100644 --- a/mysql-test/t/ps_10nestset.test +++ b/mysql-test/t/ps_10nestset.test @@ -8,28 +8,29 @@ # Source: http://kris.koehntopp.de/artikel/sql-self-references (dated 1999) # Source: http://dbmsmag.com/9603d06.html (dated 1996) -use test; - -drop table if exists personnel; +--disable_warnings +drop table if exists t1; +--enable_warnings # "Nested Set": This table represents an employee list with a hierarchy tree. # The tree is not modeled by "parent" links but rather by showing the "left" # and "right" border of any person's "region". By convention, "l" < "r". # As it is a tree, these "regions" of two persons A and B are either disjoint, -# or A's region is completely contained in B's (B is A's boss), or vice versa. -# See the references for more info. +# or A's region is completely contained in B's (B.l < A.l < A.r < B.r: +# B is A's boss), or vice versa. +# Any other overlaps violate the model. See the references for more info. -create table personnel ( +create table t1 ( id INTEGER AUTO_INCREMENT PRIMARY KEY, emp CHAR(10) NOT NULL, salary DECIMAL(6,2) NOT NULL, l INTEGER NOT NULL, r INTEGER NOT NULL); -prepare st_ins from 'insert into personnel set emp = ?, salary = ?, l = ?, r = ?'; +prepare st_ins from 'insert into t1 set emp = ?, salary = ?, l = ?, r = ?'; # Initial employee list: -# Jerry ( Bert ( ) Chuck ( Donna ( ) Eddie ( ) Fred ( ) ) ) +# Jerry ( Bert () Chuck ( Donna () Eddie () Fred () ) ) set @arg_nam= 'Jerry'; set @arg_sal= 1000; set @arg_l= 1; set @arg_r= 12; execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; set @arg_nam= 'Bert'; set @arg_sal= 900; set @arg_l= 2; set @arg_r= 3; @@ -43,11 +44,11 @@ execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; set @arg_nam= 'Fred'; set @arg_sal= 600; set @arg_l= 9; set @arg_r= 10; execute st_ins using @arg_nam, @arg_sal, @arg_l, @arg_r ; -select * from personnel; +select * from t1; # Three successive raises, each one is 100 units for managers, 10 percent for others. -prepare st_raise_base from 'update personnel set salary = salary * ( 1 + ? ) where r - l = 1'; -prepare st_raise_mgr from 'update personnel set salary = salary + ? where r - l > 1'; +prepare st_raise_base from 'update t1 set salary = salary * ( 1 + ? ) where r - l = 1'; +prepare st_raise_mgr from 'update t1 set salary = salary + ? where r - l > 1'; let $1= 3; set @arg_percent= .10; set @arg_amount= 100; @@ -58,6 +59,14 @@ while ($1) dec $1; } -select * from personnel; +select * from t1; + +# Waiting for the resolution of bug#6138 +# # Now, increase salary to a multiple of 50 +# prepare st_round from 'update t1 set salary = salary + ? - ( salary MOD ? )'; +# set @arg_round= 50; +# execute st_round using @arg_round, @arg_round; +# +# select * from t1; -drop table personnel; +drop table t1; diff --git a/mysql-test/t/ps_11bugs.test b/mysql-test/t/ps_11bugs.test index d0aeaf265bb..5945b140645 100644 --- a/mysql-test/t/ps_11bugs.test +++ b/mysql-test/t/ps_11bugs.test @@ -97,7 +97,7 @@ drop table t1; # end of bug#1644 -# bug#1677: Prepared statement two-table join returns no rows when one is expected +# bug#1676: Prepared statement two-table join returns no rows when one is expected create table t1( cola varchar(50) not null, diff --git a/mysql-test/t/rpl_commit_after_flush.test b/mysql-test/t/rpl_commit_after_flush.test new file mode 100644 index 00000000000..62c89b3aae6 --- /dev/null +++ b/mysql-test/t/rpl_commit_after_flush.test @@ -0,0 +1,17 @@ +source include/master-slave.inc; +source include/have_innodb.inc; +create table t1 (a int) engine=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +save_master_pos; +connection slave; +sync_with_master; +# cleanup +connection master; +unlock tables; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index c5e72e85835..6e16a2b02aa 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -595,3 +595,58 @@ select a as a from t3 union select "1"; select a as a from t4 union select a from t3; select a as a from t1 union select a from t4; drop table t1,t2,t3,t4; + +# +# Bug #6139 UNION doesn't understand collate in the column of second select +# +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test' collate latin1_bin) union +(select _latin1'TEST') union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test') union +(select _latin1'TEST' collate latin1_bin) union +(select _latin1'TeST'); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t1 as +(select _latin1'test') union +(select _latin1'TEST') union +(select _latin1'TeST' collate latin1_bin); +show create table t1; +select count(*) from t1; +drop table t1; + +create table t2 ( +a char character set latin1 collate latin1_swedish_ci, +b char character set latin1 collate latin1_bin); +--error 1271 +create table t1 as +(select a from t2) union +(select b from t2); +create table t1 as +(select a collate latin1_german1_ci from t2) union +(select b from t2); +show create table t1; +drop table t1; +create table t1 as +(select a from t2) union +(select b collate latin1_german1_ci from t2); +show create table t1; +drop table t1; +drop table t2; + diff --git a/mysys/hash.c b/mysys/hash.c index 6f2788ddce7..cf0f1d2dde6 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -72,19 +72,48 @@ _hash_init(HASH *hash,CHARSET_INFO *charset, } -void hash_free(HASH *hash) +/* + Call hash->free on all elements in hash. + + SYNOPSIS + hash_free_elements() + hash hash table + + NOTES: + Sets records to 0 +*/ + +static inline void hash_free_elements(HASH *hash) { - DBUG_ENTER("hash_free"); if (hash->free) { - uint i,records; HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*); - for (i=0,records=hash->records ; i < records ; i++) - (*hash->free)(data[i].data); - hash->free=0; + HASH_LINK *end= data + hash->records; + while (data < end) + (*hash->free)((data++)->data); } - delete_dynamic(&hash->array); hash->records=0; +} + + +/* + Free memory used by hash. + + SYNOPSIS + hash_free() + hash the hash to delete elements of + + NOTES: Hash can't be reused wuthing calling hash_init again. +*/ + +void hash_free(HASH *hash) +{ + DBUG_ENTER("hash_free"); + DBUG_PRINT("enter",("hash: 0x%lxd",hash)); + + hash_free_elements(hash); + hash->free= 0; + delete_dynamic(&hash->array); DBUG_VOID_RETURN; } @@ -94,21 +123,17 @@ void hash_free(HASH *hash) SYNOPSIS hash_reset() - hash the hash to delete elements of + hash the hash to delete elements of */ void hash_reset(HASH *hash) { DBUG_ENTER("hash_reset"); - if (hash->free) - { - HASH_LINK *link= dynamic_element(&hash->array, 0, HASH_LINK*); - HASH_LINK *end= link + hash->records; - for (; link < end; ++link) - (*hash->free)(link->data); - } + DBUG_PRINT("enter",("hash: 0x%lxd",hash)); + + hash_free_elements(hash); reset_dynamic(&hash->array); - hash->records= 0; + /* Set row pointers so that the hash can be reused at once */ hash->blength= 1; hash->current_record= NO_RECORD; DBUG_VOID_RETURN; diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 3a09255b0b0..ca75842ffcf 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -38,7 +38,7 @@ #include <m_string.h> -inline void bitmap_lock(MY_BITMAP *map) +static inline void bitmap_lock(MY_BITMAP *map) { #ifdef THREAD if (map->mutex) @@ -47,7 +47,7 @@ inline void bitmap_lock(MY_BITMAP *map) } -inline void bitmap_unlock(MY_BITMAP *map) +static inline void bitmap_unlock(MY_BITMAP *map) { #ifdef THREAD if (map->mutex) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 72f1cb975c4..222abe81933 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -107,7 +107,7 @@ my_bool my_gethwaddr(uchar *to __attribute__((unused))) } #endif -#else MAIN +#else /* MAIN */ int main(int argc __attribute__((unused)),char **argv) { uchar mac[6]; diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index d9e46fe1beb..d47ca8de183 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -552,8 +552,14 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) { - /* We have already got a write lock or all locks are - TL_WRITE_ALLOW_WRITE */ + /* + We have already got a write lock or all locks are + TL_WRITE_ALLOW_WRITE + */ + DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d", + (ulong) lock->write_wait.data, + lock->write.data->type)); + (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; @@ -568,6 +574,8 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) } else { + DBUG_PRINT("info", ("write_wait.data: 0x%lx", + (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ if (lock_type == TL_WRITE_CONCURRENT_INSERT && diff --git a/ndb/examples/select_all/select_all.cpp b/ndb/examples/select_all/select_all.cpp index bd25fb60128..24bb1214bd2 100644 --- a/ndb/examples/select_all/select_all.cpp +++ b/ndb/examples/select_all/select_all.cpp @@ -98,7 +98,7 @@ void ResultSetContainer::init(NdbDictionary::Dictionary * dict, // Store all attribute names for the table for (int i = 0; i < m_cols; i++) { m_names[i] = new char[255]; - snprintf(m_names[i], 255, "%s", tab->getColumn(i)->getName()); + BaseString::snprintf(m_names[i], 255, "%s", tab->getColumn(i)->getName()); } } diff --git a/ndb/include/kernel/BlockNumbers.h b/ndb/include/kernel/BlockNumbers.h index e89a82ee0cb..cb3cc697eee 100644 --- a/ndb/include/kernel/BlockNumbers.h +++ b/ndb/include/kernel/BlockNumbers.h @@ -20,13 +20,13 @@ #include <kernel_types.h> #include <RefConvert.hpp> -// 240 +/* 240 */ #define MIN_API_BLOCK_NO 0x8000 -// 2047 +/* 2047 */ #define API_PACKED 0x07ff -// 4002 +/* 4002 */ #define API_CLUSTERMGR 0x0FA2 #define BACKUP 0xF4 diff --git a/ndb/include/kernel/GlobalSignalNumbers.h b/ndb/include/kernel/GlobalSignalNumbers.h index 88acef8c772..9413f4ef56a 100644 --- a/ndb/include/kernel/GlobalSignalNumbers.h +++ b/ndb/include/kernel/GlobalSignalNumbers.h @@ -78,7 +78,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_SCAN_NEXTREQ 28 #define GSN_SCAN_TABCONF 29 -// 30 unused +/* 30 unused */ #define GSN_SCAN_TABREF 31 #define GSN_SCAN_TABREQ 32 #define GSN_KEYINFO20 33 @@ -91,42 +91,42 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_TCSEIZEREF 38 #define GSN_TCSEIZEREQ 39 -// 40 unused -// 41 unused -// 42 unused -// 43 unused -// 44 unused -// 45 unused -// 46 unused -// 47 unused -// 48 unused -// 49 unused -// 50 unused -// 51 unused -// 52 unused -// 53 unused -// 54 unused -// 55 unused -// 56 unused -// 57 unused -// 58 unused -// 59 unused -// 60 unused -// 61 unused -// 62 unused -// 63 unused -// 64 unused -// 65 unused -// 66 unused +/* 40 unused */ +/* 41 unused */ +/* 42 unused */ +/* 43 unused */ +/* 44 unused */ +/* 45 unused */ +/* 46 unused */ +/* 47 unused */ +/* 48 unused */ +/* 49 unused */ +/* 50 unused */ +/* 51 unused */ +/* 52 unused */ +/* 53 unused */ +/* 54 unused */ +/* 55 unused */ +/* 56 unused */ +/* 57 unused */ +/* 58 unused */ +/* 59 unused */ +/* 60 unused */ +/* 61 unused */ +/* 62 unused */ +/* 63 unused */ +/* 64 unused */ +/* 65 unused */ +/* 66 unused */ /** * These are used only by kernel */ #define GSN_ACC_ABORTCONF 67 -// 68 unused -// 69 unused -// 70 unused +/* 68 unused */ +/* 69 unused */ +/* 70 unused */ #define GSN_ACC_ABORTREQ 71 #define GSN_ACC_CHECK_SCAN 72 #define GSN_ACC_COMMITCONF 73 @@ -172,42 +172,42 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_API_FAILCONF 113 #define GSN_API_FAILREQ 114 #define GSN_CNTR_START_REQ 115 -// 116 not unused +/* 116 not unused */ #define GSN_CNTR_START_REF 117 #define GSN_CNTR_START_CONF 118 #define GSN_CNTR_START_REP 119 -// 120 unused -// 121 unused -// 122 unused -// 123 unused -// 124 unused +/* 120 unused */ +/* 121 unused */ +/* 122 unused */ +/* 123 unused */ +/* 124 unused */ #define GSN_CHECK_LCP_STOP 125 -#define GSN_CLOSE_COMCONF 126 // local -#define GSN_CLOSE_COMREQ 127 // local -#define GSN_CM_ACKADD 128 // distr. -// 129 unused -#define GSN_CM_ADD 130 // distr. -// 131 unused -// 132 not unused -// 133 not unused -#define GSN_CM_HEARTBEAT 134 // distr. -// 135 unused -// 136 unused -// 137 unused -#define GSN_CM_NODEINFOCONF 138 // distr. -#define GSN_CM_NODEINFOREF 139 // distr. -#define GSN_CM_NODEINFOREQ 140 // distr. -#define GSN_CM_REGCONF 141 // distr. -#define GSN_CM_REGREF 142 // distr. -#define GSN_CM_REGREQ 143 // distr. -// 144 unused -// 145 unused -// 146 unused -#define GSN_CM_ADD_REP 147 // local -// 148 unused -// 149 unused -// 150 unused -#define GSN_CNTR_WAITREP 151 // distr. +#define GSN_CLOSE_COMCONF 126 /* local */ +#define GSN_CLOSE_COMREQ 127 /* local */ +#define GSN_CM_ACKADD 128 /* distr. */ +/* 129 unused */ +#define GSN_CM_ADD 130 /* distr. */ +/* 131 unused */ +/* 132 not unused */ +/* 133 not unused */ +#define GSN_CM_HEARTBEAT 134 /* distr. */ +/* 135 unused */ +/* 136 unused */ +/* 137 unused */ +#define GSN_CM_NODEINFOCONF 138 /* distr. */ +#define GSN_CM_NODEINFOREF 139 /* distr. */ +#define GSN_CM_NODEINFOREQ 140 /* distr. */ +#define GSN_CM_REGCONF 141 /* distr. */ +#define GSN_CM_REGREF 142 /* distr. */ +#define GSN_CM_REGREQ 143 /* distr. */ +/* 144 unused */ +/* 145 unused */ +/* 146 unused */ +#define GSN_CM_ADD_REP 147 /* local */ +/* 148 unused */ +/* 149 unused */ +/* 150 unused */ +#define GSN_CNTR_WAITREP 151 /* distr. */ #define GSN_COMMIT 152 #define GSN_COMMIT_FAILCONF 153 #define GSN_COMMIT_FAILREQ 154 @@ -220,7 +220,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_COMPLETEREQ 162 #define GSN_CONNECT_REP 163 #define GSN_CONTINUEB 164 -// 165 not unused +/* 165 not unused */ #define GSN_COPY_ACTIVECONF 166 #define GSN_COPY_ACTIVEREF 167 #define GSN_COPY_ACTIVEREQ 168 @@ -243,9 +243,9 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_DIADDTABCONF 185 #define GSN_DIADDTABREF 186 #define GSN_DIADDTABREQ 187 -// 188 not unused -// 189 not unused -// 190 not unused +/* 188 not unused */ +/* 189 not unused */ +/* 190 not unused */ #define GSN_DICTSTARTCONF 191 #define GSN_DICTSTARTREQ 192 @@ -301,9 +301,9 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_DIH_RESTARTREF 218 #define GSN_DIH_RESTARTREQ 219 -// 220 not unused -// 221 not unused -// 222 not unused +/* 220 not unused */ +/* 221 not unused */ +/* 222 not unused */ #define GSN_EMPTY_LCP_REQ 223 #define GSN_EMPTY_LCP_CONF 224 @@ -315,8 +315,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_MASTER_GCPREF 228 #define GSN_MASTER_GCPREQ 229 -// 230 not unused -// 231 not unused +/* 230 not unused */ +/* 231 not unused */ #define GSN_DIRELEASECONF 232 #define GSN_DIRELEASEREF 233 @@ -388,8 +388,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_LCP_HOLDOPREQ 299 #define GSN_SHRINKCHECK2 301 #define GSN_GET_SCHEMA_INFOREQ 302 -// 303 not unused -// 304 not unused +/* 303 not unused */ +/* 304 not unused */ #define GSN_LQH_RESTART_OP 305 #define GSN_LQH_TRANSCONF 306 #define GSN_LQH_TRANSREQ 307 @@ -421,12 +421,12 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_NEXT_SCANREQ 332 #define GSN_NEXTOPERATION 333 -#define GSN_READ_CONFIG_REQ 334 // new name for sizealt, local -#define GSN_READ_CONFIG_CONF 335 // new name for sizealt, local +#define GSN_READ_CONFIG_REQ 334 /* new name for sizealt, local */ +#define GSN_READ_CONFIG_CONF 335 /* new name for sizealt, local */ -// 336 unused -// 337 unused -// 338 unused +/* 336 unused */ +/* 337 unused */ +/* 338 unused */ #define GSN_OPEN_COMCONF 339 #define GSN_OPEN_COMREF 340 #define GSN_OPEN_COMREQ 341 @@ -452,7 +452,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_TUP_ALLOCREQ 360 #define GSN_TUP_DEALLOCREQ 361 -// 362 not unused +/* 362 not unused */ #define GSN_TUP_WRITELOG_REQ 363 #define GSN_LQH_WRITELOG_REQ 364 @@ -507,16 +507,16 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_TEST_ORD 407 #define GSN_TESTSIG 408 #define GSN_TIME_SIGNAL 409 -// 410 unused -// 411 unused -// 412 unused +/* 410 unused */ +/* 411 unused */ +/* 412 unused */ #define GSN_TUP_ABORTREQ 414 #define GSN_TUP_ADD_ATTCONF 415 #define GSN_TUP_ADD_ATTRREF 416 #define GSN_TUP_ADD_ATTRREQ 417 #define GSN_TUP_ATTRINFO 418 #define GSN_TUP_COMMITREQ 419 -// 420 unused +/* 420 unused */ #define GSN_TUP_LCPCONF 421 #define GSN_TUP_LCPREF 422 #define GSN_TUP_LCPREQ 423 @@ -553,8 +553,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_STATISTICS_CONF 454 #define GSN_START_ORD 455 -// 456 unused -// 457 unused +/* 456 unused */ +/* 457 unused */ #define GSN_EVENT_SUBSCRIBE_REQ 458 #define GSN_EVENT_SUBSCRIBE_CONF 459 @@ -576,7 +576,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_CHECKNODEGROUPSREQ 471 #define GSN_CHECKNODEGROUPSCONF 472 -// 473 unused +/* 473 unused */ #define GSN_ARBIT_PREPREQ 474 #define GSN_ARBIT_PREPCONF 475 #define GSN_ARBIT_PREPREF 476 @@ -612,7 +612,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_WAIT_GCP_REF 500 #define GSN_WAIT_GCP_CONF 501 -// 502 not used +/* 502 not used */ /** * Trigger and index signals @@ -732,7 +732,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_SUB_STOP_REQ 572 #define GSN_SUB_STOP_REF 573 #define GSN_SUB_STOP_CONF 574 -// 575 unused +/* 575 unused */ #define GSN_SUB_CREATE_REQ 576 #define GSN_SUB_CREATE_REF 577 #define GSN_SUB_CREATE_CONF 578 @@ -832,7 +832,7 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_GREP_REMOVE_REF 654 #define GSN_GREP_REMOVE_CONF 655 -// Start Global Replication +/* Start Global Replication */ #define GSN_GREP_REQ 656 /** @@ -891,8 +891,8 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_TUX_MAINT_CONF 678 #define GSN_TUX_MAINT_REF 679 -// not used 680 -// not used 681 +/* not used 680 */ +/* not used 681 */ /** * from mgmtsrvr to NDBCNTR @@ -903,10 +903,10 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_API_VERSION_REQ 697 #define GSN_API_VERSION_CONF 698 -// not used 686 -// not used 687 -// not used 689 -// not used 690 +/* not used 686 */ +/* not used 687 */ +/* not used 689 */ +/* not used 690 */ /** * SUMA restart protocol @@ -915,9 +915,9 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; #define GSN_SUMA_HANDOVER_REQ 692 #define GSN_SUMA_HANDOVER_CONF 693 -// not used 694 -// not used 695 -// not used 696 +/* not used 694 */ +/* not used 695 */ +/* not used 696 */ /** * GREP restart protocol diff --git a/ndb/include/kernel/LogLevel.hpp b/ndb/include/kernel/LogLevel.hpp index be0627c98a8..6cfbe44af86 100644 --- a/ndb/include/kernel/LogLevel.hpp +++ b/ndb/include/kernel/LogLevel.hpp @@ -47,6 +47,7 @@ public: LogLevel & operator= (const LogLevel &); enum EventCategory { + llInvalid = -1, llStartUp = CFG_LOGLEVEL_STARTUP - CFG_MIN_LOGLEVEL, llShutdown = CFG_LOGLEVEL_SHUTDOWN - CFG_MIN_LOGLEVEL, llStatistic = CFG_LOGLEVEL_STATISTICS - CFG_MIN_LOGLEVEL, diff --git a/ndb/include/kernel/ndb_limits.h b/ndb/include/kernel/ndb_limits.h index 9411a98f091..88fcff22da7 100644 --- a/ndb/include/kernel/ndb_limits.h +++ b/ndb/include/kernel/ndb_limits.h @@ -50,7 +50,7 @@ **/ #define MAX_TUPLES_PER_PAGE 8191 #define MAX_TUPLES_BITS 13 /* 13 bits = 8191 tuples per page */ -//#define MAX_NO_OF_TUPLEKEY 16 Not currently used +/*#define MAX_NO_OF_TUPLEKEY 16 Not currently used */ #define MAX_TABLES 1600 #define MAX_TAB_NAME_SIZE 128 #define MAX_ATTR_NAME_SIZE 32 @@ -108,13 +108,13 @@ /* * Ordered index constants. Make configurable per index later. */ -#define MAX_TTREE_NODE_SIZE 64 // total words in node -#define MAX_TTREE_PREF_SIZE 4 // words in min prefix -#define MAX_TTREE_NODE_SLACK 3 // diff between max and min occupancy +#define MAX_TTREE_NODE_SIZE 64 /* total words in node */ +#define MAX_TTREE_PREF_SIZE 4 /* words in min prefix */ +#define MAX_TTREE_NODE_SLACK 2 /* diff between max and min occupancy */ /* * Blobs. */ -#define NDB_BLOB_HEAD_SIZE 2 // sizeof(NdbBlob::Head) >> 2 +#define NDB_BLOB_HEAD_SIZE 2 /* sizeof(NdbBlob::Head) >> 2 */ #endif diff --git a/ndb/include/kernel/signaldata/ArbitSignalData.hpp b/ndb/include/kernel/signaldata/ArbitSignalData.hpp index 271b9920cd0..f255b8dcbbe 100644 --- a/ndb/include/kernel/signaldata/ArbitSignalData.hpp +++ b/ndb/include/kernel/signaldata/ArbitSignalData.hpp @@ -54,7 +54,7 @@ public: } inline void getText(char *buf, size_t buf_len) const { - snprintf(buf, buf_len, "%08x%08x", data[0], data[1]); + BaseString::snprintf(buf, buf_len, "%08x%08x", data[0], data[1]); } /* inline char* getText() const { @@ -113,19 +113,19 @@ public: static inline void getErrText(Uint32 code, char* buf, size_t buf_len) { switch (code) { case ErrTicket: - snprintf(buf, buf_len, "invalid arbitrator-ticket"); + BaseString::snprintf(buf, buf_len, "invalid arbitrator-ticket"); break; case ErrToomany: - snprintf(buf, buf_len, "too many requests"); + BaseString::snprintf(buf, buf_len, "too many requests"); break; case ErrState: - snprintf(buf, buf_len, "invalid state"); + BaseString::snprintf(buf, buf_len, "invalid state"); break; case ErrTimeout: - snprintf(buf, buf_len, "timeout"); + BaseString::snprintf(buf, buf_len, "timeout"); break; default: - snprintf(buf, buf_len, "unknown error [code=%u]", code); + BaseString::snprintf(buf, buf_len, "unknown error [code=%u]", code); break; } } diff --git a/ndb/include/kernel/signaldata/AttrInfo.hpp b/ndb/include/kernel/signaldata/AttrInfo.hpp index 18bd9b22c40..c87470db8b0 100644 --- a/ndb/include/kernel/signaldata/AttrInfo.hpp +++ b/ndb/include/kernel/signaldata/AttrInfo.hpp @@ -35,7 +35,8 @@ class AttrInfo { */ friend class Dbtc; friend class Dblqh; - + friend class NdbScanOperation; + friend bool printATTRINFO(FILE *, const Uint32 *, Uint32, Uint16); public: diff --git a/ndb/include/kernel/signaldata/DictTabInfo.hpp b/ndb/include/kernel/signaldata/DictTabInfo.hpp index a9a50f19fbc..df0ac988e6e 100644 --- a/ndb/include/kernel/signaldata/DictTabInfo.hpp +++ b/ndb/include/kernel/signaldata/DictTabInfo.hpp @@ -38,7 +38,7 @@ offsetof(x, l) } #define DTIBREAK(x) \ - { DictTabInfo::x, 0, SimpleProperties::InvalidValue, 0, 0 } + { DictTabInfo::x, 0, SimpleProperties::InvalidValue, 0, 0, 0 } class DictTabInfo { /** diff --git a/ndb/include/kernel/signaldata/DihContinueB.hpp b/ndb/include/kernel/signaldata/DihContinueB.hpp index e683b55351c..77ecf360601 100644 --- a/ndb/include/kernel/signaldata/DihContinueB.hpp +++ b/ndb/include/kernel/signaldata/DihContinueB.hpp @@ -24,7 +24,8 @@ class DihContinueB { * Sender(s)/Reciver(s) */ friend class Dbdih; - friend bool printCONTINUEB_DBDIH(FILE * output, const Uint32 * theData, Uint32 len); + friend bool printCONTINUEB_DBDIH(FILE * output, const Uint32 * theData, + Uint32 len, Uint16); private: enum Type { ZPACK_TABLE_INTO_PAGES = 1, diff --git a/ndb/include/kernel/signaldata/KeyInfo.hpp b/ndb/include/kernel/signaldata/KeyInfo.hpp index a4c698f89b2..686f3ae053d 100644 --- a/ndb/include/kernel/signaldata/KeyInfo.hpp +++ b/ndb/include/kernel/signaldata/KeyInfo.hpp @@ -26,6 +26,7 @@ class KeyInfo { friend class DbUtil; friend class NdbOperation; friend class NdbScanOperation; + friend class NdbIndexScanOperation; /** * Reciver(s) diff --git a/ndb/include/kernel/signaldata/NdbfsContinueB.hpp b/ndb/include/kernel/signaldata/NdbfsContinueB.hpp index 2d569be721f..6154e5c19b1 100644 --- a/ndb/include/kernel/signaldata/NdbfsContinueB.hpp +++ b/ndb/include/kernel/signaldata/NdbfsContinueB.hpp @@ -24,7 +24,8 @@ class NdbfsContinueB { * Sender(s)/Reciver(s) */ friend class Ndbfs; - friend bool printCONTINUEB_NDBFS(FILE * output, const Uint32 * theData, Uint32 len); + friend bool printCONTINUEB_NDBFS(FILE * output, const Uint32 * theData, + Uint32 len, Uint16); private: enum { ZSCAN_MEMORYCHANNEL_10MS_DELAY = 0, diff --git a/ndb/include/kernel/signaldata/ScanFrag.hpp b/ndb/include/kernel/signaldata/ScanFrag.hpp index d3a89b8dc25..41ea569c45d 100644 --- a/ndb/include/kernel/signaldata/ScanFrag.hpp +++ b/ndb/include/kernel/signaldata/ScanFrag.hpp @@ -34,14 +34,16 @@ class ScanFragReq { friend class Dblqh; public: STATIC_CONST( SignalLength = 12 ); - + + friend bool printSCAN_FRAGREQ(FILE *, const Uint32*, Uint32, Uint16); + public: Uint32 senderData; Uint32 resultRef; // Where to send the result Uint32 savePointId; Uint32 requestInfo; Uint32 tableId; - Uint32 fragmentNo; + Uint32 fragmentNoKeyLen; Uint32 schemaVersion; Uint32 transId1; Uint32 transId2; diff --git a/ndb/include/kernel/signaldata/ScanTab.hpp b/ndb/include/kernel/signaldata/ScanTab.hpp index 1acd7ae4736..fb5f18eae9e 100644 --- a/ndb/include/kernel/signaldata/ScanTab.hpp +++ b/ndb/include/kernel/signaldata/ScanTab.hpp @@ -55,7 +55,7 @@ private: * DATA VARIABLES */ UintR apiConnectPtr; // DATA 0 - UintR attrLen; // DATA 1 + UintR attrLenKeyLen; // DATA 1 UintR requestInfo; // DATA 2 UintR tableId; // DATA 3 UintR tableSchemaVersion; // DATA 4 @@ -74,6 +74,7 @@ private: static Uint8 getHoldLockFlag(const UintR & requestInfo); static Uint8 getReadCommittedFlag(const UintR & requestInfo); static Uint8 getRangeScanFlag(const UintR & requestInfo); + static Uint8 getKeyinfoFlag(const UintR & requestInfo); static Uint16 getScanBatch(const UintR & requestInfo); /** @@ -85,6 +86,7 @@ private: static void setHoldLockFlag(UintR & requestInfo, Uint32 flag); static void setReadCommittedFlag(UintR & requestInfo, Uint32 flag); static void setRangeScanFlag(UintR & requestInfo, Uint32 flag); + static void setKeyinfoFlag(UintR & requestInfo, Uint32 flag); static void setScanBatch(Uint32& requestInfo, Uint32 sz); }; @@ -95,12 +97,13 @@ private: l = Lock mode - 1 Bit 8 h = Hold lock mode - 1 Bit 10 c = Read Committed - 1 Bit 11 + k = Keyinfo - 1 Bit 12 x = Range Scan (TUX) - 1 Bit 15 b = Scan batch - 10 Bit 16-25 (max 1023) 1111111111222222222233 01234567890123456789012345678901 - ppppppppl hc xbbbbbbbbbb + ppppppppl hck xbbbbbbbbbb */ #define PARALLELL_SHIFT (0) @@ -112,6 +115,9 @@ private: #define HOLD_LOCK_SHIFT (10) #define HOLD_LOCK_MASK (1) +#define KEYINFO_SHIFT (12) +#define KEYINFO_MASK (1) + #define READ_COMMITTED_SHIFT (11) #define READ_COMMITTED_MASK (1) @@ -206,6 +212,20 @@ ScanTabReq::setScanBatch(Uint32 & requestInfo, Uint32 flag){ requestInfo |= (flag << SCAN_BATCH_SHIFT); } +inline +Uint8 +ScanTabReq::getKeyinfoFlag(const UintR & requestInfo){ + return (Uint8)((requestInfo >> KEYINFO_SHIFT) & KEYINFO_MASK); +} + +inline +void +ScanTabReq::setKeyinfoFlag(UintR & requestInfo, Uint32 flag){ + ASSERT_BOOL(flag, "ScanTabReq::setKeyinfoFlag"); + requestInfo |= (flag << KEYINFO_SHIFT); +} + + /** * * SENDER: Dbtc diff --git a/ndb/include/kernel/signaldata/SignalData.hpp b/ndb/include/kernel/signaldata/SignalData.hpp index 6e5748217b2..f9d3a6faa64 100644 --- a/ndb/include/kernel/signaldata/SignalData.hpp +++ b/ndb/include/kernel/signaldata/SignalData.hpp @@ -20,6 +20,7 @@ #include <ndb_global.h> #include <ndb_limits.h> #include <kernel_types.h> +#include <BaseString.hpp> #define ASSERT_BOOL(flag, message) assert(flag<=1) #define ASSERT_RANGE(value, min, max, message) \ @@ -50,4 +51,169 @@ Uint32 getTCErrorCode() { return TCErrorCode; }; \ void setTCErrorCode(Uint32 _s) { TCErrorCode = _s; }; +#define GSN_PRINT_SIGNATURE(f) bool f(FILE *, const Uint32 *, Uint32, Uint16) + +GSN_PRINT_SIGNATURE(printTCKEYREQ); +GSN_PRINT_SIGNATURE(printTCKEYCONF); +GSN_PRINT_SIGNATURE(printTCKEYREF); +GSN_PRINT_SIGNATURE(printLQHKEYREQ); +GSN_PRINT_SIGNATURE(printLQHKEYCONF); +GSN_PRINT_SIGNATURE(printLQHKEYREF); +GSN_PRINT_SIGNATURE(printTUPKEYREQ); +GSN_PRINT_SIGNATURE(printTUPKEYCONF); +GSN_PRINT_SIGNATURE(printTUPKEYREF); +GSN_PRINT_SIGNATURE(printTUPCOMMITREQ); +GSN_PRINT_SIGNATURE(printCONTINUEB); +GSN_PRINT_SIGNATURE(printFSOPENREQ); +GSN_PRINT_SIGNATURE(printFSCLOSEREQ); +GSN_PRINT_SIGNATURE(printFSREADWRITEREQ); +GSN_PRINT_SIGNATURE(printFSREADWRITEREQ); +GSN_PRINT_SIGNATURE(printFSREF); +GSN_PRINT_SIGNATURE(printFSREF); +GSN_PRINT_SIGNATURE(printFSREF); +GSN_PRINT_SIGNATURE(printFSREF); +GSN_PRINT_SIGNATURE(printFSREF); +GSN_PRINT_SIGNATURE(printFSCONF); +GSN_PRINT_SIGNATURE(printFSCONF); +GSN_PRINT_SIGNATURE(printFSCONF); +GSN_PRINT_SIGNATURE(printFSCONF); +GSN_PRINT_SIGNATURE(printFSCONF); +GSN_PRINT_SIGNATURE(printCLOSECOMREQCONF); +GSN_PRINT_SIGNATURE(printCLOSECOMREQCONF); +GSN_PRINT_SIGNATURE(printPACKED_SIGNAL); +GSN_PRINT_SIGNATURE(printPREPFAILREQREF); +GSN_PRINT_SIGNATURE(printPREPFAILREQREF); +GSN_PRINT_SIGNATURE(printALTER_TABLE_REQ); +GSN_PRINT_SIGNATURE(printALTER_TABLE_CONF); +GSN_PRINT_SIGNATURE(printALTER_TABLE_REF); +GSN_PRINT_SIGNATURE(printALTER_TAB_REQ); +GSN_PRINT_SIGNATURE(printALTER_TAB_CONF); +GSN_PRINT_SIGNATURE(printALTER_TAB_REF); +GSN_PRINT_SIGNATURE(printCREATE_TRIG_REQ); +GSN_PRINT_SIGNATURE(printCREATE_TRIG_CONF); +GSN_PRINT_SIGNATURE(printCREATE_TRIG_REF); +GSN_PRINT_SIGNATURE(printALTER_TRIG_REQ); +GSN_PRINT_SIGNATURE(printALTER_TRIG_CONF); +GSN_PRINT_SIGNATURE(printALTER_TRIG_REF); +GSN_PRINT_SIGNATURE(printDROP_TRIG_REQ); +GSN_PRINT_SIGNATURE(printDROP_TRIG_CONF); +GSN_PRINT_SIGNATURE(printDROP_TRIG_REF); +GSN_PRINT_SIGNATURE(printFIRE_TRIG_ORD); +GSN_PRINT_SIGNATURE(printTRIG_ATTRINFO); +GSN_PRINT_SIGNATURE(printCREATE_INDX_REQ); +GSN_PRINT_SIGNATURE(printCREATE_INDX_CONF); +GSN_PRINT_SIGNATURE(printCREATE_INDX_REF); +GSN_PRINT_SIGNATURE(printDROP_INDX_REQ); +GSN_PRINT_SIGNATURE(printDROP_INDX_CONF); +GSN_PRINT_SIGNATURE(printDROP_INDX_REF); +GSN_PRINT_SIGNATURE(printALTER_INDX_REQ); +GSN_PRINT_SIGNATURE(printALTER_INDX_CONF); +GSN_PRINT_SIGNATURE(printALTER_INDX_REF); +GSN_PRINT_SIGNATURE(printTCINDXREQ); +GSN_PRINT_SIGNATURE(printTCINDXCONF); +GSN_PRINT_SIGNATURE(printTCINDXREF); +GSN_PRINT_SIGNATURE(printINDXKEYINFO); +GSN_PRINT_SIGNATURE(printINDXATTRINFO); +GSN_PRINT_SIGNATURE(printFSAPPENDREQ); +GSN_PRINT_SIGNATURE(printBACKUP_REQ); +GSN_PRINT_SIGNATURE(printBACKUP_DATA); +GSN_PRINT_SIGNATURE(printBACKUP_REF); +GSN_PRINT_SIGNATURE(printBACKUP_CONF); +GSN_PRINT_SIGNATURE(printABORT_BACKUP_ORD); +GSN_PRINT_SIGNATURE(printBACKUP_ABORT_REP); +GSN_PRINT_SIGNATURE(printBACKUP_COMPLETE_REP); +GSN_PRINT_SIGNATURE(printBACKUP_NF_COMPLETE_REP); +GSN_PRINT_SIGNATURE(printDEFINE_BACKUP_REQ); +GSN_PRINT_SIGNATURE(printDEFINE_BACKUP_REF); +GSN_PRINT_SIGNATURE(printDEFINE_BACKUP_CONF); +GSN_PRINT_SIGNATURE(printSTART_BACKUP_REQ); +GSN_PRINT_SIGNATURE(printSTART_BACKUP_REF); +GSN_PRINT_SIGNATURE(printSTART_BACKUP_CONF); +GSN_PRINT_SIGNATURE(printBACKUP_FRAGMENT_REQ); +GSN_PRINT_SIGNATURE(printBACKUP_FRAGMENT_REF); +GSN_PRINT_SIGNATURE(printBACKUP_FRAGMENT_CONF); +GSN_PRINT_SIGNATURE(printSTOP_BACKUP_REQ); +GSN_PRINT_SIGNATURE(printSTOP_BACKUP_REF); +GSN_PRINT_SIGNATURE(printSTOP_BACKUP_CONF); +GSN_PRINT_SIGNATURE(printBACKUP_STATUS_REQ); +GSN_PRINT_SIGNATURE(printBACKUP_STATUS_CONF); +GSN_PRINT_SIGNATURE(printUTIL_SEQUENCE_REQ); +GSN_PRINT_SIGNATURE(printUTIL_SEQUENCE_REF); +GSN_PRINT_SIGNATURE(printUTIL_SEQUENCE_CONF); +GSN_PRINT_SIGNATURE(printUTIL_PREPARE_REQ); +GSN_PRINT_SIGNATURE(printUTIL_PREPARE_REF); +GSN_PRINT_SIGNATURE(printUTIL_PREPARE_CONF); +GSN_PRINT_SIGNATURE(printUTIL_EXECUTE_REQ); +GSN_PRINT_SIGNATURE(printUTIL_EXECUTE_REF); +GSN_PRINT_SIGNATURE(printUTIL_EXECUTE_CONF); +GSN_PRINT_SIGNATURE(printSCANTABREQ); +GSN_PRINT_SIGNATURE(printSCANTABCONF); +GSN_PRINT_SIGNATURE(printSCANTABREF); +GSN_PRINT_SIGNATURE(printSCANNEXTREQ); +GSN_PRINT_SIGNATURE(printLQH_FRAG_REQ); +GSN_PRINT_SIGNATURE(printLQH_FRAG_REF); +GSN_PRINT_SIGNATURE(printLQH_FRAG_CONF); +GSN_PRINT_SIGNATURE(printPREP_DROP_TAB_REQ); +GSN_PRINT_SIGNATURE(printPREP_DROP_TAB_REF); +GSN_PRINT_SIGNATURE(printPREP_DROP_TAB_CONF); +GSN_PRINT_SIGNATURE(printDROP_TAB_REQ); +GSN_PRINT_SIGNATURE(printDROP_TAB_REF); +GSN_PRINT_SIGNATURE(printDROP_TAB_CONF); +GSN_PRINT_SIGNATURE(printLCP_FRAG_ORD); +GSN_PRINT_SIGNATURE(printLCP_FRAG_REP); +GSN_PRINT_SIGNATURE(printLCP_COMPLETE_REP); +GSN_PRINT_SIGNATURE(printSTART_LCP_REQ); +GSN_PRINT_SIGNATURE(printSTART_LCP_CONF); +GSN_PRINT_SIGNATURE(printMASTER_LCP_REQ); +GSN_PRINT_SIGNATURE(printMASTER_LCP_REF); +GSN_PRINT_SIGNATURE(printMASTER_LCP_CONF); +GSN_PRINT_SIGNATURE(printCOPY_GCI_REQ); +GSN_PRINT_SIGNATURE(printSYSTEM_ERROR); +GSN_PRINT_SIGNATURE(printSTART_REC_REQ); +GSN_PRINT_SIGNATURE(printSTART_REC_CONF); +GSN_PRINT_SIGNATURE(printNF_COMPLETE_REP); +GSN_PRINT_SIGNATURE(printSIGNAL_DROPPED_REP); +GSN_PRINT_SIGNATURE(printFAIL_REP); +GSN_PRINT_SIGNATURE(printDISCONNECT_REP); +GSN_PRINT_SIGNATURE(printSUB_CREATE_REQ); +GSN_PRINT_SIGNATURE(printSUB_CREATE_CONF); +GSN_PRINT_SIGNATURE(printSUB_START_REQ); +GSN_PRINT_SIGNATURE(printSUB_START_REF); +GSN_PRINT_SIGNATURE(printSUB_START_CONF); +GSN_PRINT_SIGNATURE(printSUB_SYNC_REQ); +GSN_PRINT_SIGNATURE(printSUB_SYNC_REF); +GSN_PRINT_SIGNATURE(printSUB_SYNC_CONF); +GSN_PRINT_SIGNATURE(printSUB_META_DATA); +GSN_PRINT_SIGNATURE(printSUB_TABLE_DATA); +GSN_PRINT_SIGNATURE(printSUB_SYNC_CONTINUE_REQ); +GSN_PRINT_SIGNATURE(printSUB_SYNC_CONTINUE_REF); +GSN_PRINT_SIGNATURE(printSUB_SYNC_CONTINUE_CONF); +GSN_PRINT_SIGNATURE(printSUB_GCP_COMPLETE_REP); +GSN_PRINT_SIGNATURE(printCREATE_FRAGMENTATION_REQ); +GSN_PRINT_SIGNATURE(printCREATE_FRAGMENTATION_REF); +GSN_PRINT_SIGNATURE(printCREATE_FRAGMENTATION_CONF); +GSN_PRINT_SIGNATURE(printUTIL_CREATE_LOCK_REQ); +GSN_PRINT_SIGNATURE(printUTIL_CREATE_LOCK_REF); +GSN_PRINT_SIGNATURE(printUTIL_CREATE_LOCK_CONF); +GSN_PRINT_SIGNATURE(printUTIL_DESTROY_LOCK_REQ); +GSN_PRINT_SIGNATURE(printUTIL_DESTROY_LOCK_REF); +GSN_PRINT_SIGNATURE(printUTIL_DESTROY_LOCK_CONF); +GSN_PRINT_SIGNATURE(printUTIL_LOCK_REQ); +GSN_PRINT_SIGNATURE(printUTIL_LOCK_REF); +GSN_PRINT_SIGNATURE(printUTIL_LOCK_CONF); +GSN_PRINT_SIGNATURE(printUTIL_UNLOCK_REQ); +GSN_PRINT_SIGNATURE(printUTIL_UNLOCK_REF); +GSN_PRINT_SIGNATURE(printUTIL_UNLOCK_CONF); +GSN_PRINT_SIGNATURE(printCNTR_START_REQ); +GSN_PRINT_SIGNATURE(printCNTR_START_REF); +GSN_PRINT_SIGNATURE(printCNTR_START_CONF); +GSN_PRINT_SIGNATURE(printREAD_NODES_CONF); +GSN_PRINT_SIGNATURE(printTUX_MAINT_REQ); +GSN_PRINT_SIGNATURE(printACC_LOCKREQ); +GSN_PRINT_SIGNATURE(printLQH_TRANSCONF); +GSN_PRINT_SIGNATURE(printSCAN_FRAGREQ); + +GSN_PRINT_SIGNATURE(printCONTINUEB_NDBFS); +GSN_PRINT_SIGNATURE(printCONTINUEB_DBDIH); + #endif diff --git a/ndb/include/kernel/signaldata/TcContinueB.hpp b/ndb/include/kernel/signaldata/TcContinueB.hpp index 7a093b457e8..85213791b2a 100644 --- a/ndb/include/kernel/signaldata/TcContinueB.hpp +++ b/ndb/include/kernel/signaldata/TcContinueB.hpp @@ -42,7 +42,9 @@ private: ZWAIT_ABORT_ALL = 14, ZCHECK_SCAN_ACTIVE_FAILED_LQH = 15, CHECK_WAIT_DROP_TAB_FAILED_LQH = 16, - TRIGGER_PENDING = 17 + TRIGGER_PENDING = 17, + + DelayTCKEYCONF = 18 }; }; diff --git a/ndb/include/kernel/signaldata/TcKeyConf.hpp b/ndb/include/kernel/signaldata/TcKeyConf.hpp index 27ff344f793..277872b990b 100644 --- a/ndb/include/kernel/signaldata/TcKeyConf.hpp +++ b/ndb/include/kernel/signaldata/TcKeyConf.hpp @@ -47,7 +47,8 @@ public: */ STATIC_CONST( StaticLength = 5 ); STATIC_CONST( OperationLength = 2 ); - + STATIC_CONST( SimpleReadBit = (((Uint32)1) << 31) ); + private: /** diff --git a/ndb/include/kernel/signaldata/TuxBound.hpp b/ndb/include/kernel/signaldata/TuxBound.hpp index 1f256150573..87ce3c3c098 100644 --- a/ndb/include/kernel/signaldata/TuxBound.hpp +++ b/ndb/include/kernel/signaldata/TuxBound.hpp @@ -48,7 +48,6 @@ private: Uint32 tuxScanPtrI; /* * Number of words of bound info included after fixed signal data. - * Starts with 5 unused words (word 0 is length used by LQH). */ Uint32 boundAiLength; }; diff --git a/ndb/include/kernel/signaldata/UpgradeStartup.hpp b/ndb/include/kernel/signaldata/UpgradeStartup.hpp index badc7ca0e4d..a4450221c59 100644 --- a/ndb/include/kernel/signaldata/UpgradeStartup.hpp +++ b/ndb/include/kernel/signaldata/UpgradeStartup.hpp @@ -1,6 +1,8 @@ #ifndef NDB_UPGRADE_STARTUP #define NDB_UPGRADE_STARTUP +class Ndbcntr; + struct UpgradeStartup { static void installEXEC(SimulatedBlock*); diff --git a/ndb/include/kernel/trigger_definitions.h b/ndb/include/kernel/trigger_definitions.h index 439d65c6c30..7ce74877de4 100644 --- a/ndb/include/kernel/trigger_definitions.h +++ b/ndb/include/kernel/trigger_definitions.h @@ -47,11 +47,11 @@ struct TriggerType { struct TriggerActionTime { enum Value { - TA_BEFORE = 0, // Immediate, before operation - TA_AFTER = 1, // Immediate, after operation - TA_DEFERRED = 2, // Before commit - TA_DETACHED = 3, // After commit in a separate transaction, NYI - TA_CUSTOM = 4 // Hardcoded per TriggerType + TA_BEFORE = 0, /* Immediate, before operation */ + TA_AFTER = 1, /* Immediate, after operation */ + TA_DEFERRED = 2, /* Before commit */ + TA_DETACHED = 3, /* After commit in a separate transaction, NYI */ + TA_CUSTOM = 4 /* Hardcoded per TriggerType */ }; }; @@ -60,7 +60,7 @@ struct TriggerEvent { TE_INSERT = 0, TE_DELETE = 1, TE_UPDATE = 2, - TE_CUSTOM = 3 // Hardcoded per TriggerType + TE_CUSTOM = 3 /* Hardcoded per TriggerType */ }; }; diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 44307c3e73c..6dcf58b44e2 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -64,32 +64,32 @@ extern "C" { * NDB Cluster node types */ enum ndb_mgm_node_type { - NDB_MGM_NODE_TYPE_UNKNOWN = -1, /*/< Node type not known*/ - NDB_MGM_NODE_TYPE_API = NODE_TYPE_API, /*/< An application node (API)*/ - NDB_MGM_NODE_TYPE_NDB = NODE_TYPE_DB, /*/< A database node (DB)*/ - NDB_MGM_NODE_TYPE_MGM = NODE_TYPE_MGM, /*/< A management server node (MGM)*/ - NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP, ///< A replication node - - NDB_MGM_NODE_TYPE_MIN = 0, /*/< Min valid value*/ - NDB_MGM_NODE_TYPE_MAX = 3 /*/< Max valid value*/ + NDB_MGM_NODE_TYPE_UNKNOWN = -1, /*< Node type not known*/ + NDB_MGM_NODE_TYPE_API = NODE_TYPE_API,/*< An application node (API)*/ + NDB_MGM_NODE_TYPE_NDB = NODE_TYPE_DB, /*< A database node (DB)*/ + NDB_MGM_NODE_TYPE_MGM = NODE_TYPE_MGM,/*< A mgmt server node (MGM)*/ + NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP,/*< A replication node */ + + NDB_MGM_NODE_TYPE_MIN = 0, /*< Min valid value*/ + NDB_MGM_NODE_TYPE_MAX = 3 /*< Max valid value*/ }; /** * Database node status */ enum ndb_mgm_node_status { - NDB_MGM_NODE_STATUS_UNKNOWN = 0, ///< Node status not known - NDB_MGM_NODE_STATUS_NO_CONTACT = 1, ///< No contact with node - NDB_MGM_NODE_STATUS_NOT_STARTED = 2, ///< Has not run starting protocol - NDB_MGM_NODE_STATUS_STARTING = 3, ///< Is running starting protocol - NDB_MGM_NODE_STATUS_STARTED = 4, ///< Running - NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5, ///< Is shutting down - NDB_MGM_NODE_STATUS_RESTARTING = 6, ///< Is restarting - NDB_MGM_NODE_STATUS_SINGLEUSER = 7, ///< Maintenance mode - NDB_MGM_NODE_STATUS_RESUME = 8, ///< Resume mode - - NDB_MGM_NODE_STATUS_MIN = 0, ///< Min valid value - NDB_MGM_NODE_STATUS_MAX = 6 ///< Max valid value + NDB_MGM_NODE_STATUS_UNKNOWN = 0, /*< Node status not known*/ + NDB_MGM_NODE_STATUS_NO_CONTACT = 1, /*< No contact with node*/ + NDB_MGM_NODE_STATUS_NOT_STARTED = 2, /*< Has not run starting protocol*/ + NDB_MGM_NODE_STATUS_STARTING = 3, /*< Is running starting protocol*/ + NDB_MGM_NODE_STATUS_STARTED = 4, /*< Running*/ + NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5, /*< Is shutting down*/ + NDB_MGM_NODE_STATUS_RESTARTING = 6, /*< Is restarting*/ + NDB_MGM_NODE_STATUS_SINGLEUSER = 7, /*< Maintenance mode*/ + NDB_MGM_NODE_STATUS_RESUME = 8, /*< Resume mode*/ + + NDB_MGM_NODE_STATUS_MIN = 0, /*< Min valid value*/ + NDB_MGM_NODE_STATUS_MAX = 6 /*< Max valid value*/ }; /** @@ -122,7 +122,10 @@ extern "C" { /* Service errors - Single User Mode */ NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE = 4001, - NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE = 4002 + NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE = 4002, + + /* Usage errors */ + NDB_MGM_USAGE_ERROR = 5001 }; struct Ndb_Mgm_Error_Msg { @@ -158,7 +161,11 @@ extern "C" { { NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE, "Could not enter single user mode" }, { NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE, - "Could not exit single user mode" } + "Could not exit single user mode" }, + + /* Usage errors */ + { NDB_MGM_USAGE_ERROR, + "Usage error" } }; const int ndb_mgm_noOfErrorMsgs = @@ -168,24 +175,27 @@ extern "C" { * Structure returned by ndb_mgm_get_status */ struct ndb_mgm_node_state { - int node_id; ///< NDB Cluster node id - enum ndb_mgm_node_type node_type; ///< Type of NDB Cluster node - enum ndb_mgm_node_status node_status; ///< State of node - int start_phase; ///< Start phase. - ///< @note Start phase is only - ///< valid if - ///< node_type is - ///< NDB_MGM_NODE_TYPE_NDB and - ///< node_status is - ///< NDB_MGM_NODE_STATUS_STARTING - int dynamic_id; ///< Id for heartbeats and - ///< master take-over - ///< (only valid for DB nodes) - int node_group; ///< Node group of node - ///< (only valid for DB nodes) - int version; ///< Internal version number - int connect_count; ///< No of times node has connected - ///< or disconnected to the mgm srv + int node_id; /*< NDB Cluster node id*/ + enum ndb_mgm_node_type node_type; /*< Type of NDB Cluster node*/ + enum ndb_mgm_node_status node_status; /*< State of node*/ + int start_phase; /*< Start phase. + *< @note Start phase is only + *< valid if + *< node_type is + *< NDB_MGM_NODE_TYPE_NDB and + *< node_status is + *< NDB_MGM_NODE_STATUS_STARTING + */ + int dynamic_id; /*< Id for heartbeats and + *< master take-over + *< (only valid for DB nodes) + */ + int node_group; /*< Node group of node + *< (only valid for DB nodes)*/ + int version; /*< Internal version number*/ + int connect_count; /*< No of times node has connected + *< or disconnected to the mgm srv + */ char connect_address[sizeof("000.000.000.000")+1]; }; @@ -193,9 +203,10 @@ extern "C" { * Cluster status */ struct ndb_mgm_cluster_state { - int no_of_nodes; ///< No of entries in the - ///< node_states array - struct ndb_mgm_node_state ///< An array with node_states + int no_of_nodes; /*< No of entries in the + *< node_states array + */ + struct ndb_mgm_node_state /*< An array with node_states*/ node_states[1]; const char *hostname; }; @@ -204,17 +215,18 @@ extern "C" { * Default reply from the server */ struct ndb_mgm_reply { - int return_code; ///< 0 if successful, - ///< otherwise error code. - char message[256]; ///< Error or reply message. + int return_code; /*< 0 if successful, + *< otherwise error code. + */ + char message[256]; /*< Error or reply message.*/ }; /** * Default information types */ enum ndb_mgm_info { - NDB_MGM_INFO_CLUSTER, ///< ? - NDB_MGM_INFO_CLUSTERLOG ///< Cluster log + NDB_MGM_INFO_CLUSTER, /*< ?*/ + NDB_MGM_INFO_CLUSTERLOG /*< Cluster log*/ }; /** @@ -222,39 +234,47 @@ extern "C" { * (Used only in the development of NDB Cluster.) */ enum ndb_mgm_signal_log_mode { - NDB_MGM_SIGNAL_LOG_MODE_IN, ///< Log receiving signals - NDB_MGM_SIGNAL_LOG_MODE_OUT, ///< Log sending signals - NDB_MGM_SIGNAL_LOG_MODE_INOUT, ///< Log both sending/receiving - NDB_MGM_SIGNAL_LOG_MODE_OFF ///< Log off + NDB_MGM_SIGNAL_LOG_MODE_IN, /*< Log receiving signals */ + NDB_MGM_SIGNAL_LOG_MODE_OUT, /*< Log sending signals*/ + NDB_MGM_SIGNAL_LOG_MODE_INOUT, /*< Log both sending/receiving*/ + NDB_MGM_SIGNAL_LOG_MODE_OFF /*< Log off*/ }; /** * Log severities (used to filter the cluster log) */ enum ndb_mgm_clusterlog_level { - NDB_MGM_CLUSTERLOG_OFF = 0, ///< Cluster log off - NDB_MGM_CLUSTERLOG_DEBUG = 1, ///< Used in NDB Cluster - ///< developement - NDB_MGM_CLUSTERLOG_INFO = 2, ///< Informational messages - NDB_MGM_CLUSTERLOG_WARNING = 3, ///< Conditions that are not - ///< error condition, but - ///< might require handling - NDB_MGM_CLUSTERLOG_ERROR = 4, ///< Conditions that should be - ///< corrected - NDB_MGM_CLUSTERLOG_CRITICAL = 5, ///< Critical conditions, like - ///< device errors or out of - ///< resources - NDB_MGM_CLUSTERLOG_ALERT = 6, ///< A condition that should be - ///< corrected immediately, - ///< such as a corrupted system - NDB_MGM_CLUSTERLOG_ALL = 7 ///< All severities on + NDB_MGM_CLUSTERLOG_OFF = 0, /*< Cluster log off*/ + NDB_MGM_CLUSTERLOG_DEBUG = 1, /*< Used in NDB Cluster + *< developement + */ + NDB_MGM_CLUSTERLOG_INFO = 2, /*< Informational messages*/ + NDB_MGM_CLUSTERLOG_WARNING = 3, /*< Conditions that are not + *< error condition, but + *< might require handling + */ + NDB_MGM_CLUSTERLOG_ERROR = 4, /*< Conditions that should be + *< corrected + */ + NDB_MGM_CLUSTERLOG_CRITICAL = 5, /*< Critical conditions, like + *< device errors or out of + *< resources + */ + NDB_MGM_CLUSTERLOG_ALERT = 6, /*< A condition that should be + *< corrected immediately, + *< such as a corrupted system + */ + NDB_MGM_CLUSTERLOG_ALL = 7 /*< All severities on*/ }; /** * Log categories */ enum ndb_mgm_event_category { - NDB_MGM_ILLEGAL_EVENT_CATEGORY = -1, ///< Invalid + /** + * Invalid + */ + NDB_MGM_ILLEGAL_EVENT_CATEGORY = -1, /** * Events during all kinds of startups */ diff --git a/ndb/include/mgmcommon/LocalConfig.hpp b/ndb/include/mgmcommon/LocalConfig.hpp index c741b35f482..9ceeffdba36 100644 --- a/ndb/include/mgmcommon/LocalConfig.hpp +++ b/ndb/include/mgmcommon/LocalConfig.hpp @@ -53,14 +53,14 @@ struct LocalConfig { void printUsage() const; void setError(int lineNumber, const char * _msg); - bool readConnectString(const char *); + bool readConnectString(const char *, const char *info); bool readFile(const char * file, bool &fopenError); bool parseLine(char * line, int lineNumber); bool parseNodeId(const char *buf); bool parseHostName(const char *buf); bool parseFileName(const char *buf); - bool parseString(const char *buf, char *line); + bool parseString(const char *buf, BaseString &err); }; #endif // LocalConfig_H diff --git a/ndb/include/ndb_global.h b/ndb/include/ndb_global.h index 3ce37a2edee..c128323241a 100644 --- a/ndb/include/ndb_global.h +++ b/ndb/include/ndb_global.h @@ -13,6 +13,9 @@ #undef NDB_WIN32 #endif +#ifdef _AIX +#undef _H_STRINGS +#endif #include <m_string.h> #include <m_ctype.h> #include <ndb_types.h> diff --git a/ndb/include/ndb_types.h b/ndb/include/ndb_types.h index 87ebd3d6c6b..a2988dbae78 100644 --- a/ndb/include/ndb_types.h +++ b/ndb/include/ndb_types.h @@ -33,7 +33,7 @@ typedef unsigned int UintR; #ifdef __SIZE_TYPE__ typedef __SIZE_TYPE__ UintPtr; #else -#include <my_global.h> +#include <ndb_global.h> #ifdef HAVE_STDINT_H #include <stdint.h> #endif diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 550d0c0931a..5ec09269695 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -881,6 +881,7 @@ class Table; class BaseString; class NdbEventOperation; class NdbBlob; +class NdbReceiver; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); @@ -1612,7 +1613,6 @@ private: char prefixName[NDB_MAX_INTERNAL_TABLE_LENGTH]; char * prefixEnd; - //Table* theTable; // The table object class NdbImpl * theImpl; class NdbDictionaryImpl* theDictionary; class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle; @@ -1698,10 +1698,13 @@ private: NdbApiSignal* theCommitAckSignal; + +#ifdef POORMANSPURIFY int cfreeSignals; int cnewSignals; int cgetSignals; int creleaseSignals; +#endif static void executeMessage(void*, NdbApiSignal *, struct LinearSectionPtr ptr[3]); diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbConnection.hpp index ef4972f205b..92b940e96f7 100644 --- a/ndb/include/ndbapi/NdbConnection.hpp +++ b/ndb/include/ndbapi/NdbConnection.hpp @@ -526,9 +526,8 @@ private: int sendCOMMIT(); // Send a TC_COMMITREQ signal; void setGCI(int GCI); // Set the global checkpoint identity - int OpCompleteFailure(); // Operation Completed with success - int OpCompleteSuccess(); // Operation Completed with success - + int OpCompleteFailure(Uint8 abortoption); + int OpCompleteSuccess(); void CompletedOperations(); // Move active ops to list of completed void OpSent(); // Operation Sent with success @@ -649,6 +648,18 @@ private: Uint32 theNodeSequence; // The sequence no of the db node bool theReleaseOnClose; + /** + * handle transaction spanning + * multiple TC/db nodes + * + * 1) Bitmask with used nodes + * 2) Bitmask with nodes failed during op + */ + Uint32 m_db_nodes[2]; + Uint32 m_failed_db_nodes[2]; + + int report_node_failure(Uint32 id); + // Scan operations bool m_waitForReply; NdbIndexScanOperation* m_theFirstScanOperation; @@ -673,6 +684,9 @@ private: void printState(); #endif bool checkState_TransId(const Uint32 * transId) const; + + void remove_list(NdbOperation*& head, NdbOperation*); + void define_scan_op(NdbIndexScanOperation*); }; inline diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index 82aed04a9fc..66b3fc9d43b 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -56,27 +56,11 @@ public: } /** - * @name Define Range Scan - * - * A range scan is a scan on an ordered index. The operation is on - * the index table but tuples are returned from the primary table. - * The index contains all tuples where at least one index key has not - * null value. - * - * A range scan is currently opened via a normal open scan method. - * Bounds can be defined for each index key. After setting bounds, - * usual scan methods can be used (get value, interpreter, take over). - * These operate on the primary table. - * - * @{ - */ - - /** * Type of ordered index key bound. The values (0-4) will not change * and can be used explicitly (e.g. they could be computed). */ enum BoundType { - BoundLE = 0, ///< lower bound, + BoundLE = 0, ///< lower bound BoundLT = 1, ///< lower bound, strict BoundGE = 2, ///< upper bound BoundGT = 3, ///< upper bound, strict @@ -86,20 +70,28 @@ public: /** * Define bound on index key in range scan. * - * Each index key can have lower and/or upper bound, or can be set - * equal to a value. The bounds can be defined in any order but - * a duplicate definition is an error. + * Each index key can have lower and/or upper bound. Setting the key + * equal to a value defines both upper and lower bounds. The bounds + * can be defined in any order. Conflicting definitions is an error. + * + * For equality, it is better to use BoundEQ instead of the equivalent + * pair of BoundLE and BoundGE. This is especially true when table + * distribution key is an initial part of the index key. + * + * The sets of lower and upper bounds must be on initial sequences of + * index keys. All but possibly the last bound must be non-strict. + * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not. * - * The bounds must specify a single range i.e. they are on an initial - * sequence of index keys and the condition is equality for all but - * (at most) the last key which has a lower and/or upper bound. + * The scan may currently return tuples for which the bounds are not + * satisfied. For example, "a <= 2 and b <= 3" scans the index up to + * (a=2, b=3) but also returns any (a=1, b=4). * * NULL is treated like a normal value which is less than any not-NULL - * value and equal to another NULL value. To search for NULL use + * value and equal to another NULL value. To compare against NULL use * setBound with null pointer (0). * - * An index stores also all-NULL keys (this may become optional). - * Doing index scan with empty bound set returns all table tuples. + * An index stores also all-NULL keys. Doing index scan with empty + * bound set returns all table tuples. * * @param attrName Attribute name, alternatively: * @param anAttrId Index column id (starting from 0) @@ -117,14 +109,19 @@ public: */ int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len = 0); - /** @} *********************************************************************/ + /** + * Reset bounds and put operation in list that will be + * sent on next execute + */ + int reset_bounds(); + bool getSorted() const { return m_ordered; } private: NdbIndexScanOperation(Ndb* aNdb); virtual ~NdbIndexScanOperation(); int setBound(const NdbColumnImpl*, int type, const void* aValue, Uint32 len); - int saveBoundATTRINFO(); + int insertBOUNDS(Uint32 * data, Uint32 sz); virtual int equal_impl(const NdbColumnImpl*, const char*, Uint32); virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*); diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp index a8bd8b9bfea..8e0294e41e6 100644 --- a/ndb/include/ndbapi/NdbOperation.hpp +++ b/ndb/include/ndbapi/NdbOperation.hpp @@ -717,6 +717,8 @@ public: NotDefined ///< Internal for debugging }; + LockMode getLockMode() const { return theLockMode; } + protected: /****************************************************************************** * These are the methods used to create and delete the NdbOperation objects. @@ -749,7 +751,6 @@ protected: FinalGetValue, SubroutineExec, SubroutineEnd, - SetBound, WaitResponse, WaitCommitResponse, Finished, @@ -786,11 +787,6 @@ protected: int receiveTCKEYREF(NdbApiSignal*); - - int receiveTRANSID_AI(const Uint32* aDataPtr, Uint32 aDataLength); - int receiveREAD_CONF(const Uint32* aDataPtr, Uint32 aDataLength); - - int checkMagicNumber(bool b = true); // Verify correct object int checkState_TransId(NdbApiSignal* aSignal); @@ -814,8 +810,6 @@ protected: int branch_col_null(Uint32 type, Uint32 col, Uint32 Label); // Handle ATTRINFO signals - int receiveREAD_AI(Uint32* aDataPtr, Uint32 aLength); - int insertATTRINFO(Uint32 aData); int insertATTRINFOloop(const Uint32* aDataPtr, Uint32 aLength); @@ -894,7 +888,7 @@ protected: // currently defined OperationType theOperationType; // Read Request, Update Req...... - Uint8 theLockMode; // Can be set to WRITE if read operation + LockMode theLockMode; // Can be set to WRITE if read operation OperationStatus theStatus; // The status of the operation. Uint32 theMagicNumber; // Magic number to verify that object // is correct @@ -921,9 +915,6 @@ protected: Uint16 m_keyInfoGSN; Uint16 m_attrInfoGSN; - // saveBoundATTRINFO() moves ATTRINFO here when setBound() is ready - NdbApiSignal* theBoundATTRINFO; - Uint32 theTotalBoundAI_Len; // Blobs in this operation NdbBlob* theBlobList; diff --git a/ndb/include/ndbapi/NdbReceiver.hpp b/ndb/include/ndbapi/NdbReceiver.hpp index b7f73bb618d..b95313db274 100644 --- a/ndb/include/ndbapi/NdbReceiver.hpp +++ b/ndb/include/ndbapi/NdbReceiver.hpp @@ -19,8 +19,11 @@ #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL // Not part of public interface #include <ndb_types.h> +#include <ndb_global.h> class Ndb; +class NdbConnection; + class NdbReceiver { friend class Ndb; @@ -59,6 +62,7 @@ public: inline void next(NdbReceiver* next) { m_next = next;} inline NdbReceiver* next() { return m_next; } + void setErrorCode(int); private: Uint32 theMagicNumber; Ndb* m_ndb; @@ -127,7 +131,8 @@ int NdbReceiver::execTCOPCONF(Uint32 len){ Uint32 tmp = m_received_result_length; m_expected_result_length = len; - return (tmp == len ? 1 : 0); + assert(!(tmp && !len)); + return ((bool)len ^ (bool)tmp ? 0 : 1); } inline diff --git a/ndb/include/ndbapi/NdbResultSet.hpp b/ndb/include/ndbapi/NdbResultSet.hpp index 483e08179c0..478daf8aad2 100644 --- a/ndb/include/ndbapi/NdbResultSet.hpp +++ b/ndb/include/ndbapi/NdbResultSet.hpp @@ -138,7 +138,11 @@ public: */ int deleteTuple(); int deleteTuple(NdbConnection* takeOverTransaction); - + + /** + * Get underlying operation + */ + NdbOperation* getOperation(); private: NdbResultSet(NdbScanOperation*); @@ -149,4 +153,10 @@ private: NdbScanOperation* m_operation; }; +inline +NdbOperation* +NdbResultSet::getOperation(){ + return m_operation; +} + #endif diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp index e8a4408469c..2e4d173ac75 100644 --- a/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/ndb/include/ndbapi/NdbScanOperation.hpp @@ -32,6 +32,7 @@ #include <NdbOperation.hpp> class NdbBlob; +class NdbResultSet; /** * @class NdbScanOperation @@ -87,12 +88,13 @@ protected: CursorType m_cursor_type; NdbScanOperation(Ndb* aNdb); - ~NdbScanOperation(); + virtual ~NdbScanOperation(); int nextResult(bool fetchAllowed = true); virtual void release(); void closeScan(); + int close_impl(class TransporterFacade*); // Overloaded methods from NdbCursorOperation int executeCursor(int ProcessorId); @@ -119,6 +121,7 @@ protected: int prepareSendScan(Uint32 TC_ConnectPtr, Uint64 TransactionId); int fix_receivers(Uint32 parallel); + void reset_receivers(Uint32 parallel, Uint32 ordered); Uint32* m_array; // containing all arrays below Uint32 m_allocated_receivers; NdbReceiver** m_receivers; // All receivers diff --git a/ndb/include/portlib/NdbCondition.h b/ndb/include/portlib/NdbCondition.h index fb1f2fcd69e..3d959a0db41 100644 --- a/ndb/include/portlib/NdbCondition.h +++ b/ndb/include/portlib/NdbCondition.h @@ -26,21 +26,21 @@ extern "C" { struct NdbCondition; -/* -// Create a condition -// -// * returnvalue: pointer to the condition structure -*/ +/** + * Create a condition + * + * returnvalue: pointer to the condition structure + */ struct NdbCondition* NdbCondition_Create(void); -/* -// Wait for a condition, allows a thread to wait for -// a condition and atomically releases the associated mutex. -// -// * p_cond: pointer to the condition structure -// * p_mutex: pointer to the mutex structure -// * returnvalue: 0 = succeeded, 1 = failed -*/ +/** + * Wait for a condition, allows a thread to wait for + * a condition and atomically releases the associated mutex. + * + * p_cond: pointer to the condition structure + * p_mutex: pointer to the mutex structure + * returnvalue: 0 = succeeded, 1 = failed + */ int NdbCondition_Wait(struct NdbCondition* p_cond, NdbMutex* p_mutex); @@ -60,29 +60,29 @@ NdbCondition_WaitTimeout(struct NdbCondition* p_cond, int msec); -/* -// Signal a condition -// -// * p_cond: pointer to the condition structure -// * returnvalue: 0 = succeeded, 1 = failed -*/ +/** + * Signal a condition + * + * p_cond: pointer to the condition structure + * returnvalue: 0 = succeeded, 1 = failed + */ int NdbCondition_Signal(struct NdbCondition* p_cond); -/* -// Broadcast a condition -// -// * p_cond: pointer to the condition structure -// * returnvalue: 0 = succeeded, 1 = failed -*/ +/** + * Broadcast a condition + * + * p_cond: pointer to the condition structure + * returnvalue: 0 = succeeded, 1 = failed + */ int NdbCondition_Broadcast(struct NdbCondition* p_cond); -/* -// Destroy a condition -// -// * p_cond: pointer to the condition structure -// * returnvalue: 0 = succeeded, 1 = failed -*/ +/** + * Destroy a condition + * + * p_cond: pointer to the condition structure + * returnvalue: 0 = succeeded, 1 = failed + */ int NdbCondition_Destroy(struct NdbCondition* p_cond); #ifdef __cplusplus diff --git a/ndb/include/portlib/PortDefs.h b/ndb/include/portlib/PortDefs.h index 5e24e08ec61..b61bb627e65 100644 --- a/ndb/include/portlib/PortDefs.h +++ b/ndb/include/portlib/PortDefs.h @@ -28,35 +28,35 @@ struct tms { - time_t tms_utime; // user time - time_t tms_stime; // system time - time_t tms_cutime; // user time of children - time_t tms_cstime; // system time of children + time_t tms_utime; /* user time */ + time_t tms_stime; /* system time */ + time_t tms_cutime; /* user time of children */ + time_t tms_cstime; /* system time of children */ }; struct timespec { - long tv_sec; // Seconds - long tv_nsec; // Nanoseconds + long tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ }; #define strcasecmp(a,b) _strcmpi(a,b) - // Exports a WIN32 getopt function +/* Exports a WIN32 getopt function */ extern int optind; extern char *optarg; int getopt(int, char **, char *opts); -#endif // NDB_WIN32 +#endif /* NDB_WIN32 */ #ifdef NDB_ALPHA -#ifdef NDB_GCC // only for NDB_ALPHA +#ifdef NDB_GCC /* only for NDB_ALPHA */ extern int gnuShouldNotUseRPCC(); #define RPCC() gnuShouldNotUseRPCC(); #else #ifdef NDB_WIN32 #ifdef __cplusplus extern "C" { -#endif //__cplusplus +#endif /* __cplusplus */ u_int64 __asm(char *, ...); double __dasm(char *, ...); float __fasm(char *, ...); @@ -65,32 +65,32 @@ extern "C" { int __ADD_ATOMIC_LONG2(void *, int); #ifdef __cplusplus }; -#endif //__cplusplus +#endif /* __cplusplus */ #pragma intrinsic (__asm, __dasm, __fasm) #pragma intrinsic(_ReleaseSpinLock, _AcquireSpinLock) #pragma intrinsic(__ADD_ATOMIC_LONG2) -#endif // NDB_WIN32 +#endif /* NDB_WIN32 */ #define RPCC() ((int)__asm(" rpcc v0;")) #define MB() __asm(" mb;"); #define WMB() __asm(" wmb;"); #ifdef USE_INITIALSP #define IS_IP() (__asm(" mov sp,v0;") < IPinitialSP) -#else // USE_INITIALSP +#else /* USE_INITIALSP */ #define IS_IP() (((__asm(" rpcc v0;") >> 32) & 0x7) == IP_CPU) #endif -#endif //NDB_GCC -#else // NDB_ALPHA +#endif /* NDB_GCC */ +#else /* NDB_ALPHA */ #if defined NDB_SPARC -#define MB() asm ("membar 0x0;"); // LoadLoad -#define WMB() asm ("membar 0x3;"); // StoreStore -#else // NDB_SPARC +#define MB() asm ("membar 0x0;"); /* LoadLoad */ +#define WMB() asm ("membar 0x3;"); /* StoreStore */ +#else /* NDB_SPARC */ #define MB() #define WMB() -#endif // NDB_SPARC +#endif /* NDB_SPARC */ #define IS_IP() (1==1) extern int shouldNotUseRPCC(); #define RPCC() shouldNotUseRPCC(); -#endif // NDB_ALPHA +#endif /* NDB_ALPHA */ #endif diff --git a/ndb/include/portlib/prefetch.h b/ndb/include/portlib/prefetch.h index d663dd4c40d..729c80bd93e 100644 --- a/ndb/include/portlib/prefetch.h +++ b/ndb/include/portlib/prefetch.h @@ -42,7 +42,7 @@ inline void prefetch(void* p) { #ifdef NDB_ALPHA __asm(" ldl r31,0(a0);", p); -#endif // NDB_ALPHA +#endif /* NDB_ALPHA */ #ifdef NDB_FORTE6 sparc_prefetch_read_once(p); #else @@ -54,7 +54,7 @@ inline void writehint(void* p) { #ifdef NDB_ALPHA __asm(" wh64 (a0);", p); -#endif // NDB_ALPHA +#endif /* NDB_ALPHA */ #ifdef NDB_FORTE6 sparc_prefetch_write_once(p); #else diff --git a/ndb/include/util/BaseString.hpp b/ndb/include/util/BaseString.hpp index a1bb91ea9c5..066a24f294e 100644 --- a/ndb/include/util/BaseString.hpp +++ b/ndb/include/util/BaseString.hpp @@ -177,6 +177,12 @@ public: * Trim string from <i>delim</i> */ static char* trim(char * src, const char * delim); + + /** + * snprintf on some platforms need special treatment + */ + static int snprintf(char *str, size_t size, const char *format, ...); + static int vsnprintf(char *str, size_t size, const char *format, va_list ap); private: char* m_chr; unsigned m_len; diff --git a/ndb/include/util/basestring_vsnprintf.h b/ndb/include/util/basestring_vsnprintf.h new file mode 100644 index 00000000000..7c804f22841 --- /dev/null +++ b/ndb/include/util/basestring_vsnprintf.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 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 */ + +#ifndef BASESTRING_VSNPRINTF_H +#define BASESTRING_VSNPRINTF_H +#include <stdarg.h> +#if defined(__cplusplus) +extern "C" +{ +#endif +int basestring_snprintf(char*, size_t, const char*, ...); +int basestring_vsnprintf(char*,size_t, const char*,va_list); +#if defined(__cplusplus) +} +#endif +#endif diff --git a/ndb/src/common/debugger/DebuggerNames.cpp b/ndb/src/common/debugger/DebuggerNames.cpp index b2a79e2385b..8571b8ece86 100644 --- a/ndb/src/common/debugger/DebuggerNames.cpp +++ b/ndb/src/common/debugger/DebuggerNames.cpp @@ -15,6 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <ndb_global.h> +#include <BaseString.hpp> #include "DebuggerNames.hpp" @@ -53,14 +54,13 @@ initSignalNames(const char * dst[], const GsnName src[], unsigned short len){ static int initSignalPrinters(SignalDataPrintFunction dst[], - const NameFunctionPair src[], - unsigned short len){ + const NameFunctionPair src[]){ unsigned i; for(i = 0; i<=MAX_GSN; i++) dst[i] = 0; - for(i = 0; i<len; i++){ - unsigned short gsn = src[i].gsn; + unsigned short gsn; + for(i = 0; (gsn = src[i].gsn) > 0; i++){ SignalDataPrintFunction fun = src[i].function; if(dst[gsn] != 0 && fun != 0){ @@ -107,8 +107,7 @@ xxx_DUMMY_SIGNAL_NAMES_xxx = initSignalNames(localSignalNames, NO_OF_SIGNAL_NAMES); static const int xxx_DUMMY_PRINT_FUNCTIONS_xxx = initSignalPrinters(localPrintFunctions, - SignalDataPrintFunctions, - NO_OF_PRINT_FUNCTIONS); + SignalDataPrintFunctions); static const int xxx_DUMMY_BLOCK_NAMES_xxx = initBlockNames(localBlockNames, @@ -133,7 +132,7 @@ getBlockName(unsigned short blockNo, const char * ret){ return localBlockNames[blockNo-MIN_BLOCK_NO]; if (ret == 0) { static char buf[20]; - snprintf(buf, sizeof(buf), "BLOCK#%d", (int)blockNo); + BaseString::snprintf(buf, sizeof(buf), "BLOCK#%d", (int)blockNo); return buf; } return ret; diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp index 03445622e6a..8a09be9a0a7 100644 --- a/ndb/src/common/debugger/EventLogger.cpp +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -127,7 +127,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // TODO: Change the switch implementation... char theNodeId[32]; if (nodeId != 0){ - ::snprintf(theNodeId, 32, "Node %u: ", nodeId); + BaseString::snprintf(theNodeId, 32, "Node %u: ", nodeId); } else { theNodeId[0] = 0; } @@ -135,13 +135,13 @@ EventLogger::getText(char * m_text, size_t m_text_len, EventReport::EventType eventType = (EventReport::EventType)type; switch (eventType){ case EventReport::Connected: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode %u Connected", theNodeId, theData[1]); break; case EventReport::ConnectedApiVersion: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode %u: API version %d.%d.%d", theNodeId, theData[1], @@ -150,7 +150,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, getBuild(theData[2])); break; case EventReport::Disconnected: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode %u Disconnected", theNodeId, theData[1]); @@ -159,7 +159,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT communication to node closed. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sCommunication to Node %u closed", theNodeId, theData[1]); @@ -168,7 +168,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT communication to node opened. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sCommunication to Node %u opened", theNodeId, theData[1]); @@ -177,7 +177,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // Start of NDB has been initiated. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sStart initiated (version %d.%d.%d)", theNodeId , getMajor(theData[1]), @@ -185,13 +185,13 @@ EventLogger::getText(char * m_text, size_t m_text_len, getBuild(theData[1])); break; case EventReport::NDBStopStarted: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%s%s shutdown initiated", theNodeId, (theData[1] == 1 ? "Cluster" : "Node")); break; case EventReport::NDBStopAborted: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode shutdown aborted", theNodeId); break; @@ -199,7 +199,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // Start of NDB has been completed. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sStarted (version %d.%d.%d)", theNodeId , getMajor(theData[1]), @@ -211,7 +211,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // STTORRY recevied after restart finished. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sSTTORRY received after restart finished", theNodeId); break; @@ -237,7 +237,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, type = ""; break; default:{ - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sStart phase %u completed (unknown = %d)", theNodeId, theData[1], @@ -245,7 +245,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, return m_text; } } - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sStart phase %u completed %s", theNodeId, theData[1], @@ -254,7 +254,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, break; } case EventReport::CM_REGCONF: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sCM_REGCONF president = %u, own Node = %u, our dynamic id = %u" , theNodeId, @@ -286,7 +286,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, break; }//switch - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sCM_REGREF from Node %u to our Node %u. Cause = %s", theNodeId, theData[2], @@ -298,7 +298,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Node Restart copied a fragment. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sWe are Node %u with dynamic ID %u, our left neighbour " "is Node %u, our right is Node %u", @@ -315,13 +315,13 @@ EventLogger::getText(char * m_text, size_t m_text_len, if (theData[1] == 0) { if (theData[3] != 0) { - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode %u completed failure of Node %u", theNodeId, theData[3], theData[2]); } else { - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sAll nodes completed failure of Node %u", theNodeId, theData[2]); @@ -338,7 +338,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, line = "DBLQH"; } - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNode failure of %u %s completed", theNodeId, theData[2], @@ -346,7 +346,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, } break; case EventReport::NODE_FAILREP: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode %u has failed. The Node state at failure " "was %u", @@ -366,41 +366,41 @@ EventLogger::getText(char * m_text, size_t m_text_len, const unsigned state = sd->code >> 16; switch (code) { case ArbitCode::ThreadStart: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sPresident restarts arbitration thread [state=%u]", theNodeId, state); break; case ArbitCode::PrepPart2: sd->ticket.getText(ticketText, sizeof(ticketText)); - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sPrepare arbitrator node %u [ticket=%s]", theNodeId, sd->node, ticketText); break; case ArbitCode::PrepAtrun: sd->ticket.getText(ticketText, sizeof(ticketText)); - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sReceive arbitrator node %u [ticket=%s]", theNodeId, sd->node, ticketText); break; case ArbitCode::ApiStart: sd->ticket.getText(ticketText, sizeof(ticketText)); - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sStarted arbitrator node %u [ticket=%s]", theNodeId, sd->node, ticketText); break; case ArbitCode::ApiFail: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sLost arbitrator node %u - process failure [state=%u]", theNodeId, sd->node, state); break; case ArbitCode::ApiExit: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sLost arbitrator node %u - process exit [state=%u]", theNodeId, sd->node, state); break; default: ArbitCode::getErrText(code, errText, sizeof(errText)); - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sLost arbitrator node %u - %s [state=%u]", theNodeId, sd->node, errText, state); break; @@ -417,48 +417,48 @@ EventLogger::getText(char * m_text, size_t m_text_len, const unsigned state = sd->code >> 16; switch (code) { case ArbitCode::LoseNodes: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration check lost - less than 1/2 nodes left", theNodeId); break; case ArbitCode::WinGroups: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration check won - node group majority", theNodeId); break; case ArbitCode::LoseGroups: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration check lost - missing node group", theNodeId); break; case ArbitCode::Partitioning: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNetwork partitioning - arbitration required", theNodeId); break; case ArbitCode::WinChoose: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration won - positive reply from node %u", theNodeId, sd->node); break; case ArbitCode::LoseChoose: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration lost - negative reply from node %u", theNodeId, sd->node); break; case ArbitCode::LoseNorun: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNetwork partitioning - no arbitrator available", theNodeId); break; case ArbitCode::LoseNocfg: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sNetwork partitioning - no arbitrator configured", theNodeId); break; default: ArbitCode::getErrText(code, errText, sizeof(errText)); - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sArbitration failure - %s [state=%u]", theNodeId, errText, state); break; @@ -470,7 +470,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // This event reports that a global checkpoint has been started and this // node is the master of this global checkpoint. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sGlobal checkpoint %u started", theNodeId, @@ -481,7 +481,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // This event reports that a global checkpoint has been completed on this // node and the node is the master of this global checkpoint. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sGlobal checkpoint %u completed", theNodeId, theData[1]); @@ -491,7 +491,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // This event reports that a local checkpoint has been started and this // node is the master of this local checkpoint. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLocal checkpoint %u started. " "Keep GCI = %u oldest restorable GCI = %u", @@ -505,7 +505,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // This event reports that a local checkpoint has been completed on this // node and the node is the master of this local checkpoint. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLocal checkpoint %u completed", theNodeId, @@ -515,14 +515,14 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // This event reports that a table has been created. //----------------------------------------------------------------------- - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sTable with ID = %u created", theNodeId, theData[1]); break; case EventReport::LCPStoppedInCalcKeepGci: if (theData[1] == 0) - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sLocal Checkpoint stopped in CALCULATED_KEEP_GCI", theNodeId); break; @@ -530,7 +530,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Node Restart completed copy of dictionary information. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode restart completed copy of dictionary information", theNodeId); @@ -539,7 +539,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Node Restart completed copy of distribution information. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode restart completed copy of distribution information", theNodeId); @@ -548,7 +548,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Node Restart is starting to copy the fragments. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode restart starting to copy the fragments " "to Node %u", @@ -559,7 +559,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Node Restart copied a fragment. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sTable ID = %u, fragment ID = %u have been copied " "to Node %u", @@ -569,7 +569,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[1]); break; case EventReport::NR_CopyFragsCompleted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode restart completed copying the fragments " "to Node %u", @@ -577,7 +577,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[1]); break; case EventReport::LCPFragmentCompleted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sTable ID = %u, fragment ID = %u has completed LCP " "on Node %u", @@ -590,7 +590,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, // ------------------------------------------------------------------- // Report information about transaction activity once per 10 seconds. // ------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sTrans. Count = %u, Commit Count = %u, " "Read Count = %u, Simple Read Count = %u,\n" @@ -610,7 +610,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[10]); break; case EventReport::OperationReportCounters: - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%sOperations=%u", theNodeId, theData[1]); @@ -619,7 +619,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Undo Logging blocked due to buffer near to overflow. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sACC Blocked %u and TUP Blocked %u times last second", theNodeId, @@ -628,7 +628,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, break; case EventReport::TransporterError: case EventReport::TransporterWarning: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sTransporter to node %d reported error 0x%x", theNodeId, @@ -639,7 +639,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Undo Logging blocked due to buffer near to overflow. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode %d missed heartbeat %d", theNodeId, @@ -650,21 +650,21 @@ EventLogger::getText(char * m_text, size_t m_text_len, //----------------------------------------------------------------------- // REPORT Undo Logging blocked due to buffer near to overflow. //----------------------------------------------------------------------- - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode %d declared dead due to missed heartbeat", theNodeId, theData[1]); break; case EventReport::JobStatistic: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sMean loop Counter in doJob last 8192 times = %u", theNodeId, theData[1]); break; case EventReport::SendBytesStatistic: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sMean send size to Node = %d last 4096 sends = %u bytes", theNodeId, @@ -672,7 +672,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[2]); break; case EventReport::ReceiveBytesStatistic: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sMean receive size to Node = %d last 4096 sends = %u bytes", theNodeId, @@ -680,14 +680,14 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[2]); break; case EventReport::SentHeartbeat: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode Sent Heartbeat to node = %d", theNodeId, theData[1]); break; case EventReport::CreateLogBytes: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLog part %u, log file %u, MB %u", theNodeId, @@ -696,7 +696,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[3]); break; case EventReport::StartLog: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLog part %u, start MB %u, stop MB %u, last GCI, log exec %u", theNodeId, @@ -706,7 +706,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[4]); break; case EventReport::StartREDOLog: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sNode: %d StartLog: [GCI Keep: %d LastCompleted: %d NewestRestorable: %d]", theNodeId, @@ -723,7 +723,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, line = "DBACC"; } - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%s UNDO %s %d [%d %d %d %d %d %d %d %d %d]", theNodeId, @@ -741,36 +741,36 @@ EventLogger::getText(char * m_text, size_t m_text_len, } break; case EventReport::InfoEvent: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%s%s", theNodeId, (char *)&theData[1]); break; case EventReport::WarningEvent: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%s%s", theNodeId, (char *)&theData[1]); break; case EventReport::GCP_TakeoverStarted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sGCP Take over started", theNodeId); break; case EventReport::GCP_TakeoverCompleted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sGCP Take over completed", theNodeId); break; case EventReport::LCP_TakeoverStarted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLCP Take over started", theNodeId); break; case EventReport::LCP_TakeoverCompleted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sLCP Take over completed (state = %d)", theNodeId, theData[1]); @@ -783,7 +783,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int block = theData[5]; const int percent = (used*100)/total; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "%s%s usage %s %d%s(%d %dK pages of total %d)", theNodeId, (block==DBACC ? "Index" : (block == DBTUP ?"Data":"<unknown>")), @@ -802,7 +802,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Created subscription id" " (subId=%d,SubKey=%d)" " Return code: %d.", @@ -816,7 +816,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Created subscription id" " (subId=%d,SubKey=%d)" " Return code: %d.", @@ -831,7 +831,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subKey = theData[3]; const int err = theData[4]; const int nodegrp = theData[5]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Created subscription using" " (subId=%d,SubKey=%d)" " in primary system. Primary system has %d nodegroup(s)." @@ -847,7 +847,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have created " "subscriptions" " using (subId=%d,SubKey=%d)." @@ -862,7 +862,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Logging started on meta data changes." " using (subId=%d,SubKey=%d)" " Return code: %d", @@ -876,7 +876,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have started " "logging meta data" " changes on the subscription subId=%d,SubKey=%d) " @@ -891,7 +891,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Logging started on table data changes " " using (subId=%d,SubKey=%d)" " Return code: %d", @@ -905,7 +905,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have started logging " "table data changes on the subscription " "subId=%d,SubKey=%d)." @@ -920,7 +920,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have started " " synchronization on meta data (META SCAN) using " "(subId=%d,SubKey=%d)." @@ -935,7 +935,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Synchronization started (META SCAN) on " " meta data using (subId=%d,SubKey=%d)" " Return code: %d", @@ -949,7 +949,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have started " "synchronization " " on table data (DATA SCAN) using (subId=%d,SubKey=%d)." @@ -965,7 +965,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subKey = theData[3]; const int err = theData[4]; const int gci = theData[5]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Synchronization started (DATA SCAN) on " "table data using (subId=%d,SubKey=%d). GCI = %d" " Return code: %d", @@ -980,7 +980,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: All participants have removed " "subscription (subId=%d,SubKey=%d). I have cleaned " "up resources I've used." @@ -995,7 +995,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Removed subscription " "(subId=%d,SubKey=%d)" " Return code: %d", @@ -1005,7 +1005,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, break; } default: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sUnknown GrepSubscriptonInfo event: %d", theNodeId, @@ -1024,7 +1024,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord:Error code: %d Error message: %s" " (subId=%d,SubKey=%d)", err, @@ -1038,7 +1038,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: FAILED to Created subscription using" " (subId=%d,SubKey=%d)in primary system." " Error code: %d Error Message: %s", @@ -1053,7 +1053,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Logging failed to start on meta " "data changes." " using (subId=%d,SubKey=%d)" @@ -1069,7 +1069,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Logging FAILED to start on table data " " changes using (subId=%d,SubKey=%d)" " Error code: %d Error Message: %s", @@ -1084,7 +1084,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Synchronization FAILED (META SCAN) on " " meta data using (subId=%d,SubKey=%d)" " Error code: %d Error Message: %s", @@ -1100,7 +1100,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subKey = theData[3]; const int err = theData[4]; const int gci = theData[5]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Synchronization FAILED (DATA SCAN) on " "table data using (subId=%d,SubKey=%d). GCI = %d" " Error code: %d Error Message: %s", @@ -1116,7 +1116,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::SSCoord: Failed to remove subscription " "(subId=%d,SubKey=%d). " " Error code: %d Error Message: %s", @@ -1133,7 +1133,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Error code: %d Error Message: %s" " (subId=%d,SubKey=%d)", err, @@ -1147,7 +1147,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: FAILED to Created subscription using" " (subId=%d,SubKey=%d)in primary system." " Error code: %d Error Message: %s", @@ -1162,7 +1162,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Logging failed to start on meta " "data changes." " using (subId=%d,SubKey=%d)" @@ -1178,7 +1178,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Logging FAILED to start on table data " " changes using (subId=%d,SubKey=%d)" " Error code: %d Error Message: %s", @@ -1193,7 +1193,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Synchronization FAILED (META SCAN) on " " meta data using (subId=%d,SubKey=%d)" " Error code: %d Error Message: %s", @@ -1209,7 +1209,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subKey = theData[3]; const int err = theData[4]; const int gci = theData[5]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Synchronization FAILED (DATA SCAN) on " "table data using (subId=%d,SubKey=%d). GCI = %d. " " Error code: %d Error Message: %s", @@ -1225,7 +1225,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, const int subId = theData[2]; const int subKey = theData[3]; const int err = theData[4]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Grep::PSCoord: Failed to remove subscription " "(subId=%d,SubKey=%d)." " Error code: %d Error Message: %s", @@ -1239,7 +1239,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, { const int err = theData[4]; const int nodeId = theData[5]; - ::snprintf(m_text, m_text_len, + BaseString::snprintf(m_text, m_text_len, "Rep: Node %d." " Error code: %d Error Message: %s", nodeId, @@ -1250,7 +1250,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, default: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sUnknown GrepSubscriptionAlert event: %d", theNodeId, @@ -1261,19 +1261,19 @@ EventLogger::getText(char * m_text, size_t m_text_len, } case EventReport::BackupStarted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sBackup %d started from node %d", theNodeId, theData[2], refToNode(theData[1])); break; case EventReport::BackupFailedToStart: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sBackup request from %d failed to start. Error: %d", theNodeId, refToNode(theData[1]), theData[2]); break; case EventReport::BackupCompleted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sBackup %d started from node %d completed\n" " StartGCP: %d StopGCP: %d\n" @@ -1284,7 +1284,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[5], theData[7]); break; case EventReport::BackupAborted: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sBackup %d started from %d has been aborted. Error: %d", theNodeId, @@ -1293,7 +1293,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, theData[3]); break; default: - ::snprintf(m_text, + BaseString::snprintf(m_text, m_text_len, "%sUnknown event: %d", theNodeId, @@ -1306,7 +1306,7 @@ EventLogger::getText(char * m_text, size_t m_text_len, EventLogger::EventLogger() : m_filterLevel(15) { setCategory("EventLogger"); - enable(Logger::Logger::LL_INFO, Logger::Logger::LL_ALERT); + enable(Logger::LL_INFO, Logger::LL_ALERT); } EventLogger::~EventLogger() @@ -1343,7 +1343,7 @@ EventLogger::log(int eventType, const Uint32* theData, NodeId nodeId, { Uint32 threshold = 0; Logger::LoggerLevel severity = Logger::LL_WARNING; - LogLevel::EventCategory cat; + LogLevel::EventCategory cat= LogLevel::llInvalid; for(unsigned i = 0; i<EventLoggerBase::matrixSize; i++){ if(EventLoggerBase::matrix[i].eventType == eventType){ @@ -1353,6 +1353,9 @@ EventLogger::log(int eventType, const Uint32* theData, NodeId nodeId, break; } } + + if (cat == LogLevel::llInvalid) + return; Uint32 set = ll?ll->getLogLevel(cat) : m_logLevel.getLogLevel(cat); if (threshold <= set){ diff --git a/ndb/src/common/debugger/signaldata/ContinueB.cpp b/ndb/src/common/debugger/signaldata/ContinueB.cpp index 1be6da86cb1..c295041bc01 100644 --- a/ndb/src/common/debugger/signaldata/ContinueB.cpp +++ b/ndb/src/common/debugger/signaldata/ContinueB.cpp @@ -24,9 +24,9 @@ bool printCONTINUEB(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiverBlockNo){ if(receiverBlockNo == DBDIH){ - return printCONTINUEB_DBDIH(output, theData, len); + return printCONTINUEB_DBDIH(output, theData, len, 0); } else if(receiverBlockNo == NDBFS) { - return printCONTINUEB_NDBFS(output, theData, len); + return printCONTINUEB_NDBFS(output, theData, len, 0); } return false; diff --git a/ndb/src/common/debugger/signaldata/CopyGCI.cpp b/ndb/src/common/debugger/signaldata/CopyGCI.cpp index 96186e82525..173b3f6708f 100644 --- a/ndb/src/common/debugger/signaldata/CopyGCI.cpp +++ b/ndb/src/common/debugger/signaldata/CopyGCI.cpp @@ -21,22 +21,22 @@ void print(char * buf, size_t buf_len, CopyGCIReq::CopyReason r){ switch(r){ case CopyGCIReq::IDLE: - snprintf(buf, buf_len, "IDLE"); + BaseString::snprintf(buf, buf_len, "IDLE"); break; case CopyGCIReq::LOCAL_CHECKPOINT: - snprintf(buf, buf_len, "LOCAL_CHECKPOINT"); + BaseString::snprintf(buf, buf_len, "LOCAL_CHECKPOINT"); break; case CopyGCIReq::RESTART: - snprintf(buf, buf_len, "RESTART"); + BaseString::snprintf(buf, buf_len, "RESTART"); break; case CopyGCIReq::GLOBAL_CHECKPOINT: - snprintf(buf, buf_len, "GLOBAL_CHECKPOINT"); + BaseString::snprintf(buf, buf_len, "GLOBAL_CHECKPOINT"); break; case CopyGCIReq::INITIAL_START_COMPLETED: - snprintf(buf, buf_len, "INITIAL_START_COMPLETED"); + BaseString::snprintf(buf, buf_len, "INITIAL_START_COMPLETED"); break; default: - snprintf(buf, buf_len, "<Unknown>"); + BaseString::snprintf(buf, buf_len, "<Unknown>"); } } diff --git a/ndb/src/common/debugger/signaldata/CreateTrig.cpp b/ndb/src/common/debugger/signaldata/CreateTrig.cpp index ddd45080cba..db5344cfbe7 100644 --- a/ndb/src/common/debugger/signaldata/CreateTrig.cpp +++ b/ndb/src/common/debugger/signaldata/CreateTrig.cpp @@ -28,51 +28,51 @@ bool printCREATE_TRIG_REQ(FILE * output, const Uint32 * theData, Uint32 len, Uin //sig->getTriggerName((char *) &triggerName); switch (sig->getTriggerType()) { case(TriggerType::SECONDARY_INDEX): - snprintf(triggerType, sizeof(triggerType), "SECONDARY_INDEX"); + BaseString::snprintf(triggerType, sizeof(triggerType), "SECONDARY_INDEX"); break; case(TriggerType::SUBSCRIPTION): - snprintf(triggerType, sizeof(triggerType), "SUBSCRIPTION"); + BaseString::snprintf(triggerType, sizeof(triggerType), "SUBSCRIPTION"); break; case(TriggerType::ORDERED_INDEX): - snprintf(triggerType, sizeof(triggerType), "ORDERED_INDEX"); + BaseString::snprintf(triggerType, sizeof(triggerType), "ORDERED_INDEX"); break; default: - snprintf(triggerType, sizeof(triggerType), "UNKNOWN [%d]", (int)sig->getTriggerType()); + BaseString::snprintf(triggerType, sizeof(triggerType), "UNKNOWN [%d]", (int)sig->getTriggerType()); break; } switch (sig->getTriggerActionTime()) { case (TriggerActionTime::TA_BEFORE): - snprintf(triggerActionTime, sizeof(triggerActionTime), "BEFORE"); + BaseString::snprintf(triggerActionTime, sizeof(triggerActionTime), "BEFORE"); break; case(TriggerActionTime::TA_AFTER): - snprintf(triggerActionTime, sizeof(triggerActionTime), "AFTER"); + BaseString::snprintf(triggerActionTime, sizeof(triggerActionTime), "AFTER"); break; case (TriggerActionTime::TA_DEFERRED): - snprintf(triggerActionTime, sizeof(triggerActionTime), "DEFERRED"); + BaseString::snprintf(triggerActionTime, sizeof(triggerActionTime), "DEFERRED"); break; case (TriggerActionTime::TA_DETACHED): - snprintf(triggerActionTime, sizeof(triggerActionTime), "DETACHED"); + BaseString::snprintf(triggerActionTime, sizeof(triggerActionTime), "DETACHED"); break; default: - snprintf(triggerActionTime, sizeof(triggerActionTime), + BaseString::snprintf(triggerActionTime, sizeof(triggerActionTime), "UNKNOWN [%d]", (int)sig->getTriggerActionTime()); break; } switch (sig->getTriggerEvent()) { case (TriggerEvent::TE_INSERT): - snprintf(triggerEvent, sizeof(triggerEvent), "INSERT"); + BaseString::snprintf(triggerEvent, sizeof(triggerEvent), "INSERT"); break; case(TriggerEvent::TE_DELETE): - snprintf(triggerEvent, sizeof(triggerEvent), "DELETE"); + BaseString::snprintf(triggerEvent, sizeof(triggerEvent), "DELETE"); break; case(TriggerEvent::TE_UPDATE): - snprintf(triggerEvent, sizeof(triggerEvent), "UPDATE"); + BaseString::snprintf(triggerEvent, sizeof(triggerEvent), "UPDATE"); break; case(TriggerEvent::TE_CUSTOM): - snprintf(triggerEvent, sizeof(triggerEvent), "CUSTOM"); + BaseString::snprintf(triggerEvent, sizeof(triggerEvent), "CUSTOM"); break; default: - snprintf(triggerEvent, sizeof(triggerEvent), "UNKNOWN [%d]", (int)sig->getTriggerEvent()); + BaseString::snprintf(triggerEvent, sizeof(triggerEvent), "UNKNOWN [%d]", (int)sig->getTriggerEvent()); break; } diff --git a/ndb/src/common/debugger/signaldata/DihContinueB.cpp b/ndb/src/common/debugger/signaldata/DihContinueB.cpp index 94453e76d72..9fece17315c 100644 --- a/ndb/src/common/debugger/signaldata/DihContinueB.cpp +++ b/ndb/src/common/debugger/signaldata/DihContinueB.cpp @@ -18,7 +18,10 @@ #include <signaldata/DihContinueB.hpp> bool -printCONTINUEB_DBDIH(FILE * output, const Uint32 * theData, Uint32 len){ +printCONTINUEB_DBDIH(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 not_used){ + + (void)not_used; switch (theData[0]) { case DihContinueB::ZPACK_TABLE_INTO_PAGES: diff --git a/ndb/src/common/debugger/signaldata/Makefile.am b/ndb/src/common/debugger/signaldata/Makefile.am index 0a5806e1e00..c855c5f8a18 100644 --- a/ndb/src/common/debugger/signaldata/Makefile.am +++ b/ndb/src/common/debugger/signaldata/Makefile.am @@ -23,7 +23,8 @@ libsignaldataprint_la_SOURCES = \ FailRep.cpp DisconnectRep.cpp SignalDroppedRep.cpp \ SumaImpl.cpp NdbSttor.cpp CreateFragmentation.cpp \ UtilLock.cpp TuxMaint.cpp AccLock.cpp \ - LqhTrans.cpp ReadNodesConf.cpp CntrStart.cpp + LqhTrans.cpp ReadNodesConf.cpp CntrStart.cpp \ + ScanFrag.cpp include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_ndbapi.mk.am diff --git a/ndb/src/common/debugger/signaldata/MasterLCP.cpp b/ndb/src/common/debugger/signaldata/MasterLCP.cpp index aa30404524f..078b92f6f2e 100644 --- a/ndb/src/common/debugger/signaldata/MasterLCP.cpp +++ b/ndb/src/common/debugger/signaldata/MasterLCP.cpp @@ -23,16 +23,16 @@ void print(char *buf, size_t buf_len, MasterLCPConf::State s){ switch(s){ case MasterLCPConf::LCP_STATUS_IDLE: - snprintf(buf, buf_len, "LCP_STATUS_IDLE"); + BaseString::snprintf(buf, buf_len, "LCP_STATUS_IDLE"); break; case MasterLCPConf::LCP_STATUS_ACTIVE: - snprintf(buf, buf_len, "LCP_STATUS_ACTIVE"); + BaseString::snprintf(buf, buf_len, "LCP_STATUS_ACTIVE"); break; case MasterLCPConf::LCP_TAB_COMPLETED: - snprintf(buf, buf_len, "LCP_TAB_COMPLETED"); + BaseString::snprintf(buf, buf_len, "LCP_TAB_COMPLETED"); break; case MasterLCPConf::LCP_TAB_SAVED: - snprintf(buf, buf_len, "LCP_TAB_SAVED"); + BaseString::snprintf(buf, buf_len, "LCP_TAB_SAVED"); break; } } diff --git a/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp b/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp index b3c7a61136e..9f55efae017 100644 --- a/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp +++ b/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp @@ -18,7 +18,10 @@ #include <signaldata/NdbfsContinueB.hpp> bool -printCONTINUEB_NDBFS(FILE * output, const Uint32 * theData, Uint32 len){ +printCONTINUEB_NDBFS(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 not_used){ + + (void)not_used; switch (theData[0]) { case NdbfsContinueB::ZSCAN_MEMORYCHANNEL_10MS_DELAY: diff --git a/ndb/src/common/debugger/signaldata/ScanFrag.cpp b/ndb/src/common/debugger/signaldata/ScanFrag.cpp new file mode 100644 index 00000000000..4d19a325637 --- /dev/null +++ b/ndb/src/common/debugger/signaldata/ScanFrag.cpp @@ -0,0 +1,42 @@ +/* Copyright (C) 2003 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 <BlockNumbers.h> +#include <signaldata/ScanTab.hpp> +#include <signaldata/ScanFrag.hpp> + +bool +printSCAN_FRAGREQ(FILE * output, const Uint32 * theData, + Uint32 len, Uint16 receiverBlockNo) { + const ScanFragReq * const sig = (ScanFragReq *)theData; + fprintf(output, " senderData: %x\n", sig->senderData); + fprintf(output, " resultRef: %x\n", sig->resultRef); + fprintf(output, " savePointId: %x\n", sig->savePointId); + fprintf(output, " requestInfo: %x\n", sig->requestInfo); + fprintf(output, " tableId: %x\n", sig->tableId); + fprintf(output, " fragmentNo: %x\n", sig->fragmentNoKeyLen & 0xFFFF); + fprintf(output, " keyLen: %x\n", sig->fragmentNoKeyLen >> 16); + fprintf(output, " schemaVersion: %x\n", sig->schemaVersion); + fprintf(output, " transId1: %x\n", sig->transId1); + fprintf(output, " transId2: %x\n", sig->transId2); + fprintf(output, " clientOpPtr: %x\n", sig->clientOpPtr); + fprintf(output, " batch_size_rows: %x\n", sig->batch_size_rows); + fprintf(output, " batch_size_bytes: %x\n", sig->batch_size_bytes); + return true; +} + diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp index 3f2109d9477..72a4d9f94b9 100644 --- a/ndb/src/common/debugger/signaldata/ScanTab.cpp +++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp @@ -30,15 +30,18 @@ printSCANTABREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiv fprintf(output, " apiConnectPtr: H\'%.8x", sig->apiConnectPtr); fprintf(output, " requestInfo: H\'%.8x:\n", requestInfo); - fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Holdlock: %u, RangeScan: %u\n", + fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u\n", sig->getParallelism(requestInfo), sig->getScanBatch(requestInfo), sig->getLockMode(requestInfo), sig->getHoldLockFlag(requestInfo), - sig->getRangeScanFlag(requestInfo)); + sig->getRangeScanFlag(requestInfo), + sig->getKeyinfoFlag(requestInfo)); - fprintf(output, " attrLen: %d, tableId: %d, tableSchemaVer: %d\n", - sig->attrLen, sig->tableId, sig->tableSchemaVersion); + Uint32 keyLen = (sig->attrLenKeyLen >> 16); + Uint32 attrLen = (sig->attrLenKeyLen & 0xFFFF); + fprintf(output, " attrLen: %d, keyLen: %d tableId: %d, tableSchemaVer: %d\n", + attrLen, keyLen, sig->tableId, sig->tableSchemaVersion); fprintf(output, " transId(1, 2): (H\'%.8x, H\'%.8x) storedProcId: H\'%.8x\n", sig->transId1, sig->transId2, sig->storedProcId); diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp index 65351663789..3314f0bd097 100644 --- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp +++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp @@ -53,6 +53,7 @@ #include <signaldata/UtilPrepare.hpp> #include <signaldata/UtilExecute.hpp> #include <signaldata/ScanTab.hpp> +#include <signaldata/ScanFrag.hpp> #include <signaldata/LqhFrag.hpp> #include <signaldata/LqhTransConf.hpp> #include <signaldata/DropTab.hpp> @@ -75,12 +76,11 @@ #include <signaldata/TuxMaint.hpp> #include <signaldata/AccLock.hpp> -bool printCONTINUEB(FILE *, const Uint32 *, Uint32, Uint16); - /** * This is the register */ -const NameFunctionPair + +const NameFunctionPair SignalDataPrintFunctions[] = { { GSN_TCKEYREQ, printTCKEYREQ }, { GSN_TCKEYCONF, printTCKEYCONF }, @@ -250,10 +250,10 @@ SignalDataPrintFunctions[] = { ,{ GSN_TUX_MAINT_REQ, printTUX_MAINT_REQ } ,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ } ,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF } + ,{ GSN_SCAN_FRAGREQ, printSCAN_FRAGREQ } + ,{ 0, 0 } }; -const unsigned short NO_OF_PRINT_FUNCTIONS = sizeof(SignalDataPrintFunctions)/sizeof(NameFunctionPair); - template class Bitmask<1>; template class Bitmask<2>; template class Bitmask<4>; diff --git a/ndb/src/common/debugger/signaldata/SignalNames.cpp b/ndb/src/common/debugger/signaldata/SignalNames.cpp index 9d4d5bdf6f5..9228e305677 100644 --- a/ndb/src/common/debugger/signaldata/SignalNames.cpp +++ b/ndb/src/common/debugger/signaldata/SignalNames.cpp @@ -446,6 +446,8 @@ const GsnName SignalNames [] = { ,{ GSN_STOP_REQ, "STOP_REQ" } ,{ GSN_STOP_REF, "STOP_REF" } + ,{ GSN_API_VERSION_REQ, "API_VERSION_REQ" } + ,{ GSN_API_VERSION_CONF, "API_VERSION_CONF" } ,{ GSN_ABORT_ALL_REQ, "ABORT_ALL_REQ" } ,{ GSN_ABORT_ALL_REF, "ABORT_ALL_REF" } diff --git a/ndb/src/common/debugger/signaldata/TcKeyConf.cpp b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp index 727e097a464..652c2b8a557 100644 --- a/ndb/src/common/debugger/signaldata/TcKeyConf.cpp +++ b/ndb/src/common/debugger/signaldata/TcKeyConf.cpp @@ -22,38 +22,48 @@ printTCKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receive if (receiverBlockNo == API_PACKED) { - fprintf(output, "Signal data: "); - Uint32 i = 0; - while (i < len) - fprintf(output, "H\'%.8x ", theData[i++]); - fprintf(output,"\n"); + return false; + Uint32 Theader = * theData++; + Uint32 TpacketLen = (Theader & 0x1F) + 3; + Uint32 TrecBlockNo = Theader >> 16; + + do { + fprintf(output, "Block: %d %d %d\n", TrecBlockNo, len, TpacketLen); + printTCKEYCONF(output, theData, TpacketLen, TrecBlockNo); + assert(len >= (1 + TpacketLen)); + len -= (1 + TpacketLen); + theData += TpacketLen; + } while(len); + return true; } else { const TcKeyConf * const sig = (TcKeyConf *) theData; - fprintf(output, "Signal data: "); Uint32 i = 0; Uint32 confInfo = sig->confInfo; Uint32 noOfOp = TcKeyConf::getNoOfOperations(confInfo); if (noOfOp > 10) noOfOp = 10; - while (i < len) - fprintf(output, "H\'%.8x ", theData[i++]); - fprintf(output,"\n"); - fprintf(output, "apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", + fprintf(output, " apiConnectPtr: H'%.8x, gci: %u, transId:(H'%.8x, H'%.8x)\n", sig->apiConnectPtr, sig->gci, sig->transId1, sig->transId2); - fprintf(output, "noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", + fprintf(output, " noOfOperations: %u, commitFlag: %s, markerFlag: %s\n", noOfOp, (TcKeyConf::getCommitFlag(confInfo) == 0)?"false":"true", (TcKeyConf::getMarkerFlag(confInfo) == 0)?"false":"true"); fprintf(output, "Operations:\n"); for(i = 0; i < noOfOp; i++) { - fprintf(output, - "apiOperationPtr: H'%.8x, attrInfoLen: %u\n", - sig->operations[i].apiOperationPtr, - sig->operations[i].attrInfoLen); + if(sig->operations[i].attrInfoLen > TcKeyConf::SimpleReadBit) + fprintf(output, + " apiOperationPtr: H'%.8x, simplereadnode: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen & (~TcKeyConf::SimpleReadBit)); + else + fprintf(output, + " apiOperationPtr: H'%.8x, attrInfoLen: %u\n", + sig->operations[i].apiOperationPtr, + sig->operations[i].attrInfoLen); } } - + return true; } diff --git a/ndb/src/common/logger/FileLogHandler.cpp b/ndb/src/common/logger/FileLogHandler.cpp index 632db71db15..29172ff93ad 100644 --- a/ndb/src/common/logger/FileLogHandler.cpp +++ b/ndb/src/common/logger/FileLogHandler.cpp @@ -153,11 +153,11 @@ FileLogHandler::createNewFile() if (fileNo >= m_maxNoFiles) { fileNo = 1; - ::snprintf(newName, sizeof(newName), + BaseString::snprintf(newName, sizeof(newName), "%s.%d", m_pLogFile->getName(), fileNo); break; } - ::snprintf(newName, sizeof(newName), + BaseString::snprintf(newName, sizeof(newName), "%s.%d", m_pLogFile->getName(), fileNo++); } while (File_class::exists(newName)); diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index 83d479c82fd..4fab957fc50 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -45,7 +45,7 @@ LogHandler::getDefaultHeader(char* pStr, const char* pCategory, Logger::LoggerLevel level) const { char time[MAX_DATE_TIME_HEADER_LENGTH]; - ::snprintf(pStr, MAX_HEADER_LENGTH, "%s [%s] %s -- ", + BaseString::snprintf(pStr, MAX_HEADER_LENGTH, "%s [%s] %s -- ", getTimeAsString((char*)time), pCategory, Logger::LoggerLevelNames[level]); @@ -84,7 +84,7 @@ LogHandler::getTimeAsString(char* pStr) const tm_now = ::localtime(&now); //uses the "current" timezone #endif - ::snprintf(pStr, MAX_DATE_TIME_HEADER_LENGTH, + BaseString::snprintf(pStr, MAX_DATE_TIME_HEADER_LENGTH, m_pDateTimeFormat, tm_now->tm_year + 1900, tm_now->tm_mon + 1, //month is [0,11]. +1 -> [1,12] diff --git a/ndb/src/common/logger/Logger.cpp b/ndb/src/common/logger/Logger.cpp index c2fdecb642b..fed5c211149 100644 --- a/ndb/src/common/logger/Logger.cpp +++ b/ndb/src/common/logger/Logger.cpp @@ -340,7 +340,7 @@ Logger::log(LoggerLevel logLevel, const char* pMsg, va_list ap) const while ( (pHandler = m_pHandlerList->next()) != NULL) { char buf[1024]; - vsnprintf(buf, sizeof(buf), pMsg, ap); + BaseString::vsnprintf(buf, sizeof(buf), pMsg, ap); pHandler->append(m_pCategory, logLevel, buf); } } diff --git a/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp index 44ee11717b4..7de9ee46479 100644 --- a/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp +++ b/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { ndbout << "-- " << " Test " << i + 1 << " [" << testCases[i].name << "] --" << endl; - snprintf(str, 256, "%s %s %s %d", "Logging ", + BaseString::snprintf(str, 256, "%s %s %s %d", "Logging ", testCases[i].name, " message ", i); if (testCases[i].test(str)) { @@ -128,7 +128,7 @@ LogHandlerListUnitTest::testTraverseNext(const char* msg) { char* str = new char[3]; pHandlers[i] = new ConsoleLogHandler(); - ::snprintf(str, 3, "%d", i); + BaseString::snprintf(str, 3, "%d", i); pHandlers[i]->setDateTimeFormat(str); list.add(pHandlers[i]); } diff --git a/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp b/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp index 017dcb79c1f..990d2e0eada 100644 --- a/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp +++ b/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp @@ -86,7 +86,7 @@ NDB_COMMAND(loggertest, "loggertest", "loggertest -console | -file", { ndbout << "-- " << " Test " << i + 1 << " [" << testCases[i].name << "] --" << endl; - ::snprintf(str, 256, "%s %s %s %d", "Logging ", + BaseString::snprintf(str, 256, "%s %s %s %d", "Logging ", testCases[i].name, " message ", i); if (testCases[i].test(str)) { diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp index b4f2d0b9897..d8417ac146a 100644 --- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -186,7 +186,7 @@ ConfigRetriever::getConfig(const char * filename){ const int res = stat(filename, &sbuf); if(res != 0){ char buf[255]; - snprintf(buf, sizeof(buf), "Could not find file: \"%s\"", filename); + BaseString::snprintf(buf, sizeof(buf), "Could not find file: \"%s\"", filename); setError(CR_ERROR, buf); return 0; } @@ -211,7 +211,7 @@ ConfigRetriever::getConfig(const char * filename){ ConfigValuesFactory cvf; if(!cvf.unpack(buf2, bytes)){ char buf[255]; - snprintf(buf, sizeof(buf), "Error while unpacking"); + BaseString::snprintf(buf, sizeof(buf), "Error while unpacking"); setError(CR_ERROR, buf); delete []buf2; return 0; @@ -241,7 +241,7 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE); if(it == 0){ - snprintf(buf, 255, "Unable to create config iterator"); + BaseString::snprintf(buf, 255, "Unable to create config iterator"); setError(CR_ERROR, buf); return false; @@ -249,14 +249,14 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 NdbAutoPtr<ndb_mgm_configuration_iterator> ptr(it); if(ndb_mgm_find(it, CFG_NODE_ID, nodeid) != 0){ - snprintf(buf, 255, "Unable to find node with id: %d", nodeid); + BaseString::snprintf(buf, 255, "Unable to find node with id: %d", nodeid); setError(CR_ERROR, buf); return false; } const char * hostname; if(ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &hostname)){ - snprintf(buf, 255, "Unable to get hostname(%d) from config",CFG_NODE_HOST); + BaseString::snprintf(buf, 255, "Unable to get hostname(%d) from config",CFG_NODE_HOST); setError(CR_ERROR, buf); return false; } @@ -268,7 +268,7 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 if (hostname && hostname[0] != 0 && !SocketServer::tryBind(0,hostname)) { - snprintf(buf, 255, "Config hostname(%s) don't match a local interface," + BaseString::snprintf(buf, 255, "Config hostname(%s) don't match a local interface," " tried to bind, error = %d - %s", hostname, errno, strerror(errno)); setError(CR_ERROR, buf); @@ -277,14 +277,14 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 unsigned int _type; if(ndb_mgm_get_int_parameter(it, CFG_TYPE_OF_SECTION, &_type)){ - snprintf(buf, 255, "Unable to get type of node(%d) from config", + BaseString::snprintf(buf, 255, "Unable to get type of node(%d) from config", CFG_TYPE_OF_SECTION); setError(CR_ERROR, buf); return false; } if(_type != m_node_type){ - snprintf(buf, 255, "Supplied node type(%d) and config node type(%d) " + BaseString::snprintf(buf, 255, "Supplied node type(%d) and config node type(%d) " " don't match", m_node_type, _type); setError(CR_ERROR, buf); return false; diff --git a/ndb/src/common/mgmcommon/LocalConfig.cpp b/ndb/src/common/mgmcommon/LocalConfig.cpp index cc66f357236..3cd4341c6b7 100644 --- a/ndb/src/common/mgmcommon/LocalConfig.cpp +++ b/ndb/src/common/mgmcommon/LocalConfig.cpp @@ -40,7 +40,7 @@ LocalConfig::init(const char *connectString, //1. Check connectString if(connectString != 0 && connectString[0] != 0){ - if(readConnectString(connectString)){ + if(readConnectString(connectString, "connect string")){ return true; } return false; @@ -59,7 +59,7 @@ LocalConfig::init(const char *connectString, char buf[255]; if(NdbEnv_GetEnv("NDB_CONNECTSTRING", buf, sizeof(buf)) && strlen(buf) != 0){ - if(readConnectString(buf)){ + if(readConnectString(buf, "NDB_CONNECTSTRING")){ return true; } return false; @@ -90,8 +90,8 @@ LocalConfig::init(const char *connectString, //7. Check { char buf[256]; - snprintf(buf, sizeof(buf), "host=localhost:%s", NDB_BASE_PORT); - if(readConnectString(buf)) + BaseString::snprintf(buf, sizeof(buf), "host=localhost:%s", NDB_BASE_PORT); + if(readConnectString(buf, "default connect string")) return true; } @@ -109,8 +109,10 @@ void LocalConfig::setError(int lineNumber, const char * _msg) { } void LocalConfig::printError() const { - ndbout << "Local configuration error"<< endl - << "Line: "<< error_line << ", " << error_msg << endl << endl; + ndbout << "Configuration error" << endl; + if (error_line) + ndbout << "Line: "<< error_line << ", "; + ndbout << error_msg << endl << endl; } void LocalConfig::printUsage() const { @@ -140,7 +142,7 @@ const char *nodeIdTokens[] = { const char *hostNameTokens[] = { "host://%[^:]:%i", "host=%[^:]:%i", - "%[^:]:%i", + "%[^:^=^ ]:%i", "%s %i", 0 }; @@ -192,7 +194,7 @@ LocalConfig::parseFileName(const char * buf){ } bool -LocalConfig::parseString(const char * connectString, char *line){ +LocalConfig::parseString(const char * connectString, BaseString &err){ char * for_strtok; char * copy = strdup(connectString); NdbAutoPtr<char> tmp_aptr(copy); @@ -212,15 +214,12 @@ LocalConfig::parseString(const char * connectString, char *line){ if (found_other = parseFileName(tok)) continue; - if (line) - snprintf(line, 150, "Unexpected entry: \"%s\"", tok); + err.assfmt("Unexpected entry: \"%s\"", tok); return false; } if (!found_other) { - if (line) - snprintf(line, 150, "Missing host/file name extry in \"%s\"", - connectString); + err.appfmt("Missing host/file name extry in \"%s\"", connectString); return false; } @@ -235,7 +234,8 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) FILE * file = fopen(filename, "r"); if(file == 0){ - snprintf(line, 150, "Unable to open local config file: %s", filename); + BaseString::snprintf(line, sizeof(line), + "Unable to open local config file: %s", filename); setError(0, line); fopenError = true; return false; @@ -243,7 +243,7 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) BaseString theString; - while(fgets(line, 1024, file)){ + while(fgets(line, sizeof(line), file)){ BaseString tmp(line); tmp.trim(" \t\n\r"); if(tmp.length() > 0 && tmp.c_str()[0] != '#'){ @@ -251,7 +251,7 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) break; } } - while (fgets(line, 1024, file)) { + while (fgets(line, sizeof(line), file)) { BaseString tmp(line); tmp.trim(" \t\n\r"); if(tmp.length() > 0 && tmp.c_str()[0] != '#'){ @@ -260,11 +260,12 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) } } - bool return_value = parseString(theString.c_str(), line); + BaseString err; + bool return_value = parseString(theString.c_str(), err); if (!return_value) { BaseString tmp; - tmp.assfmt("Reading %s: %s", filename, line); + tmp.assfmt("Reading %s: %s", filename, err.c_str()); setError(0, tmp.c_str()); } @@ -273,12 +274,14 @@ bool LocalConfig::readFile(const char * filename, bool &fopenError) } bool -LocalConfig::readConnectString(const char * connectString){ - char line[150], line2[150]; - bool return_value = parseString(connectString, line); +LocalConfig::readConnectString(const char * connectString, + const char * info){ + BaseString err; + bool return_value = parseString(connectString, err); if (!return_value) { - snprintf(line2, 150, "Reading NDB_CONNECTSTRING \"%s\": %s", connectString, line); - setError(0,line2); + BaseString err2; + err2.assfmt("Reading %d \"%s\": %s", info, connectString, err.c_str()); + setError(0,err2.c_str()); } return return_value; } diff --git a/ndb/src/common/portlib/NdbDaemon.c b/ndb/src/common/portlib/NdbDaemon.c index d8d33595156..c73b5927ff4 100644 --- a/ndb/src/common/portlib/NdbDaemon.c +++ b/ndb/src/common/portlib/NdbDaemon.c @@ -28,6 +28,8 @@ NdbDaemon_Make(const char* lockfile, const char* logfile, unsigned flags) int lockfd = -1, logfd = -1, n; char buf[64]; + (void)flags; /* remove warning for unused parameter */ + /* Check that we have write access to lock file */ assert(lockfile != NULL); lockfd = open(lockfile, O_CREAT|O_RDWR, 0644); diff --git a/ndb/src/common/portlib/NdbMem.c b/ndb/src/common/portlib/NdbMem.c index c077d6650ce..f964f4d9937 100644 --- a/ndb/src/common/portlib/NdbMem.c +++ b/ndb/src/common/portlib/NdbMem.c @@ -42,6 +42,7 @@ void* NdbMem_Allocate(size_t size) void* NdbMem_AllocateAlign(size_t size, size_t alignment) { + (void)alignment; /* remove warning for unused parameter */ /* return (void*)memalign(alignment, size); TEMP fix diff --git a/ndb/src/common/portlib/NdbSleep.c b/ndb/src/common/portlib/NdbSleep.c index 8702a25d1b1..19ab526fda8 100644 --- a/ndb/src/common/portlib/NdbSleep.c +++ b/ndb/src/common/portlib/NdbSleep.c @@ -16,7 +16,7 @@ #include <ndb_global.h> -#include "NdbSleep.h" +#include <NdbSleep.h> int NdbSleep_MilliSleep(int milliseconds){ diff --git a/ndb/src/common/portlib/NdbThread.c b/ndb/src/common/portlib/NdbThread.c index 60687a9053e..69e39994a9c 100644 --- a/ndb/src/common/portlib/NdbThread.c +++ b/ndb/src/common/portlib/NdbThread.c @@ -42,6 +42,8 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, int result; pthread_attr_t thread_attr; + (void)thread_prio; /* remove warning for unused parameter */ + if (p_thread_func == NULL) return 0; @@ -49,8 +51,7 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func, if (tmpThread == NULL) return NULL; - snprintf(tmpThread->thread_name, sizeof(tmpThread->thread_name), - "%s", p_thread_name); + strnmov(tmpThread->thread_name,p_thread_name,sizeof(tmpThread->thread_name)); pthread_attr_init(&thread_attr); pthread_attr_setstacksize(&thread_attr, thread_stack_size); @@ -109,6 +110,7 @@ int NdbThread_SetConcurrencyLevel(int level) #ifdef USE_PTHREAD_EXTRAS return pthread_setconcurrency(level); #else + (void)level; /* remove warning for unused parameter */ return 0; #endif } diff --git a/ndb/src/common/portlib/memtest.c b/ndb/src/common/portlib/memtest.c index 059a4ec025e..673f23fa803 100644 --- a/ndb/src/common/portlib/memtest.c +++ b/ndb/src/common/portlib/memtest.c @@ -90,7 +90,7 @@ void malloctest(int loopcount, int memsize, int touch) { long long start=0; int total=0; int i=0, j=0; - int size=memsize*1024*1024; //bytes; + int size=memsize*1024*1024; /*bytes*/; float mean; char * ptr =0; @@ -126,7 +126,7 @@ void mmaptest(int loopcount, int memsize, int touch) { int total=0; int i=0, j=0; char * ptr; - int size=memsize*1024*1024; //bytes; + int size=memsize*1024*1024; /*bytes*/; float mean; printf("Staring mmaptest "); @@ -165,7 +165,7 @@ void unmaptest(loopcount, memsize) int total=0; int i=0, j=0; char * ptr; - int size=memsize*1024*1024; //bytes; + int size=memsize*1024*1024; /*bytes*/; float mean; printf("Staring munmap test (loopcount = 1 no matter what you prev. set)\n"); @@ -215,7 +215,7 @@ void freetest(int loopcount, int memsize) { long long start=0; int total=0; int i=0, j=0; - int size=memsize*1024*1024; //bytes; + int size=memsize*1024*1024; /*bytes*/; float mean; char * ptr =0; diff --git a/ndb/src/common/transporter/OSE_Receiver.cpp b/ndb/src/common/transporter/OSE_Receiver.cpp index b7d47b2f88c..63a33fc8f24 100644 --- a/ndb/src/common/transporter/OSE_Receiver.cpp +++ b/ndb/src/common/transporter/OSE_Receiver.cpp @@ -41,7 +41,7 @@ OSE_Receiver::OSE_Receiver(TransporterRegistry * tr, phantomCreated = false; localNodeId = _localNodeId; - snprintf(localHostName, sizeof(localHostName), + BaseString::snprintf(localHostName, sizeof(localHostName), "ndb_node%d", localNodeId); DEBUG("localNodeId = " << localNodeId << " -> localHostName = " diff --git a/ndb/src/common/transporter/OSE_Transporter.cpp b/ndb/src/common/transporter/OSE_Transporter.cpp index c9b0f777319..a52862a80e5 100644 --- a/ndb/src/common/transporter/OSE_Transporter.cpp +++ b/ndb/src/common/transporter/OSE_Transporter.cpp @@ -51,10 +51,10 @@ OSE_Transporter::OSE_Transporter(int _prioASignalSize, prioBSignalSize = _prioBSignalSize; if (strcmp(lHostName, rHostName) == 0){ - snprintf(remoteNodeName, sizeof(remoteNodeName), + BaseString::snprintf(remoteNodeName, sizeof(remoteNodeName), "ndb_node%d", remoteNodeId); } else { - snprintf(remoteNodeName, sizeof(remoteNodeName), + BaseString::snprintf(remoteNodeName, sizeof(remoteNodeName), "%s/ndb_node%d", rHostName, remoteNodeId); } diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp index 7cfdc224b34..524ecd653e0 100644 --- a/ndb/src/common/transporter/TCP_Transporter.cpp +++ b/ndb/src/common/transporter/TCP_Transporter.cpp @@ -362,7 +362,7 @@ TCP_Transporter::doReceive() { // Select-function must return the socket for read // before this method is called // It reads the external TCP/IP interface once - int size = receiveBuffer.sizeOfBuffer - receiveBuffer.sizeOfData; + Uint32 size = receiveBuffer.sizeOfBuffer - receiveBuffer.sizeOfData; if(size > 0){ const int nBytesRead = recv(theSocket, receiveBuffer.insertPtr, diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp index 7a469252c00..e68bc86718e 100644 --- a/ndb/src/common/transporter/Transporter.cpp +++ b/ndb/src/common/transporter/Transporter.cpp @@ -32,7 +32,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, NodeId rNodeId, int _byteorder, bool _compression, bool _checksum, bool _signalId) - : m_r_port(r_port), localNodeId(lNodeId), remoteNodeId(rNodeId), + : m_r_port(r_port), remoteNodeId(rNodeId), localNodeId(lNodeId), isServer(lNodeId < rNodeId), m_packer(_signalId, _checksum), m_transporter_registry(t_reg) diff --git a/ndb/src/common/transporter/perftest/perfTransporterTest.cpp b/ndb/src/common/transporter/perftest/perfTransporterTest.cpp index d33221c2835..71df9f12a4c 100644 --- a/ndb/src/common/transporter/perftest/perfTransporterTest.cpp +++ b/ndb/src/common/transporter/perftest/perfTransporterTest.cpp @@ -276,7 +276,7 @@ printReport(TestPhase & p){ char buf[255]; if(p.signalSize != 0){ - snprintf(buf, 255, + BaseString::snprintf(buf, 255, "%d\t%d\t%s\t%s\t%s\t%s\t%d\t%d", p.noOfSignals, 4*p.signalSize, @@ -287,7 +287,7 @@ printReport(TestPhase & p){ (int)(p.sendLenBytes / (p.sendCount == 0 ? 1 : p.sendCount)), (int)(p.recvLenBytes / (p.recvCount == 0 ? 1 : p.recvCount))); } else { - snprintf(buf, 255, + BaseString::snprintf(buf, 255, "%d\trand\t%s\t%s\t%s\t%s\t%d\t%d", p.noOfSignals, st, diff --git a/ndb/src/common/transporter/priotest/prioTransporterTest.cpp b/ndb/src/common/transporter/priotest/prioTransporterTest.cpp index 0fce6aaad39..6c5623a49a6 100644 --- a/ndb/src/common/transporter/priotest/prioTransporterTest.cpp +++ b/ndb/src/common/transporter/priotest/prioTransporterTest.cpp @@ -375,7 +375,7 @@ printReport(TestPhase & p){ char buf[255]; if(p.signalSize != 0){ - snprintf(buf, 255, + BaseString::snprintf(buf, 255, "%d\t%d\t%d\t%s\t%s\t%s\t%d\t%d\t%d\t%d", p.noOfSignals, p.signalSize, @@ -388,7 +388,7 @@ printReport(TestPhase & p){ (int)(p.totTimePrioA / p.loopCount), (int)(p.bytesSentBeforePrioA)); } else { - snprintf(buf, 255, + BaseString::snprintf(buf, 255, "%d\trand\t4*rand\t%s\t%s\t%s\t%d\t%d\t%d\t%d", p.noOfSignals, st, diff --git a/ndb/src/common/util/BaseString.cpp b/ndb/src/common/util/BaseString.cpp index 8b7df485f77..dbff44c377d 100644 --- a/ndb/src/common/util/BaseString.cpp +++ b/ndb/src/common/util/BaseString.cpp @@ -17,6 +17,7 @@ /* -*- c-basic-offset: 4; -*- */ #include <ndb_global.h> #include <BaseString.hpp> +#include <basestring_vsnprintf.h> BaseString::BaseString() { @@ -127,14 +128,14 @@ BaseString::assfmt(const char *fmt, ...) * when called as vsnprintf(NULL, 0, ...). */ va_start(ap, fmt); - l = vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1; va_end(ap); if(l > (int)m_len) { delete[] m_chr; m_chr = new char[l]; } va_start(ap, fmt); - vsnprintf(m_chr, l, fmt, ap); + basestring_vsnprintf(m_chr, l, fmt, ap); va_end(ap); m_len = strlen(m_chr); return *this; @@ -152,11 +153,11 @@ BaseString::appfmt(const char *fmt, ...) * when called as vsnprintf(NULL, 0, ...). */ va_start(ap, fmt); - l = vsnprintf(buf, sizeof(buf), fmt, ap) + 1; + l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1; va_end(ap); char *tmp = new char[l]; va_start(ap, fmt); - vsnprintf(tmp, l, fmt, ap); + basestring_vsnprintf(tmp, l, fmt, ap); va_end(ap); append(tmp); delete[] tmp; @@ -335,6 +336,22 @@ BaseString::trim(char * str, const char * delim){ return str; } +int +BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + return(basestring_vsnprintf(str, size, format, ap)); +} + +int +BaseString::snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + int ret= basestring_vsnprintf(str, size, format, ap); + va_end(ap); + return(ret); +} + #ifdef TEST_BASE_STRING diff --git a/ndb/src/common/util/ConfigValues.cpp b/ndb/src/common/util/ConfigValues.cpp index 8a14882550c..5c4b17c73ca 100644 --- a/ndb/src/common/util/ConfigValues.cpp +++ b/ndb/src/common/util/ConfigValues.cpp @@ -1,9 +1,6 @@ + +#include <ndb_global.h> #include <ConfigValues.hpp> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <new> #include <NdbOut.hpp> #include <NdbTCP.h> diff --git a/ndb/src/common/util/File.cpp b/ndb/src/common/util/File.cpp index 22d262a0d27..f3faa8c4f7f 100644 --- a/ndb/src/common/util/File.cpp +++ b/ndb/src/common/util/File.cpp @@ -83,7 +83,7 @@ File_class::File_class(const char* aFileName, const char* mode) : m_file(NULL), m_fileMode(mode) { - ::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); + BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); } bool @@ -99,7 +99,7 @@ File_class::open(const char* aFileName, const char* mode) /** * Only copy if it's not the same string */ - ::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); + BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName); } m_fileMode = mode; bool rc = true; diff --git a/ndb/src/common/util/Makefile.am b/ndb/src/common/util/Makefile.am index efb249dd330..0235adae7c9 100644 --- a/ndb/src/common/util/Makefile.am +++ b/ndb/src/common/util/Makefile.am @@ -9,7 +9,7 @@ libgeneral_la_SOURCES = \ NdbSqlUtil.cpp new.cpp \ uucode.c random.c getarg.c version.c \ strdup.c strlcat.c strlcpy.c \ - ConfigValues.cpp ndb_init.c + ConfigValues.cpp ndb_init.c basestring_vsnprintf.c include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_util.mk.am diff --git a/ndb/src/common/util/NdbErrHnd.cpp b/ndb/src/common/util/NdbErrHnd.cpp index f1c28a7bbdd..38a67f29853 100644 --- a/ndb/src/common/util/NdbErrHnd.cpp +++ b/ndb/src/common/util/NdbErrHnd.cpp @@ -346,53 +346,53 @@ extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, file_name = "ose_err.h"; } - snprintf (error_message.header1, + BaseString::snprintf(error_message.header1, BUFSIZE, "This is the OSE Example System Error handler\r\n"); - snprintf (error_message.err_hnd_file, + BaseString::snprintf(error_message.err_hnd_file, BUFSIZE, "located in: " __FILE__ "\r\n"); - snprintf (error_message.header2, + BaseString::snprintf(error_message.header2, BUFSIZE, "An Error has been reported:\r\n"); if (user_called == (OSBOOLEAN) 0 ) { - snprintf(error_message.user_called_line, + BaseString::snprintf(error_message.user_called_line, BUFSIZE, "user_called: 0x%x (Error detected by the kernel)\r\n", user_called); } else { - snprintf(error_message.user_called_line, + BaseString::snprintf(error_message.user_called_line, BUFSIZE, "user_called: 0x%x (Error detected by an application)\r\n", user_called); } - snprintf (error_message.error_code_line, + BaseString::snprintf(error_message.error_code_line, BUFSIZE, "error code: 0x%08x\r\n", error_code); - snprintf (error_message.subcode_line, + BaseString::snprintf(error_message.subcode_line, BUFSIZE, " subcode: %s (0x%08x)\r\n", subcode_mnemonic, ( subcode << 16)); - snprintf (error_message.product_line, + BaseString::snprintf(error_message.product_line, BUFSIZE, " product: %s\r\n", product_name); - snprintf (error_message.header_file_line, + BaseString::snprintf(error_message.header_file_line, BUFSIZE, " header file: %s\r\n", file_name); - snprintf (error_message.extra_line, + BaseString::snprintf(error_message.extra_line, BUFSIZE, "extra: 0x%08x\r\n", extra); @@ -401,22 +401,22 @@ extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, struct OS_pcb *pcb = get_pcb(current_process()); const char *process_name = &pcb->strings[pcb->name]; - snprintf(error_message.current_process_id_line, + BaseString::snprintf(error_message.current_process_id_line, BUFSIZE, "Current Process: 0x%08x\r\n", current_process()); - snprintf(error_message.current_process_name_line, + BaseString::snprintf(error_message.current_process_name_line, BUFSIZE, "Process Name: %s\r\n", process_name); - snprintf(error_message.file_line, + BaseString::snprintf(error_message.file_line, BUFSIZE, "File: %s\r\n", &pcb->strings[pcb->file]); - snprintf(error_message.line_line, + BaseString::snprintf(error_message.line_line, BUFSIZE, "Line: %d\r\n", pcb->line); @@ -452,7 +452,7 @@ extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, char *expr = ((char **)extra)[0]; char *file = ((char **)extra)[1]; unsigned line = ((unsigned *)extra)[2]; - snprintf(assert_line, BUFSIZE, "Assertion Failed: %s:%u: %s\r\n", file, line, expr); + BaseString::snprintf(assert_line, BUFSIZE, "Assertion Failed: %s:%u: %s\r\n", file, line, expr); ndbout << assert_line; } } @@ -467,13 +467,13 @@ extern "C" OSBOOLEAN ndb_err_hnd(bool user_called, const char *rcv_name = &rcv->strings[rcv->name]; struct OS_pcb *snd = get_pcb(snd_); const char *snd_name = &snd->strings[snd->name]; - snprintf(unknown_signal_line, BUFSIZE, + BaseString::snprintf(unknown_signal_line, BUFSIZE, "Unknown Signal Received\r\n"); - snprintf(unknown_signal_line, BUFSIZE, + BaseString::snprintf(unknown_signal_line, BUFSIZE, "Signal Number: 0x%08lx\r\n", signo); - snprintf(unknown_signal_line, BUFSIZE, + BaseString::snprintf(unknown_signal_line, BUFSIZE, "Sending Process: 0x%08lx (%s))\r\n", snd_, snd_name); - snprintf(unknown_signal_line, BUFSIZE, + BaseString::snprintf(unknown_signal_line, BUFSIZE, "Receiving Process: 0x%08lx (%s))\r\n", rcv_, rcv_name); free_buf((union SIGNAL **)&rcv); free_buf((union SIGNAL **)&snd); } diff --git a/ndb/src/common/util/NdbOut.cpp b/ndb/src/common/util/NdbOut.cpp index 6d76cf22402..fa74cb364f3 100644 --- a/ndb/src/common/util/NdbOut.cpp +++ b/ndb/src/common/util/NdbOut.cpp @@ -102,7 +102,7 @@ NdbOut::print(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); ndbout << buf; va_end(ap); } @@ -114,7 +114,7 @@ NdbOut::println(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); ndbout << buf << endl; va_end(ap); } @@ -127,7 +127,7 @@ ndbout_c(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); ndbout << buf << endl; va_end(ap); } diff --git a/ndb/src/common/util/OutputStream.cpp b/ndb/src/common/util/OutputStream.cpp index bf3599dbac9..a41eef649dd 100644 --- a/ndb/src/common/util/OutputStream.cpp +++ b/ndb/src/common/util/OutputStream.cpp @@ -74,7 +74,7 @@ SoftOseOutputStream::print(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); else buf[0] = 0; va_end(ap); @@ -88,7 +88,7 @@ SoftOseOutputStream::println(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); else buf[0] = 0; va_end(ap); diff --git a/ndb/src/common/util/Properties.cpp b/ndb/src/common/util/Properties.cpp index 80fb0027830..a13e31780eb 100644 --- a/ndb/src/common/util/Properties.cpp +++ b/ndb/src/common/util/Properties.cpp @@ -371,7 +371,7 @@ Properties::print(FILE * out, const char * prefix) const{ break; case PropertiesType_Properties: char buf2 [1024]; - snprintf(buf2, sizeof(buf2), "%s%s%c",buf, impl->content[i]->name, + BaseString::snprintf(buf2, sizeof(buf2), "%s%s%c",buf, impl->content[i]->name, Properties::delimiter); ((Properties *)impl->content[i]->value)->print(out, buf2); break; @@ -994,7 +994,7 @@ bool Properties::put(const char * name, Uint32 no, Uint32 val, bool replace){ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = put(tmp, val, replace); free(tmp); return res; @@ -1004,7 +1004,7 @@ bool Properties::put64(const char * name, Uint32 no, Uint64 val, bool replace){ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = put(tmp, val, replace); free(tmp); return res; @@ -1015,7 +1015,7 @@ bool Properties::put(const char * name, Uint32 no, const char * val, bool replace){ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = put(tmp, val, replace); free(tmp); return res; @@ -1027,7 +1027,7 @@ Properties::put(const char * name, Uint32 no, const Properties * val, bool replace){ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = put(tmp, val, replace); free(tmp); return res; @@ -1039,7 +1039,7 @@ Properties::getTypeOf(const char * name, Uint32 no, PropertiesType * type) const { size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = getTypeOf(tmp, type); free(tmp); return res; @@ -1049,7 +1049,7 @@ bool Properties::contains(const char * name, Uint32 no) const { size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = contains(tmp); free(tmp); return res; @@ -1059,7 +1059,7 @@ bool Properties::get(const char * name, Uint32 no, Uint32 * value) const{ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = get(tmp, value); free(tmp); return res; @@ -1069,7 +1069,7 @@ bool Properties::get(const char * name, Uint32 no, Uint64 * value) const{ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = get(tmp, value); free(tmp); return res; @@ -1080,7 +1080,7 @@ bool Properties::get(const char * name, Uint32 no, const char ** value) const { size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = get(tmp, value); free(tmp); return res; @@ -1091,7 +1091,7 @@ bool Properties::get(const char * name, Uint32 no, const Properties ** value) const{ size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = get(tmp, value); free(tmp); return res; @@ -1102,7 +1102,7 @@ bool Properties::getCopy(const char * name, Uint32 no, char ** value) const { size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = getCopy(tmp, value); free(tmp); return res; @@ -1113,7 +1113,7 @@ bool Properties::getCopy(const char * name, Uint32 no, Properties ** value) const { size_t tmp_len = strlen(name)+20; char * tmp = (char*)malloc(tmp_len); - snprintf(tmp, tmp_len, "%s_%d", name, no); + BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no); bool res = getCopy(tmp, value); free(tmp); return res; diff --git a/ndb/src/common/util/SimpleProperties.cpp b/ndb/src/common/util/SimpleProperties.cpp index c3980f03c4d..00c440fcb4e 100644 --- a/ndb/src/common/util/SimpleProperties.cpp +++ b/ndb/src/common/util/SimpleProperties.cpp @@ -293,7 +293,7 @@ SimpleProperties::Reader::printAll(NdbOut& ndbout){ break; default: ndbout << "Unknown type for key: " << getKey() - << " type: " << getValueType() << endl; + << " type: " << (Uint32)getValueType() << endl; } } } diff --git a/ndb/src/common/util/basestring_vsnprintf.c b/ndb/src/common/util/basestring_vsnprintf.c new file mode 100644 index 00000000000..10932226d18 --- /dev/null +++ b/ndb/src/common/util/basestring_vsnprintf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2003 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 */ + +/* define on IRIX to get posix compliant vsnprintf */ +#define _XOPEN_SOURCE 500 +#include <stdio.h> +#include <basestring_vsnprintf.h> + +int +basestring_snprintf(char *str, size_t size, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret= basestring_vsnprintf(str, size, format, ap); + va_end(ap); + return(ret); +} + +int +basestring_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + return(vsnprintf(str, size, format, ap)); +} diff --git a/ndb/src/common/util/socket_io.cpp b/ndb/src/common/util/socket_io.cpp index b2f4ef91031..6f4c7e63684 100644 --- a/ndb/src/common/util/socket_io.cpp +++ b/ndb/src/common/util/socket_io.cpp @@ -175,13 +175,13 @@ vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis, size_t size = sizeof(buf); if (fmt != 0) { - size = vsnprintf(buf, sizeof(buf), fmt, ap); + size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); /* Check if the output was truncated */ if(size >= sizeof(buf)) { buf2 = (char *)malloc(size+1); if(buf2 == NULL) return -1; - vsnprintf(buf2, size, fmt, ap); + BaseString::vsnprintf(buf2, size, fmt, ap); } else size = sizeof(buf); } else @@ -202,13 +202,13 @@ vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis, size_t size = sizeof(buf); if (fmt != 0) { - size = vsnprintf(buf, sizeof(buf), fmt, ap); + size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); /* Check if the output was truncated */ if(size >= sizeof(buf)-1) { buf2 = (char *)malloc(size+2); if(buf2 == NULL) return -1; - vsnprintf(buf2, size+1, fmt, ap); + BaseString::vsnprintf(buf2, size+1, fmt, ap); } else size = sizeof(buf); } else diff --git a/ndb/src/cw/cpcd/APIService.cpp b/ndb/src/cw/cpcd/APIService.cpp index de0e40cebfc..63d0aaafe86 100644 --- a/ndb/src/cw/cpcd/APIService.cpp +++ b/ndb/src/cw/cpcd/APIService.cpp @@ -309,7 +309,7 @@ propToString(Properties *prop, const char *key) { case PropertiesType_Uint32: Uint32 val; prop->get(key, &val); - snprintf(buf, sizeof buf, "%d", val); + BaseString::snprintf(buf, sizeof buf, "%d", val); retval = buf; break; case PropertiesType_char: @@ -318,7 +318,7 @@ propToString(Properties *prop, const char *key) { retval = str; break; default: - snprintf(buf, sizeof buf, "(unknown)"); + BaseString::snprintf(buf, sizeof buf, "(unknown)"); retval = buf; } return retval; diff --git a/ndb/src/cw/cpcd/CPCD.cpp b/ndb/src/cw/cpcd/CPCD.cpp index bc9f350755f..69a7b840528 100644 --- a/ndb/src/cw/cpcd/CPCD.cpp +++ b/ndb/src/cw/cpcd/CPCD.cpp @@ -237,9 +237,9 @@ CPCD::saveProcessList(){ FILE *f; /* Create the filenames that we will use later */ - snprintf(newfile, sizeof(newfile), "%s.new", m_procfile.c_str()); - snprintf(oldfile, sizeof(oldfile), "%s.old", m_procfile.c_str()); - snprintf(curfile, sizeof(curfile), "%s", m_procfile.c_str()); + BaseString::snprintf(newfile, sizeof(newfile), "%s.new", m_procfile.c_str()); + BaseString::snprintf(oldfile, sizeof(oldfile), "%s.old", m_procfile.c_str()); + BaseString::snprintf(curfile, sizeof(curfile), "%s", m_procfile.c_str()); f = fopen(newfile, "w"); @@ -380,7 +380,7 @@ CPCD::getProcessList() { void CPCD::RequestStatus::err(enum RequestStatusCode status, const char *msg) { m_status = status; - snprintf(m_errorstring, sizeof(m_errorstring), "%s", msg); + BaseString::snprintf(m_errorstring, sizeof(m_errorstring), "%s", msg); } #if 0 diff --git a/ndb/src/cw/cpcd/Process.cpp b/ndb/src/cw/cpcd/Process.cpp index c38b2a45145..2d3973d1aba 100644 --- a/ndb/src/cw/cpcd/Process.cpp +++ b/ndb/src/cw/cpcd/Process.cpp @@ -140,7 +140,7 @@ CPCD::Process::readPid() { memset(buf, 0, sizeof(buf)); - snprintf(filename, sizeof(filename), "%d", m_id); + BaseString::snprintf(filename, sizeof(filename), "%d", m_id); f = fopen(filename, "r"); @@ -167,8 +167,8 @@ CPCD::Process::writePid(int pid) { char filename[PATH_MAX*2+1]; FILE *f; - snprintf(tmpfilename, sizeof(tmpfilename), "tmp.XXXXXX"); - snprintf(filename, sizeof(filename), "%d", m_id); + BaseString::snprintf(tmpfilename, sizeof(tmpfilename), "tmp.XXXXXX"); + BaseString::snprintf(filename, sizeof(filename), "%d", m_id); int fd = mkstemp(tmpfilename); if(fd < 0) { @@ -439,7 +439,7 @@ void CPCD::Process::stop() { char filename[PATH_MAX*2+1]; - snprintf(filename, sizeof(filename), "%d", m_id); + BaseString::snprintf(filename, sizeof(filename), "%d", m_id); unlink(filename); if(m_pid <= 1){ diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 43532a973f9..70f11c33cd7 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -3,7 +3,7 @@ Next NDBCNTR 1000 Next NDBFS 2000 Next DBACC 3001 Next DBTUP 4007 -Next DBLQH 5040 +Next DBLQH 5042 Next DBDICT 6006 Next DBDIH 7174 Next DBTC 8035 @@ -193,6 +193,8 @@ Delay execution of ABORTREQ signal 2 seconds to generate time-out. 5038: Drop LQHKEYREQ + set 5039 5039: Drop ABORT + set 5003 +8048: Make TC not choose own node for simple/dirty read +5041: Crash is receiving simple read from other TC on different node ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC ------------------------------------------------- diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 08a8bf83e20..e6fe63d9014 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -1307,7 +1307,7 @@ Backup::sendCreateTrig(Signal* signal, for (int i=0; i < 3; i++) { req->setTriggerEvent(triggerEventValues[i]); - snprintf(triggerName, sizeof(triggerName), triggerNameFormat[i], + BaseString::snprintf(triggerName, sizeof(triggerName), triggerNameFormat[i], ptr.p->backupId, tabPtr.p->tableId); w.reset(); w.add(CreateTrigReq::TriggerNameKey, triggerName); @@ -1945,7 +1945,7 @@ Backup::sendDropTrig(Signal* signal, BackupRecordPtr ptr, TablePtr tabPtr) sendSignal(DBDICT_REF, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); } else { - snprintf(triggerName, sizeof(triggerName), triggerNameFormat[i], + BaseString::snprintf(triggerName, sizeof(triggerName), triggerNameFormat[i], ptr.p->backupId, tabPtr.p->tableId); w.reset(); w.add(CreateTrigReq::TriggerNameKey, triggerName); @@ -3360,7 +3360,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal) req->senderData = filePtr.i; req->resultRef = reference(); req->schemaVersion = table.schemaVersion; - req->fragmentNo = fragNo; + req->fragmentNoKeyLen = fragNo; req->requestInfo = 0; req->savePointId = 0; req->tableId = table.tableId; diff --git a/ndb/src/kernel/blocks/backup/restore/Restore.cpp b/ndb/src/kernel/blocks/backup/restore/Restore.cpp index 9e1ad228ee5..fb3bde6bdef 100644 --- a/ndb/src/kernel/blocks/backup/restore/Restore.cpp +++ b/ndb/src/kernel/blocks/backup/restore/Restore.cpp @@ -515,7 +515,7 @@ BackupFile::setCtlFile(Uint32 nodeId, Uint32 backupId, const char * path){ m_expectedFileHeader.FileType = BackupFormat::CTL_FILE; char name[PATH_MAX]; const Uint32 sz = sizeof(name); - snprintf(name, sz, "BACKUP-%d.%d.ctl", backupId, nodeId); + BaseString::snprintf(name, sz, "BACKUP-%d.%d.ctl", backupId, nodeId); setName(path, name); } @@ -526,7 +526,7 @@ BackupFile::setDataFile(const BackupFile & bf, Uint32 no){ m_expectedFileHeader.FileType = BackupFormat::DATA_FILE; char name[PATH_MAX]; const Uint32 sz = sizeof(name); - snprintf(name, sz, "BACKUP-%d-%d.%d.Data", + BaseString::snprintf(name, sz, "BACKUP-%d-%d.%d.Data", m_expectedFileHeader.BackupId, no, m_nodeId); setName(bf.m_path, name); } @@ -538,7 +538,7 @@ BackupFile::setLogFile(const BackupFile & bf, Uint32 no){ m_expectedFileHeader.FileType = BackupFormat::LOG_FILE; char name[PATH_MAX]; const Uint32 sz = sizeof(name); - snprintf(name, sz, "BACKUP-%d.%d.log", + BaseString::snprintf(name, sz, "BACKUP-%d.%d.log", m_expectedFileHeader.BackupId, m_nodeId); setName(bf.m_path, name); } @@ -548,15 +548,15 @@ BackupFile::setName(const char * p, const char * n){ const Uint32 sz = sizeof(m_path); if(p != 0 && strlen(p) > 0){ if(p[strlen(p)-1] == '/'){ - snprintf(m_path, sz, "%s", p); + BaseString::snprintf(m_path, sz, "%s", p); } else { - snprintf(m_path, sz, "%s%s", p, "/"); + BaseString::snprintf(m_path, sz, "%s%s", p, "/"); } } else { m_path[0] = 0; } - snprintf(m_fileName, sizeof(m_fileName), "%s%s", m_path, n); + BaseString::snprintf(m_fileName, sizeof(m_fileName), "%s%s", m_path, n); debug << "Filename = " << m_fileName << endl; } @@ -936,8 +936,9 @@ operator<<(NdbOut& ndbout, const TableS & table){ for (int j = 0; j < table.getNoOfAttributes(); j++) { const AttributeDesc * desc = table[j]; - ndbout << desc->m_column->getName() << ": " << desc->m_column->getType(); - ndbout << " key: " << desc->m_column->getPrimaryKey(); + ndbout << desc->m_column->getName() << ": " + << (Uint32) desc->m_column->getType(); + ndbout << " key: " << (Uint32) desc->m_column->getPrimaryKey(); ndbout << " array: " << desc->arraySize; ndbout << " size: " << desc->size << endl; } // for diff --git a/ndb/src/kernel/blocks/backup/restore/Restore.hpp b/ndb/src/kernel/blocks/backup/restore/Restore.hpp index 8ca68fd9b23..0ec1ab852e9 100644 --- a/ndb/src/kernel/blocks/backup/restore/Restore.hpp +++ b/ndb/src/kernel/blocks/backup/restore/Restore.hpp @@ -91,7 +91,7 @@ class TupleS { private: friend class RestoreDataIterator; - TableS *m_currentTable; + class TableS *m_currentTable; AttributeData *allAttrData; bool prepareRecord(TableS &); diff --git a/ndb/src/kernel/blocks/backup/restore/consumer_restore.cpp b/ndb/src/kernel/blocks/backup/restore/consumer_restore.cpp index fb82570b0b9..a35d9d22c65 100644 --- a/ndb/src/kernel/blocks/backup/restore/consumer_restore.cpp +++ b/ndb/src/kernel/blocks/backup/restore/consumer_restore.cpp @@ -121,7 +121,7 @@ BackupRestore::get_table(const NdbDictionary::Table* tab){ int cnt, id1, id2; char buf[256]; if((cnt = sscanf(tab->getName(), "%[^/]/%[^/]/NDB$BLOB_%d_%d", buf, buf, &id1, &id2)) == 4){ - snprintf(buf, sizeof(buf), "NDB$BLOB_%d_%d", m_new_tables[id1]->getTableId(), id2); + BaseString::snprintf(buf, sizeof(buf), "NDB$BLOB_%d_%d", m_new_tables[id1]->getTableId(), id2); m_cache.m_new_table = m_ndb->getDictionary()->getTable(buf); } else { m_cache.m_new_table = m_new_tables[tab->getTableId()]; diff --git a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp index 3bf50026c4b..169b77c0d85 100644 --- a/ndb/src/kernel/blocks/dbacc/Dbacc.hpp +++ b/ndb/src/kernel/blocks/dbacc/Dbacc.hpp @@ -1087,10 +1087,10 @@ private: void deleteLongKey(Signal* signal); void removeFromPageArrayList(Signal* signal); void insertPageArrayList(Signal* signal); - void checkPageArrayList(Signal* signal, char *); - void checkPageB4Insert(Uint32, char *); - void checkPageB4Remove(Uint32, char *); - void checkIndexInLongKeyPage(Uint32, char *); + void checkPageArrayList(Signal* signal, const char *); + void checkPageB4Insert(Uint32, const char *); + void checkPageB4Remove(Uint32, const char *); + void checkIndexInLongKeyPage(Uint32, const char *); void printoutInfoAndShutdown(LongKeyPage *); void releaseLongPage(Signal* signal); void abortOperation(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index 79034c9eb36..9a1bbd86562 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -2369,7 +2369,7 @@ void Dbacc::execACC_COMMITREQ(Signal* signal) ptrCheckGuard(rootfragrecptr, crootfragmentsize, rootfragmentrec); rootfragrecptr.p->noOfElements++; fragrecptr.p->slack -= operationRecPtr.p->insertDeleteLen; - if (fragrecptr.p->slack >= (Uint32)(1 << 31)) { + if (fragrecptr.p->slack >= (1u << 31)) { /* IT MEANS THAT IF SLACK < ZERO */ if (fragrecptr.p->expandFlag == 0) { jam(); @@ -2479,7 +2479,7 @@ void Dbacc::execACC_LOCKREQ(Signal* signal) Uint32 opCode = ZSCAN_OP; signal->theData[0] = operationRecPtr.i; signal->theData[1] = fragrecptr.i; - signal->theData[2] = opCode | (lockMode << 4) | (1 << 31); + signal->theData[2] = opCode | (lockMode << 4) | (1u << 31); signal->theData[3] = req->hashValue; signal->theData[4] = 1; // fake primKeyLen signal->theData[5] = req->transId1; @@ -4051,7 +4051,7 @@ void Dbacc::deleteLongKey(Signal* signal) }//Dbacc::deleteLongKey() -void Dbacc::checkIndexInLongKeyPage(Uint32 pageId, char *calledFrom) { +void Dbacc::checkIndexInLongKeyPage(Uint32 pageId, const char *calledFrom) { Page8Ptr pagePtr; LongKeyPage *page; Uint32 indexNo; @@ -4206,7 +4206,7 @@ void Dbacc::insertPageArrayList(Signal* signal) // --------------------------------------------------------------------------------- */ // Check the page array list. // --------------------------------------------------------------------------------- */ -void Dbacc::checkPageArrayList(Signal* signal, char *calledFrom) +void Dbacc::checkPageArrayList(Signal* signal, const char *calledFrom) { Page8Ptr pagePtr; Uint32 pageArrayIndex; @@ -4251,7 +4251,7 @@ void Dbacc::checkPageArrayList(Signal* signal, char *calledFrom) // --------------------------------------------------------------------------------- */ // Check the page to put into the pageArrayList. // --------------------------------------------------------------------------------- */ -void Dbacc::checkPageB4Insert(Uint32 pageId, char *calledFrom) { +void Dbacc::checkPageB4Insert(Uint32 pageId, const char *calledFrom) { Page8Ptr pagePtr; Uint32 pageArrayIndex; LongKeyPage *page; @@ -4318,7 +4318,7 @@ void Dbacc::checkPageB4Insert(Uint32 pageId, char *calledFrom) { // --------------------------------------------------------------------------------- */ // Check the page to remove from the pageArrayList. // --------------------------------------------------------------------------------- */ -void Dbacc::checkPageB4Remove(Uint32 pageId, char *calledFrom) { +void Dbacc::checkPageB4Remove(Uint32 pageId, const char *calledFrom) { Page8Ptr pagePtr; Uint32 pageArrayIndex; Uint32 noOfOccurrence = 0; @@ -6510,7 +6510,7 @@ void Dbacc::endofexpLab(Signal* signal) Uint32 noOfBuckets = (fragrecptr.p->maxp + 1) + fragrecptr.p->p; Uint32 Thysteres = fragrecptr.p->maxloadfactor - fragrecptr.p->minloadfactor; fragrecptr.p->slackCheck = noOfBuckets * Thysteres; - if (fragrecptr.p->slack > (Uint32)(1 << 31)) { + if (fragrecptr.p->slack > (1u << 31)) { jam(); /* IT MEANS THAT IF SLACK < ZERO */ /* --------------------------------------------------------------------------------- */ @@ -6974,7 +6974,7 @@ void Dbacc::execSHRINKCHECK2(Signal* signal) /*--------------------------------------------------------------*/ return; }//if - if (fragrecptr.p->slack > (Uint32)(1 << 31)) { + if (fragrecptr.p->slack > (1u << 31)) { jam(); /*--------------------------------------------------------------*/ /* THE SLACK IS NEGATIVE, IN THIS CASE WE WILL NOT NEED ANY */ @@ -7213,7 +7213,7 @@ void Dbacc::endofshrinkbucketLab(Signal* signal) expDirRangePtr.p->dirArray[fragrecptr.p->expSenderDirIndex >> 8] = RNIL; }//if }//if - if (fragrecptr.p->slack < (Uint32)(1 << 31)) { + if (fragrecptr.p->slack < (1u << 31)) { jam(); /*--------------------------------------------------------------*/ /* THE SLACK IS POSITIVE, IN THIS CASE WE WILL CHECK WHETHER */ @@ -13411,8 +13411,12 @@ Dbacc::execREAD_PSUEDO_REQ(Signal* signal){ default: tmp = 0; } - Uint32 * src = (Uint32*)&tmp; - signal->theData[0] = src[0]; - signal->theData[1] = src[1]; + memcpy(signal->theData, &tmp, 8); /* must be memcpy, gives strange results on + * ithanium gcc (GCC) 3.4.1 smp linux 2.4 + * otherwise + */ + // Uint32 * src = (Uint32*)&tmp; + // signal->theData[0] = src[0]; + // signal->theData[1] = src[1]; } diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 572e9f39ba5..76aa745c3e0 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -1438,7 +1438,7 @@ void Dbdih::execREAD_NODESCONF(Signal* signal) continue; } char buf[255]; - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Illegal configuration change." " Initial start needs to be performed " " when changing no of storage nodes (node %d)", i); @@ -1638,7 +1638,7 @@ void Dbdih::execSTART_PERMREQ(Signal* signal) }//if if (getNodeStatus(nodeId) != NodeRecord::DEAD){ ndbout << "nodeStatus in START_PERMREQ = " - << getNodeStatus(nodeId) << endl; + << (Uint32) getNodeStatus(nodeId) << endl; ndbrequire(false); }//if @@ -3500,7 +3500,7 @@ void Dbdih::selectMasterCandidateAndSend(Signal* signal) Uint32 count = node_groups[nodePtr.i]; if(count != 0 && count != cnoReplicas){ char buf[255]; - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Illegal configuration change." " Initial start needs to be performed " " when changing no of replicas (%d != %d)", @@ -4268,7 +4268,7 @@ void Dbdih::failedNodeLcpHandling(Signal* signal, NodeRecordPtr failedNodePtr) failedNodePtr.p->activeStatus = Sysfile::NS_NotActive_NotTakenOver; break; default: - ndbout << "activeStatus = " << failedNodePtr.p->activeStatus; + ndbout << "activeStatus = " << (Uint32) failedNodePtr.p->activeStatus; ndbout << " at failure after NODE_FAILREP of node = "; ndbout << failedNodePtr.i << endl; ndbrequire(false); @@ -4618,6 +4618,7 @@ void Dbdih::execMASTER_GCPREQ(Signal* signal) /* BUT NOT YET COMPLETED. */ /*--------------------------------------------------*/ ndbrequire(false); + gcpState= MasterGCPConf::GCP_READY; // remove warning break; default: /*------------------------------------------------*/ @@ -4627,6 +4628,7 @@ void Dbdih::execMASTER_GCPREQ(Signal* signal) /* NODE WHICH WAS NOT A MASTER NODE. */ /*------------------------------------------------*/ ndbrequire(false); + gcpState= MasterGCPConf::GCP_READY; // remove warning break; }//switch MasterGCPConf * const masterGCPConf = (MasterGCPConf *)&signal->theData[0]; @@ -5535,6 +5537,7 @@ Dbdih::sendMASTER_LCPCONF(Signal * signal){ * it not allowed */ ndbrequire(false); + lcpState= MasterLCPConf::LCP_STATUS_IDLE; // remove warning break; case LCP_COPY_GCI: case LCP_INIT_TABLES: @@ -5543,6 +5546,7 @@ Dbdih::sendMASTER_LCPCONF(Signal * signal){ * These two states are handled by if statements above */ ndbrequire(false); + lcpState= MasterLCPConf::LCP_STATUS_IDLE; // remove warning break; }//switch ndbrequire(ok); @@ -6198,7 +6202,8 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){ if (primaryTableId == RNIL) { if(fragmentNode == 0){ jam(); - NGPtr.i = c_nextNodeGroup; + // needs to be fixed for single fragment tables + NGPtr.i = 0; //c_nextNodeGroup; c_nextNodeGroup = (NGPtr.i + 1 == cnoOfNodeGroups ? 0 : NGPtr.i + 1); } else if(! (fragmentNode < MAX_NDB_NODES)) { jam(); @@ -6255,20 +6260,22 @@ void Dbdih::execCREATE_FRAGMENTATION_REQ(Signal * signal){ //@todo use section writer Uint32 count = 2; Uint32 fragments[2 + 8*MAX_REPLICAS*MAX_NDB_NODES]; + Uint32 next_replica_node[MAX_NDB_NODES]; + memset(next_replica_node,0,sizeof(next_replica_node)); if (primaryTableId == RNIL) { jam(); for(Uint32 fragNo = 0; fragNo<noOfFragments; fragNo++){ jam(); ptrCheckGuard(NGPtr, MAX_NDB_NODES, nodeGroupRecord); - Uint32 ind = NGPtr.p->nextReplicaNode; + Uint32 ind = next_replica_node[NGPtr.i]; const Uint32 max = NGPtr.p->nodeCount; //------------------------------------------------------------------- // We make an extra step to ensure that the primary replicas are // spread among the nodes. //------------------------------------------------------------------- - NGPtr.p->nextReplicaNode = (ind + 1 >= max ? 0 : ind + 1); + next_replica_node[NGPtr.i] = (ind + 1 >= max ? 0 : ind + 1); for(Uint32 replicaNo = 0; replicaNo<noOfReplicas; replicaNo++){ jam(); @@ -7127,7 +7134,7 @@ void Dbdih::checkGcpStopLab(Signal* signal) jam(); #ifdef VM_TRACE ndbout << "System crash due to GCP Stop in state = "; - ndbout << cgcpStatus << endl; + ndbout << (Uint32) cgcpStatus << endl; #endif crashSystemAtGcpStop(signal); return; @@ -7141,7 +7148,7 @@ void Dbdih::checkGcpStopLab(Signal* signal) jam(); #ifdef VM_TRACE ndbout << "System crash due to GCP Stop in state = "; - ndbout << cgcpStatus << endl; + ndbout << (Uint32) cgcpStatus << endl; #endif crashSystemAtGcpStop(signal); return; @@ -8631,7 +8638,7 @@ void Dbdih::startFragment(Signal* signal, Uint32 tableId, Uint32 fragId) /* POSSIBLE TO RESTORE THE SYSTEM. */ /* --------------------------------------------------------------------- */ char buf[100]; - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Unable to find restorable replica for " "table: %d fragment: %d gci: %d", tableId, fragId, SYSFILE->newestRestorableGCI); @@ -9074,7 +9081,7 @@ void Dbdih::checkTcCounterLab(Signal* signal) { CRASH_INSERTION(7009); if (c_lcpState.lcpStatus != LCP_STATUS_IDLE) { - ndbout << "lcpStatus = " << c_lcpState.lcpStatus; + ndbout << "lcpStatus = " << (Uint32) c_lcpState.lcpStatus; ndbout << "lcpStatusUpdatedPlace = " << c_lcpState.lcpStatusUpdatedPlace << endl; ndbrequire(false); @@ -12735,6 +12742,7 @@ void Dbdih::setNodeRestartInfoBits() break; default: ndbrequire(false); + tsnrNodeActiveStatus = Sysfile::NS_NotDefined; // remove warning break; }//switch Sysfile::setNodeStatus(nodePtr.i, SYSFILE->nodeStatus, @@ -12939,7 +12947,7 @@ Dbdih::execDUMP_STATE_ORD(Signal* signal) snprintf(buf, sizeof(buf), " Table %d Fragment %d - ", tabPtr.i, j); for(Uint32 k = 0; k < noOfReplicas; k++){ char tmp[100]; - snprintf(tmp, sizeof(tmp), "%d ", nodeOrder[k]); + BaseString::snprintf(tmp, sizeof(tmp), "%d ", nodeOrder[k]); strcat(buf, tmp); } infoEvent(buf); @@ -13155,12 +13163,12 @@ Dbdih::execDUMP_STATE_ORD(Signal* signal) replicaPtr.i = fragPtr.p->storedReplicas; do { ptrCheckGuard(replicaPtr, creplicaFileSize, replicaRecord); - snprintf(buf2, sizeof(buf2), "%s %d(on %d)=%d(%s)", + BaseString::snprintf(buf2, sizeof(buf2), "%s %d(on %d)=%d(%s)", buf, num, replicaPtr.p->procNode, replicaPtr.p->lcpIdStarted, replicaPtr.p->lcpOngoingFlag ? "Ongoing" : "Idle"); - snprintf(buf, sizeof(buf), "%s", buf2); + BaseString::snprintf(buf, sizeof(buf), "%s", buf2); num++; replicaPtr.i = replicaPtr.p->nextReplica; diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index a94af7b59c8..d6987f3e478 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -234,10 +234,6 @@ #define ZNODE_UP 0 #define ZNODE_DOWN 1 /* ------------------------------------------------------------------------- */ -/* OPERATION TYPES */ -/* ------------------------------------------------------------------------- */ -#define ZSIMPLE_READ 1 -/* ------------------------------------------------------------------------- */ /* START PHASES */ /* ------------------------------------------------------------------------- */ #define ZLAST_START_PHASE 255 @@ -2248,7 +2244,7 @@ private: void sendAttrinfoLoop(Signal* signal); void sendAttrinfoSignal(Signal* signal); void sendLqhAttrinfoSignal(Signal* signal); - void sendKeyinfoAcc(Signal* signal); + void sendKeyinfoAcc(Signal* signal, Uint32 pos); Uint32 initScanrec(const class ScanFragReq *); void initScanTc(Signal* signal, Uint32 transid1, @@ -2437,6 +2433,7 @@ private: void abortStateHandlerLab(Signal* signal); void writeAttrinfoLab(Signal* signal); void scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length); + void abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode); void localAbortStateHandlerLab(Signal* signal); void logLqhkeyreqLab(Signal* signal); void lqhAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 8342870d69c..cd15ad0c3b2 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -2803,8 +2803,10 @@ void Dblqh::execKEYINFO(Signal* signal) return; }//if TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->transactionState != - TcConnectionrec::WAIT_TUPKEYINFO) { + TcConnectionrec::TransactionState state = regTcPtr->transactionState; + if (state != TcConnectionrec::WAIT_TUPKEYINFO && + state != TcConnectionrec::WAIT_SCAN_AI) + { jam(); /*****************************************************************************/ /* TRANSACTION WAS ABORTED, THIS IS MOST LIKELY A SIGNAL BELONGING TO THE */ @@ -2823,14 +2825,20 @@ void Dblqh::execKEYINFO(Signal* signal) }//if jam(); terrorCode = errorCode; - abortErrorLab(signal); + if(state == TcConnectionrec::WAIT_TUPKEYINFO) + abortErrorLab(signal); + else + abort_scan(signal, regTcPtr->tcScanRec, errorCode); return; }//if - FragrecordPtr regFragptr; - regFragptr.i = regTcPtr->fragmentptr; - ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); - fragptr = regFragptr; - endgettupkeyLab(signal); + if(state == TcConnectionrec::WAIT_TUPKEYINFO) + { + FragrecordPtr regFragptr; + regFragptr.i = regTcPtr->fragmentptr; + ptrCheckGuard(regFragptr, cfragrecFileSize, fragrecord); + fragptr = regFragptr; + endgettupkeyLab(signal); + } return; }//Dblqh::execKEYINFO() @@ -2838,9 +2846,9 @@ void Dblqh::execKEYINFO(Signal* signal) /* FILL IN KEY DATA INTO DATA BUFFERS. */ /* ------------------------------------------------------------------------- */ Uint32 Dblqh::handleLongTupKey(Signal* signal, - Uint32 keyLength, - Uint32 primKeyLength, - Uint32* dataPtr) + Uint32 keyLength, + Uint32 primKeyLength, + Uint32* dataPtr) { TcConnectionrec * const regTcPtr = tcConnectptr.p; Uint32 dataPos = 0; @@ -3293,12 +3301,15 @@ void Dblqh::execLQHKEYREQ(Signal* signal) regTcPtr->dirtyOp = LqhKeyReq::getDirtyFlag(Treqinfo); regTcPtr->opExec = LqhKeyReq::getInterpretedFlag(Treqinfo); regTcPtr->opSimple = LqhKeyReq::getSimpleFlag(Treqinfo); - regTcPtr->simpleRead = ((Treqinfo >> 18) & 15); regTcPtr->operation = LqhKeyReq::getOperation(Treqinfo); + regTcPtr->simpleRead = regTcPtr->operation == ZREAD && regTcPtr->opSimple; regTcPtr->seqNoReplica = LqhKeyReq::getSeqNoReplica(Treqinfo); UintR TreclenAiLqhkey = LqhKeyReq::getAIInLqhKeyReq(Treqinfo); regTcPtr->apiVersionNo = 0; + CRASH_INSERTION2(5041, regTcPtr->simpleRead && + refToNode(signal->senderBlockRef()) != cownNodeid); + regTcPtr->reclenAiLqhkey = TreclenAiLqhkey; regTcPtr->currReclenAi = TreclenAiLqhkey; UintR TitcKeyLen = LqhKeyReq::getKeyLen(Treqinfo); @@ -3425,7 +3436,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal) if ((tfragDistKey != TdistKey) && (regTcPtr->seqNoReplica == 0) && (regTcPtr->dirtyOp == ZFALSE) && - (regTcPtr->simpleRead != ZSIMPLE_READ)) { + (regTcPtr->simpleRead == ZFALSE)) { /* ---------------------------------------------------------------------- * WE HAVE DIFFERENT OPINION THAN THE DIH THAT STARTED THE TRANSACTION. * THE REASON COULD BE THAT THIS IS AN OLD DISTRIBUTION WHICH IS NO LONGER @@ -3433,7 +3444,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal) * ONE IS ADDED TO THE DISTRIBUTION KEY EVERY TIME WE ADD A NEW REPLICA. * FAILED REPLICAS DO NOT AFFECT THE DISTRIBUTION KEY. THIS MEANS THAT THE * MAXIMUM DEVIATION CAN BE ONE BETWEEN THOSE TWO VALUES. - * ---------------------------------------------------------------------- */ + * --------------------------------------------------------------------- */ Int32 tmp = TdistKey - tfragDistKey; tmp = (tmp < 0 ? - tmp : tmp); if ((tmp <= 1) || (tfragDistKey == 0)) { @@ -3686,7 +3697,7 @@ void Dblqh::prepareContinueAfterBlockedLab(Signal* signal) signal->theData[9] = sig3; signal->theData[10] = sig4; if (regTcPtr->primKeyLen > 4) { - sendKeyinfoAcc(signal); + sendKeyinfoAcc(signal, 11); }//if EXECUTE_DIRECT(refToBlock(regTcPtr->tcAccBlockref), GSN_ACCKEYREQ, signal, 7 + regTcPtr->primKeyLen); @@ -3708,9 +3719,8 @@ void Dblqh::prepareContinueAfterBlockedLab(Signal* signal) /* ======= SEND KEYINFO TO ACC ======= */ /* */ /* ========================================================================== */ -void Dblqh::sendKeyinfoAcc(Signal* signal) +void Dblqh::sendKeyinfoAcc(Signal* signal, Uint32 Ti) { - UintR Ti = 11; DatabufPtr regDatabufptr; regDatabufptr.i = tcConnectptr.p->firstTupkeybuf; @@ -3874,7 +3884,7 @@ void Dblqh::tupkeyConfLab(Signal* signal) /* ---- GET OPERATION TYPE AND CHECK WHAT KIND OF OPERATION IS REQUESTED ---- */ const TupKeyConf * const tupKeyConf = (TupKeyConf *)&signal->theData[0]; TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); /* ---------------------------------------------------------------------- * THE OPERATION IS A SIMPLE READ. WE WILL IMMEDIATELY COMMIT THE OPERATION. @@ -5462,6 +5472,8 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) TcConnectionrec * const regTcPtr = tcConnectptr.p; Fragrecord * const regFragptr = fragptr.p; Uint32 operation = regTcPtr->operation; + Uint32 simpleRead = regTcPtr->simpleRead; + Uint32 dirtyOp = regTcPtr->dirtyOp; if (regTcPtr->activeCreat == ZFALSE) { if ((cCommitBlocked == true) && (regFragptr->fragActiveStatus == ZTRUE)) { @@ -5499,13 +5511,18 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) tupCommitReq->hashValue = regTcPtr->hashValue; EXECUTE_DIRECT(tup, GSN_TUP_COMMITREQ, signal, TupCommitReq::SignalLength); - }//if - Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); - signal->theData[0] = regTcPtr->accConnectrec; - EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); - Uint32 simpleRead = regTcPtr->simpleRead; + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } else { + if(!dirtyOp){ + Uint32 acc = refToBlock(regTcPtr->tcAccBlockref); + signal->theData[0] = regTcPtr->accConnectrec; + EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); + } + } jamEntry(); - if (simpleRead == ZSIMPLE_READ) { + if (simpleRead) { jam(); /* ------------------------------------------------------------------------- */ /*THE OPERATION WAS A SIMPLE READ THUS THE COMMIT PHASE IS ONLY NEEDED TO */ @@ -5518,7 +5535,6 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) return; }//if }//if - Uint32 dirtyOp = regTcPtr->dirtyOp; Uint32 seqNoReplica = regTcPtr->seqNoReplica; if (regTcPtr->gci > regFragptr->newestGci) { jam(); @@ -6087,7 +6103,7 @@ void Dblqh::abortStateHandlerLab(Signal* signal) /* ------------------------------------------------------------------------- */ return; }//if - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); /* ------------------------------------------------------------------------- */ /*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO */ @@ -6373,7 +6389,7 @@ void Dblqh::continueAbortLab(Signal* signal) void Dblqh::continueAfterLogAbortWriteLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->simpleRead == ZSIMPLE_READ) { + if (regTcPtr->simpleRead) { jam(); TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); @@ -7409,7 +7425,8 @@ void Dblqh::execSCAN_FRAGREQ(Signal* signal) jamEntry(); const Uint32 reqinfo = scanFragReq->requestInfo; - const Uint32 fragId = scanFragReq->fragmentNo; + const Uint32 fragId = (scanFragReq->fragmentNoKeyLen & 0xFFFF); + const Uint32 keyLen = (scanFragReq->fragmentNoKeyLen >> 16); tabptr.i = scanFragReq->tableId; const Uint32 max_rows = scanFragReq->batch_size_rows; const Uint32 scanLockMode = ScanFragReq::getLockMode(reqinfo); @@ -7473,6 +7490,8 @@ void Dblqh::execSCAN_FRAGREQ(Signal* signal) transid2, fragId, ZNIL); + tcConnectptr.p->save1 = 4; + tcConnectptr.p->primKeyLen = keyLen + 4; // hard coded in execKEYINFO errorCode = initScanrec(scanFragReq); if (errorCode != ZOK) { jam(); @@ -7585,23 +7604,29 @@ void Dblqh::scanAttrinfoLab(Signal* signal, Uint32* dataPtr, Uint32 length) }//if return; }//if - terrorCode = ZGET_ATTRINBUF_ERROR; + abort_scan(signal, scanptr.i, ZGET_ATTRINBUF_ERROR); +} + +void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){ + jam(); + scanptr.i = scan_ptr_i; + c_scanRecordPool.getPtr(scanptr); finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->transactionState = TcConnectionrec::IDLE; tcConnectptr.p->abortState = TcConnectionrec::ABORT_ACTIVE; - + ScanFragRef * ref = (ScanFragRef*)&signal->theData[0]; ref->senderData = tcConnectptr.p->clientConnectrec; ref->transId1 = tcConnectptr.p->transid[0]; ref->transId2 = tcConnectptr.p->transid[1]; - ref->errorCode = terrorCode; + ref->errorCode = errcode; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGREF, signal, ScanFragRef::SignalLength, JBB); deleteTransidHash(signal); releaseOprec(signal); releaseTcrec(signal, tcConnectptr); -}//Dblqh::scanAttrinfoLab() +} /*---------------------------------------------------------------------*/ /* Send this 'I am alive' signal to TC when it is received from ACC */ @@ -7672,34 +7697,17 @@ void Dblqh::accScanConfScanLab(Signal* signal) return; }//if scanptr.p->scanAccPtr = accScanConf->accPtr; - AttrbufPtr regAttrinbufptr; - regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf; - Uint32 boundAiLength = 0; + Uint32 boundAiLength = tcConnectptr.p->primKeyLen - 4; if (scanptr.p->rangeScan) { jam(); - // bound info length is in first of the 5 header words - ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); - boundAiLength = regAttrinbufptr.p->attrbuf[0]; TuxBoundInfo* const req = (TuxBoundInfo*)signal->getDataPtrSend(); req->errorCode = RNIL; req->tuxScanPtrI = scanptr.p->scanAccPtr; req->boundAiLength = boundAiLength; - Uint32* out = (Uint32*)req + TuxBoundInfo::SignalLength; - Uint32 sz = 0; - while (sz < boundAiLength) { - jam(); - ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); - Uint32 dataLen = regAttrinbufptr.p->attrbuf[ZINBUF_DATA_LEN]; - MEMCOPY_NO_WORDS(&out[sz], - ®Attrinbufptr.p->attrbuf[0], - dataLen); - sz += dataLen; - regAttrinbufptr.i = regAttrinbufptr.p->attrbuf[ZINBUF_NEXT]; - ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); - } - ndbrequire(sz == boundAiLength); + if(boundAiLength > 0) + sendKeyinfoAcc(signal, TuxBoundInfo::SignalLength); EXECUTE_DIRECT(DBTUX, GSN_TUX_BOUND_INFO, - signal, TuxBoundInfo::SignalLength + boundAiLength); + signal, TuxBoundInfo::SignalLength + boundAiLength); jamEntry(); if (req->errorCode != 0) { jam(); @@ -7716,12 +7724,14 @@ void Dblqh::accScanConfScanLab(Signal* signal) signal->theData[1] = tcConnectptr.p->tableref; signal->theData[2] = scanptr.p->scanSchemaVersion; signal->theData[3] = ZSTORED_PROC_SCAN; - ndbrequire(boundAiLength <= scanptr.p->scanAiLength); - signal->theData[4] = scanptr.p->scanAiLength - boundAiLength; + + signal->theData[4] = scanptr.p->scanAiLength; sendSignal(tcConnectptr.p->tcTupBlockref, GSN_STORED_PROCREQ, signal, 5, JBB); signal->theData[0] = tcConnectptr.p->tupConnectrec; + AttrbufPtr regAttrinbufptr; + regAttrinbufptr.i = tcConnectptr.p->firstAttrinbuf; while (regAttrinbufptr.i != RNIL) { ptrCheckGuard(regAttrinbufptr, cattrinbufFileSize, attrbuf); jam(); @@ -14797,7 +14807,7 @@ void Dblqh::execDEBUG_SIG(Signal* signal) tdebug = logPagePtr.p->logPageWord[0]; char buf[100]; - snprintf(buf, 100, + BaseString::snprintf(buf, 100, "Error while reading REDO log.\n" "D=%d, F=%d Mb=%d FP=%d W1=%d W2=%d", signal->theData[2], signal->theData[3], signal->theData[4], diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index a5f07f8e9e1..a209df24c44 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -192,7 +192,8 @@ public: OS_WAIT_ATTR = 14, OS_WAIT_COMMIT_CONF = 15, OS_WAIT_ABORT_CONF = 16, - OS_WAIT_COMPLETE_CONF = 17 + OS_WAIT_COMPLETE_CONF = 17, + OS_WAIT_SCAN = 18 }; enum AbortState { @@ -1169,6 +1170,8 @@ public: // Length of expected attribute information Uint32 scanAiLength; + Uint32 scanKeyLen; + // Reference to ApiConnectRecord Uint32 scanApiRec; @@ -1194,18 +1197,7 @@ public: Uint16 first_batch_size; Uint32 batch_byte_size; - // Shall the locks be held until the application have read the - // records - Uint8 scanLockHold; - - // Shall the locks be read or write locks - Uint8 scanLockMode; - - // Skip locks by other transactions and read latest committed - Uint8 readCommitted; - - // Scan is on ordered index - Uint8 rangeScan; + Uint32 scanRequestInfo; // ScanFrag format // Close is ordered bool m_close_scan_req; @@ -1467,7 +1459,7 @@ private: void releaseAttrinfo(); void releaseGcp(Signal* signal); void releaseKeys(); - void releaseSimpleRead(Signal* signal); + void releaseSimpleRead(Signal*, ApiConnectRecordPtr, TcConnectRecord*); void releaseDirtyWrite(Signal* signal); void releaseTcCon(); void releaseTcConnectFail(Signal* signal); @@ -1571,7 +1563,7 @@ private: void diFcountReqLab(Signal* signal, ScanRecordPtr); void signalErrorRefuseLab(Signal* signal); void abort080Lab(Signal* signal); - void packKeyData000Lab(Signal* signal, BlockReference TBRef); + void packKeyData000Lab(Signal* signal, BlockReference TBRef, Uint32 len); void abortScanLab(Signal* signal, ScanRecordPtr, Uint32 errCode); void sendAbortedAfterTimeout(Signal* signal, int Tcheck); void abort010Lab(Signal* signal); diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index d270c6acc61..d8b3ee10532 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -274,6 +274,12 @@ void Dbtc::execCONTINUEB(Signal* signal) transPtr.p->triggerPending = false; executeTriggers(signal, &transPtr); return; + case TcContinueB::DelayTCKEYCONF: + jam(); + apiConnectptr.i = Tdata0; + ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); + sendtckeyconf(signal, Tdata1); + return; default: ndbrequire(false); }//switch @@ -1759,6 +1765,7 @@ void Dbtc::execKEYINFO(Signal* signal) switch (apiConnectptr.p->apiConnectstate) { case CS_RECEIVING: case CS_REC_COMMITTING: + case CS_START_SCAN: jam(); /*empty*/; break; @@ -1812,12 +1819,54 @@ void Dbtc::execKEYINFO(Signal* signal) jam(); tckeyreq020Lab(signal); return; + case OS_WAIT_SCAN: + break; default: jam(); terrorCode = ZSTATE_ERROR; abortErrorLab(signal); return; }//switch + + UintR TdataPos = 0; + UintR TkeyLen = regCachePtr->keylen; + UintR Tlen = regCachePtr->save1; + + do { + if (cfirstfreeDatabuf == RNIL) { + jam(); + abort(); + seizeDatabuferrorLab(signal); + return; + }//if + linkKeybuf(signal); + arrGuard(TdataPos, 19); + databufptr.p->data[0] = signal->theData[TdataPos + 3]; + databufptr.p->data[1] = signal->theData[TdataPos + 4]; + databufptr.p->data[2] = signal->theData[TdataPos + 5]; + databufptr.p->data[3] = signal->theData[TdataPos + 6]; + Tlen = Tlen + 4; + TdataPos = TdataPos + 4; + if (Tlen < TkeyLen) { + jam(); + if (TdataPos >= tmaxData) { + jam(); + /*----------------------------------------------------*/ + /** EXIT AND WAIT FOR SIGNAL KEYINFO OR KEYINFO9 **/ + /** WHEN EITHER OF THE SIGNALS IS RECEIVED A JUMP **/ + /** TO LABEL "KEYINFO_LABEL" IS DONE. THEN THE **/ + /** PROGRAM RETURNS TO LABEL TCKEYREQ020 **/ + /*----------------------------------------------------*/ + setApiConTimer(apiConnectptr.i, ctcTimer, __LINE__); + regCachePtr->save1 = Tlen; + return; + }//if + } else { + jam(); + return; + }//if + } while (1); + return; }//Dbtc::execKEYINFO() /*---------------------------------------------------------------------------*/ @@ -1826,45 +1875,45 @@ void Dbtc::execKEYINFO(Signal* signal) /* WE WILL ALWAYS PACK 4 WORDS AT A TIME. */ /*---------------------------------------------------------------------------*/ void Dbtc::packKeyData000Lab(Signal* signal, - BlockReference TBRef) + BlockReference TBRef, + Uint32 totalLen) { CacheRecord * const regCachePtr = cachePtr.p; UintR Tmp; - Uint16 tdataPos; jam(); - tdataPos = 0; - Tmp = regCachePtr->keylen; + Uint32 len = 0; databufptr.i = regCachePtr->firstKeybuf; + signal->theData[0] = tcConnectptr.i; + signal->theData[1] = apiConnectptr.p->transid[0]; + signal->theData[2] = apiConnectptr.p->transid[1]; + Uint32 * dst = signal->theData+3; + ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); + do { jam(); - if (tdataPos == 20) { - jam(); - /*---------------------------------------------------------------------*/ - /* 4 MORE WORDS WILL NOT FIT IN THE 24 DATA WORDS IN A SIGNAL */ - /*---------------------------------------------------------------------*/ - sendKeyinfo(signal, TBRef, 20); - tdataPos = 0; - }//if - Tmp = Tmp - 4; - ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); - cdata[tdataPos ] = databufptr.p->data[0]; - cdata[tdataPos + 1] = databufptr.p->data[1]; - cdata[tdataPos + 2] = databufptr.p->data[2]; - cdata[tdataPos + 3] = databufptr.p->data[3]; - tdataPos = tdataPos + 4; - if (Tmp <= 4) { + databufptr.i = databufptr.p->nextDatabuf; + dst[len + 0] = databufptr.p->data[0]; + dst[len + 1] = databufptr.p->data[1]; + dst[len + 2] = databufptr.p->data[2]; + dst[len + 3] = databufptr.p->data[3]; + len += 4; + if (totalLen <= 4) { jam(); /*---------------------------------------------------------------------*/ /* LAST PACK OF KEY DATA HAVE BEEN SENT */ /*---------------------------------------------------------------------*/ /* THERE WERE UNSENT INFORMATION, SEND IT. */ /*---------------------------------------------------------------------*/ - sendKeyinfo(signal, TBRef, tdataPos); - releaseKeys(); + sendSignal(TBRef, GSN_KEYINFO, signal, 3 + len, JBB); return; - }//if - databufptr.i = databufptr.p->nextDatabuf; + } else if(len == KeyInfo::DataLength){ + jam(); + len = 0; + sendSignal(TBRef, GSN_KEYINFO, signal, 3 + KeyInfo::DataLength, JBB); + } + totalLen -= 4; + ptrCheckGuard(databufptr, cdatabufFilesize, databufRecord); } while (1); }//Dbtc::packKeyData000Lab() @@ -2247,6 +2296,7 @@ void Dbtc::initApiConnectRec(Signal* signal, regApiPtr->m_exec_flag = 0; regApiPtr->returncode = 0; regApiPtr->returnsignal = RS_TCKEYCONF; + ndbassert(regApiPtr->firstTcConnect == RNIL); regApiPtr->firstTcConnect = RNIL; regApiPtr->lastTcConnect = RNIL; regApiPtr->globalcheckpointid = 0; @@ -2441,18 +2491,30 @@ void Dbtc::execTCKEYREQ(Signal* signal) } break; case CS_STARTED: - //------------------------------------------------------------------------ - // Transaction is started already. Check that the operation is on the same - // transaction. - //------------------------------------------------------------------------ - compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1; - compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2; - jam(); - compare_transid1 = compare_transid1 | compare_transid2; - if (compare_transid1 != 0) { - TCKEY_abort(signal, 1); - return; - }//if + if(TstartFlag == 1 && regApiPtr->firstTcConnect == RNIL) + { + /** + * If last operation in last transaction was a simple/dirty read + * it does not have to be committed or rollbacked hence, + * the state will be CS_STARTED + */ + jam(); + initApiConnectRec(signal, regApiPtr); + regApiPtr->m_exec_flag = TexecFlag; + } else { + //---------------------------------------------------------------------- + // Transaction is started already. + // Check that the operation is on the same transaction. + //----------------------------------------------------------------------- + compare_transid1 = regApiPtr->transid[0] ^ tcKeyReq->transId1; + compare_transid2 = regApiPtr->transid[1] ^ tcKeyReq->transId2; + jam(); + compare_transid1 = compare_transid1 | compare_transid2; + if (compare_transid1 != 0) { + TCKEY_abort(signal, 1); + return; + }//if + } break; case CS_ABORTING: if (regApiPtr->abortState == AS_IDLE) { @@ -2601,7 +2663,7 @@ void Dbtc::execTCKEYREQ(Signal* signal) regCachePtr->schemaVersion = TtableSchemaVersion; regTcPtr->operation = TOperationType; - // Uint8 TSimpleFlag = tcKeyReq->getSimpleFlag(Treqinfo); + Uint8 TSimpleFlag = tcKeyReq->getSimpleFlag(Treqinfo); Uint8 TDirtyFlag = tcKeyReq->getDirtyFlag(Treqinfo); Uint8 TInterpretedFlag = tcKeyReq->getInterpretedFlag(Treqinfo); Uint8 TDistrGroupFlag = tcKeyReq->getDistributionGroupFlag(Treqinfo); @@ -2609,11 +2671,9 @@ void Dbtc::execTCKEYREQ(Signal* signal) Uint8 TDistrKeyFlag = tcKeyReq->getDistributionKeyFlag(Treqinfo); Uint8 TexecuteFlag = TexecFlag; - //RONM_TEST Disable simple reads temporarily - regCachePtr->opSimple = 0; - // regCachePtr->opSimple = TSimpleFlag; - regTcPtr->dirtyOp = TDirtyFlag; + regCachePtr->opSimple = TSimpleFlag; regCachePtr->opExec = TInterpretedFlag; + regTcPtr->dirtyOp = TDirtyFlag; regCachePtr->distributionGroupIndicator = TDistrGroupFlag; regCachePtr->distributionGroupType = TDistrGroupTypeFlag; @@ -2714,7 +2774,6 @@ void Dbtc::execTCKEYREQ(Signal* signal) } } - UintR Tattrlength = regCachePtr->attrlength; UintR TwriteCount = c_counters.cwriteCount; UintR Toperationsize = coperationsize; /* -------------------------------------------------------------------- @@ -2723,13 +2782,13 @@ void Dbtc::execTCKEYREQ(Signal* signal) * TEMP TABLES DON'T PARTICIPATE. * -------------------------------------------------------------------- */ if (localTabptr.p->storedTable) { - coperationsize = ((Toperationsize + Tattrlength) + TkeyLength) + 17; + coperationsize = ((Toperationsize + TattrLen) + TkeyLength) + 17; } c_counters.cwriteCount = TwriteCount + 1; switch (TOperationType) { case ZUPDATE: jam(); - if (Tattrlength == 0) { + if (TattrLen == 0) { //TCKEY_abort(signal, 5); //return; }//if @@ -2775,7 +2834,6 @@ void Dbtc::execTCKEYREQ(Signal* signal) if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { jam(); // Trigger execution at commit - regApiPtr->apiConnectstate = CS_REC_COMMITTING; } else { jam(); @@ -2895,12 +2953,13 @@ void Dbtc::tckeyreq050Lab(Signal* signal) regTcPtr->tcNodedata[3] = Tdata6; Uint8 Toperation = regTcPtr->operation; + Uint8 Tdirty = regTcPtr->dirtyOp; tnoOfBackup = tnodeinfo & 3; tnoOfStandby = (tnodeinfo >> 8) & 3; regCachePtr->distributionKey = (tnodeinfo >> 16) & 255; if (Toperation == ZREAD) { - if (regCachePtr->opSimple == 1) { + if (Tdirty == 1) { jam(); /*-------------------------------------------------------------*/ /* A SIMPLE READ CAN SELECT ANY OF THE PRIMARY AND */ @@ -2910,23 +2969,28 @@ void Dbtc::tckeyreq050Lab(Signal* signal) /*-------------------------------------------------------------*/ arrGuard(tnoOfBackup, 4); UintR Tindex; + UintR TownNode = cownNodeid; for (Tindex = 1; Tindex <= tnoOfBackup; Tindex++) { UintR Tnode = regTcPtr->tcNodedata[Tindex]; - UintR TownNode = cownNodeid; jam(); if (Tnode == TownNode) { jam(); regTcPtr->tcNodedata[0] = Tnode; }//if }//for - if (regCachePtr->attrlength == 0) { - /*-------------------------------------------------------------*/ - // A simple read which does not read anything is a strange - // creature and we abort rather than continue. - /*-------------------------------------------------------------*/ - TCKEY_abort(signal, 12); - return; - }//if + if(ERROR_INSERTED(8048) || ERROR_INSERTED(8049)) + { + for (Tindex = 0; Tindex <= tnoOfBackup; Tindex++) + { + UintR Tnode = regTcPtr->tcNodedata[Tindex]; + jam(); + if (Tnode != TownNode) { + jam(); + regTcPtr->tcNodedata[0] = Tnode; + ndbout_c("Choosing %d", Tnode); + }//if + }//for + } }//if jam(); regTcPtr->lastReplicaNo = 0; @@ -3014,7 +3078,8 @@ void Dbtc::packLqhkeyreq(Signal* signal, UintR TfirstAttrbuf = regCachePtr->firstAttrbuf; sendlqhkeyreq(signal, TBRef); if (Tkeylen > 4) { - packKeyData000Lab(signal, TBRef); + packKeyData000Lab(signal, TBRef, Tkeylen - 4); + releaseKeys(); }//if packLqhkeyreq040Lab(signal, TfirstAttrbuf, @@ -3235,7 +3300,7 @@ void Dbtc::packLqhkeyreq040Lab(Signal* signal, releaseAttrinfo(); if (Tboth) { jam(); - releaseSimpleRead(signal); + releaseSimpleRead(signal, apiConnectptr, tcConnectptr.p); return; }//if regTcPtr->tcConnectstate = OS_OPERATING; @@ -3297,8 +3362,21 @@ void Dbtc::releaseAttrinfo() /* ========================================================================= */ /* ------- RELEASE ALL RECORDS CONNECTED TO A SIMPLE OPERATION ------- */ /* ========================================================================= */ -void Dbtc::releaseSimpleRead(Signal* signal) -{ +void Dbtc::releaseSimpleRead(Signal* signal, + ApiConnectRecordPtr regApiPtr, + TcConnectRecord* regTcPtr) +{ + Uint32 Ttckeyrec = regApiPtr.p->tckeyrec; + Uint32 TclientData = regTcPtr->clientData; + Uint32 Tnode = regTcPtr->tcNodedata[0]; + Uint32 Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; + Uint32 TsimpleReadCount = c_counters.csimpleReadCount; + ConnectionState state = regApiPtr.p->apiConnectstate; + + regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; + regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::SimpleReadBit | Tnode; + regApiPtr.p->tckeyrec = Ttckeyrec + 2; + unlinkReadyTcCon(signal); releaseTcCon(); @@ -3306,31 +3384,27 @@ void Dbtc::releaseSimpleRead(Signal* signal) * No LQHKEYCONF in Simple/Dirty read * Therefore decrese no LQHKEYCONF(REF) we are waiting for */ - ApiConnectRecord * const regApiPtr = apiConnectptr.p; - UintR TsimpleReadCount = c_counters.csimpleReadCount; - UintR Tlqhkeyreqrec = regApiPtr->lqhkeyreqrec; - c_counters.csimpleReadCount = TsimpleReadCount + 1; - regApiPtr->lqhkeyreqrec = Tlqhkeyreqrec - 1; - - /** - * If start committing and no operation in lists - * simply return - */ - if (regApiPtr->apiConnectstate == CS_START_COMMITTING && - regApiPtr->firstTcConnect == RNIL) { + regApiPtr.p->lqhkeyreqrec = --Tlqhkeyreqrec; + + if(Tlqhkeyreqrec == 0) + { + /** + * Special case of lqhKeyConf_checkTransactionState: + * - commit with zero operations: handle only for simple read + */ + sendtckeyconf(signal, state == CS_START_COMMITTING); + regApiPtr.p->apiConnectstate = + (state == CS_START_COMMITTING ? CS_CONNECTED : state); + setApiConTimer(regApiPtr.i, 0, __LINE__); - jam(); - setApiConTimer(apiConnectptr.i, 0, __LINE__); - regApiPtr->apiConnectstate = CS_CONNECTED; return; - }//if - + } + /** - * Else Emulate LQHKEYCONF + * Emulate LQHKEYCONF */ - lqhKeyConf_checkTransactionState(signal, regApiPtr); - + lqhKeyConf_checkTransactionState(signal, regApiPtr.p); }//Dbtc::releaseSimpleRead() /* ------------------------------------------------------------------------- */ @@ -3766,6 +3840,15 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, void Dbtc::sendtckeyconf(Signal* signal, UintR TcommitFlag) { + if(ERROR_INSERTED(8049)){ + CLEAR_ERROR_INSERT_VALUE; + signal->theData[0] = TcContinueB::DelayTCKEYCONF; + signal->theData[1] = apiConnectptr.i; + signal->theData[2] = TcommitFlag; + sendSignalWithDelay(cownref, GSN_CONTINUEB, signal, 3000, 3); + return; + } + HostRecordPtr localHostptr; ApiConnectRecord * const regApiPtr = apiConnectptr.p; const UintR TopWords = (UintR)regApiPtr->tckeyrec; @@ -5024,27 +5107,15 @@ void Dbtc::execLQHKEYREF(Signal* signal) *---------------------------------------------------------------------*/ regApiPtr->lqhkeyreqrec--; if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) { - if ((regApiPtr->lqhkeyconfrec == 0) && - (regApiPtr->apiConnectstate == CS_START_COMMITTING)) { - - if(abort == TcKeyReq::IgnoreError){ + if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { + if(regApiPtr->lqhkeyconfrec) { jam(); - regApiPtr->returnsignal = RS_NO_RETURN; - abort010Lab(signal); - return; + diverify010Lab(signal); + } else { + jam(); + sendtckeyconf(signal, 1); + regApiPtr->apiConnectstate = CS_CONNECTED; } - - /*---------------------------------------------------------------- - * Not a single operation was successful. - * This we report as an aborted transaction - * to avoid performing a commit of zero operations. - *----------------------------------------------------------------*/ - TCKEY_abort(signal, 54); - return; - }//if - if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { - jam(); - diverify010Lab(signal); return; } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) { jam(); @@ -6045,6 +6116,7 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr) << " - place: " << c_apiConTimer_line[apiConnectptr.i]); switch (apiConnectptr.p->apiConnectstate) { case CS_STARTED: + ndbrequire(c_apiConTimer_line[apiConnectptr.i] != 3615); if(apiConnectptr.p->lqhkeyreqrec == apiConnectptr.p->lqhkeyconfrec){ jam(); /* @@ -6297,8 +6369,8 @@ void Dbtc::sendAbortedAfterTimeout(Signal* signal, int Tcheck) snprintf(buf, sizeof(buf), "TC %d: %d ops:", __LINE__, apiConnectptr.i); for(Uint32 i = 0; i<TloopCount; i++){ - snprintf(buf2, sizeof(buf2), "%s %d", buf, tmp[i]); - snprintf(buf, sizeof(buf), buf2); + BaseString::snprintf(buf2, sizeof(buf2), "%s %d", buf, tmp[i]); + BaseString::snprintf(buf, sizeof(buf), buf2); } warningEvent(buf); ndbout_c(buf); @@ -8406,7 +8478,8 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) { const ScanTabReq * const scanTabReq = (ScanTabReq *)&signal->theData[0]; const Uint32 reqinfo = scanTabReq->requestInfo; - const Uint32 aiLength = scanTabReq->attrLen; + const Uint32 aiLength = (scanTabReq->attrLenKeyLen & 0xFFFF); + const Uint32 keyLen = scanTabReq->attrLenKeyLen >> 16; const Uint32 schemaVersion = scanTabReq->tableSchemaVersion; const Uint32 transid1 = scanTabReq->transId1; const Uint32 transid2 = scanTabReq->transId2; @@ -8444,6 +8517,10 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) if (transP->apiConnectstate == CS_ABORTING && transP->abortState == AS_IDLE) { jam(); + } else if(transP->apiConnectstate == CS_STARTED && + transP->firstTcConnect == RNIL){ + jam(); + // left over from simple/dirty read } else { jam(); errCode = ZSTATE_ERROR; @@ -8480,8 +8557,12 @@ void Dbtc::execSCAN_TABREQ(Signal* signal) seizeTcConnect(signal); tcConnectptr.p->apiConnect = apiConnectptr.i; + tcConnectptr.p->tcConnectstate = OS_WAIT_SCAN; + apiConnectptr.p->lastTcConnect = tcConnectptr.i; seizeCacheRecord(signal); + cachePtr.p->keylen = keyLen; + cachePtr.p->save1 = 0; scanptr = seizeScanrec(signal); ndbrequire(transP->apiScanRec == RNIL); @@ -8558,21 +8639,27 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, UintR scanParallel, UintR noOprecPerFrag) { - const UintR reqinfo = scanTabReq->requestInfo; - scanptr.p->scanTcrec = tcConnectptr.i; scanptr.p->scanApiRec = apiConnectptr.i; - scanptr.p->scanAiLength = scanTabReq->attrLen; + scanptr.p->scanAiLength = scanTabReq->attrLenKeyLen & 0xFFFF; + scanptr.p->scanKeyLen = scanTabReq->attrLenKeyLen >> 16; scanptr.p->scanTableref = tabptr.i; scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion; scanptr.p->scanParallel = scanParallel; scanptr.p->noOprecPerFrag = noOprecPerFrag; scanptr.p->first_batch_size= scanTabReq->first_batch_size; scanptr.p->batch_byte_size= scanTabReq->batch_byte_size; - scanptr.p->scanLockMode = ScanTabReq::getLockMode(reqinfo); - scanptr.p->scanLockHold = ScanTabReq::getHoldLockFlag(reqinfo); - scanptr.p->readCommitted = ScanTabReq::getReadCommittedFlag(reqinfo); - scanptr.p->rangeScan = ScanTabReq::getRangeScanFlag(reqinfo); + + Uint32 tmp = 0; + const UintR ri = scanTabReq->requestInfo; + ScanFragReq::setLockMode(tmp, ScanTabReq::getLockMode(ri)); + ScanFragReq::setHoldLockFlag(tmp, ScanTabReq::getHoldLockFlag(ri)); + ScanFragReq::setKeyinfoFlag(tmp, ScanTabReq::getKeyinfoFlag(ri)); + ScanFragReq::setReadCommittedFlag(tmp,ScanTabReq::getReadCommittedFlag(ri)); + ScanFragReq::setRangeScanFlag(tmp, ScanTabReq::getRangeScanFlag(ri)); + ScanFragReq::setAttrLen(tmp, scanTabReq->attrLenKeyLen & 0xFFFF); + + scanptr.p->scanRequestInfo = tmp; scanptr.p->scanStoredProcId = scanTabReq->storedProcId; scanptr.p->scanState = ScanRecord::RUNNING; scanptr.p->m_queued_count = 0; @@ -8589,7 +8676,7 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, ptr.p->m_apiPtr = cdata[i]; }//for - (* (scanptr.p->rangeScan ? + (* (ScanTabReq::getRangeScanFlag(ri) ? &c_counters.c_range_scan_count : &c_counters.c_scan_count))++; }//Dbtc::initScanrec() @@ -8807,6 +8894,7 @@ void Dbtc::releaseScanResources(ScanRecordPtr scanPtr) if (apiConnectptr.p->cachePtr != RNIL) { cachePtr.i = apiConnectptr.p->cachePtr; ptrCheckGuard(cachePtr, ccacheFilesize, cacheRecord); + releaseKeys(); releaseAttrinfo(); }//if tcConnectptr.i = scanPtr.p->scanTcrec; @@ -9448,17 +9536,8 @@ void Dbtc::sendScanFragReq(Signal* signal, ScanRecord* scanP, ScanFragRec* scanFragP) { - Uint32 requestInfo = 0; ScanFragReq * const req = (ScanFragReq *)&signal->theData[0]; - ScanFragReq::setLockMode(requestInfo, scanP->scanLockMode); - ScanFragReq::setHoldLockFlag(requestInfo, scanP->scanLockHold); - if(scanP->scanLockMode == 1){ // Not read -> keyinfo - jam(); - ScanFragReq::setKeyinfoFlag(requestInfo, 1); - } - ScanFragReq::setReadCommittedFlag(requestInfo, scanP->readCommitted); - ScanFragReq::setRangeScanFlag(requestInfo, scanP->rangeScan); - ScanFragReq::setAttrLen(requestInfo, scanP->scanAiLength); + Uint32 requestInfo = scanP->scanRequestInfo; ScanFragReq::setScanPrio(requestInfo, 1); apiConnectptr.i = scanP->scanApiRec; req->tableId = scanP->scanTableref; @@ -9466,7 +9545,7 @@ void Dbtc::sendScanFragReq(Signal* signal, ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); req->senderData = scanFragptr.i; req->requestInfo = requestInfo; - req->fragmentNo = scanFragP->scanFragId; + req->fragmentNoKeyLen = scanFragP->scanFragId | (scanP->scanKeyLen << 16); req->resultRef = apiConnectptr.p->ndbapiBlockref; req->savePointId = apiConnectptr.p->currSavePointId; req->transId1 = apiConnectptr.p->transid[0]; @@ -9476,6 +9555,11 @@ void Dbtc::sendScanFragReq(Signal* signal, req->batch_size_bytes= scanP->batch_byte_size; sendSignal(scanFragP->lqhBlockref, GSN_SCAN_FRAGREQ, signal, ScanFragReq::SignalLength, JBB); + if(scanP->scanKeyLen > 0) + { + tcConnectptr.i = scanFragptr.i; + packKeyData000Lab(signal, scanFragP->lqhBlockref, scanP->scanKeyLen); + } updateBuddyTimer(apiConnectptr); scanFragP->startFragTimer(ctcTimer); }//Dbtc::sendScanFragReq() @@ -9586,6 +9670,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -9612,6 +9697,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -9638,6 +9724,7 @@ void Dbtc::initApiConnect(Signal* signal) apiConnectptr.p->ndbapiBlockref = 0xFFFFFFFF; // Invalid ref apiConnectptr.p->commitAckMarker = RNIL; apiConnectptr.p->firstTcConnect = RNIL; + apiConnectptr.p->lastTcConnect = RNIL; apiConnectptr.p->triggerPending = false; apiConnectptr.p->isIndexOp = false; apiConnectptr.p->accumulatingIndexOp = RNIL; @@ -10422,9 +10509,6 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) sp.p->scanSchemaVersion, sp.p->scanTableref, sp.p->scanStoredProcId); - infoEvent(" lhold=%d, lmode=%d", - sp.p->scanLockHold, - sp.p->scanLockMode); infoEvent(" apiRec=%d, next=%d", sp.p->scanApiRec, sp.p->nextScan); @@ -10995,9 +11079,11 @@ void Dbtc::execTCINDXREQ(Signal* signal) // Seize index operation TcIndexOperationPtr indexOpPtr; if ((startFlag == 1) && - ((regApiPtr->apiConnectstate == CS_CONNECTED) || - ((regApiPtr->apiConnectstate == CS_ABORTING) && - (regApiPtr->abortState == AS_IDLE)))) { + (regApiPtr->apiConnectstate == CS_CONNECTED || + (regApiPtr->apiConnectstate == CS_STARTED && + regApiPtr->firstTcConnect == RNIL)) || + (regApiPtr->apiConnectstate == CS_ABORTING && + regApiPtr->abortState == AS_IDLE)) { jam(); // This is a newly started transaction, clean-up releaseAllSeizedIndexOperations(regApiPtr); @@ -11652,7 +11738,7 @@ void Dbtc::readIndexTable(Signal* signal, tcKeyLength += MIN(keyLength, keyBufSize); tcKeyReq->tableSchemaVersion = indexOp->tcIndxReq.indexSchemaVersion; TcKeyReq::setOperationType(tcKeyRequestInfo, - opType == ZREAD ? opType : ZREAD_EX); + opType == ZREAD ? ZREAD : ZREAD_EX); TcKeyReq::setAIInTcKeyReq(tcKeyRequestInfo, 1); // Allways send one AttrInfo TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); BlockReference originalReceiver = regApiPtr->ndbapiBlockref; @@ -11677,6 +11763,9 @@ void Dbtc::readIndexTable(Signal* signal, AttributeHeader::init(dataPtr, indexData->primaryKeyPos, 0); tcKeyLength++; tcKeyReq->requestInfo = tcKeyRequestInfo; + + ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); + ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); EXECUTE_DIRECT(DBTC, GSN_TCKEYREQ, signal, tcKeyLength); /** @@ -11828,6 +11917,9 @@ void Dbtc::executeIndexOperation(Signal* signal, TcKeyReq::setExecutingTrigger(tcKeyRequestInfo, 0); tcKeyReq->requestInfo = tcKeyRequestInfo; + ndbassert(TcKeyReq::getDirtyFlag(tcKeyRequestInfo) == 0); + ndbassert(TcKeyReq::getSimpleFlag(tcKeyRequestInfo) == 0); + /** * Decrease lqhkeyreqrec to compensate for addition * during read of index table diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index 0e8dd5fbbe8..55ad1d0910a 100644 --- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -35,14 +35,6 @@ #define ZMIN_PAGE_LIMIT_TUPKEYREQ 5 #define ZTUP_VERSION_BITS 15 -typedef bool (Dbtup::* ReadFunction)(Uint32*, - AttributeHeader*, - Uint32, - Uint32); -typedef bool (Dbtup::* UpdateFunction)(Uint32*, - Uint32, - Uint32); - #ifdef DBTUP_C //------------------------------------------------------------------ // Jam Handling: @@ -351,6 +343,14 @@ typedef bool (Dbtup::* UpdateFunction)(Uint32*, class Dbtup: public SimulatedBlock { public: + + typedef bool (Dbtup::* ReadFunction)(Uint32*, + AttributeHeader*, + Uint32, + Uint32); + typedef bool (Dbtup::* UpdateFunction)(Uint32*, + Uint32, + Uint32); // State values enum State { NOT_INITIALIZED = 0, diff --git a/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp b/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp index a50bb2fe52c..808cfd33696 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp @@ -353,11 +353,11 @@ operator<<(NdbOut& out, const Dbtup::Operationrec& op) out << " [interpretedExec " << dec << op.interpretedExec << "]"; out << " [opSimple " << dec << op.opSimple << "]"; // state - out << " [tupleState " << dec << op.tupleState << "]"; - out << " [transstate " << dec << op.transstate << "]"; + out << " [tupleState " << dec << (Uint32) op.tupleState << "]"; + out << " [transstate " << dec << (Uint32) op.transstate << "]"; out << " [inFragList " << dec << op.inFragList << "]"; out << " [inActiveOpList " << dec << op.inActiveOpList << "]"; - out << " [undoLogged " << dec << op.undoLogged << "]"; + out << " [undoLogged " << dec << (Uint32) op.undoLogged << "]"; // links out << " [prevActiveOp " << hex << op.prevActiveOp << "]"; out << " [nextActiveOp " << hex << op.nextActiveOp << "]"; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 0061ebe812d..49de0d80bcd 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -893,19 +893,19 @@ int Dbtup::handleReadReq(Signal* signal, if (regOperPtr->interpretedExec != 1) { jam(); - - Uint32 TnoOfDataRead = readAttributes(pagePtr, - Ttupheadoffset, - &cinBuffer[0], - regOperPtr->attrinbufLen, - dst, - dstLen, - false); - if (TnoOfDataRead != (Uint32)-1) { + int ret = readAttributes(pagePtr, + Ttupheadoffset, + &cinBuffer[0], + regOperPtr->attrinbufLen, + dst, + dstLen, + false); + if (ret != -1) { /* ------------------------------------------------------------------------- */ // We have read all data into coutBuffer. Now send it to the API. /* ------------------------------------------------------------------------- */ jam(); + Uint32 TnoOfDataRead= (Uint32) ret; regOperPtr->attroutbufLen = TnoOfDataRead; sendReadAttrinfo(signal, TnoOfDataRead, regOperPtr); return 0; @@ -1100,7 +1100,7 @@ Dbtup::updateStartLab(Signal* signal, Tablerec* const regTabPtr, Page* const pagePtr) { - Uint32 retValue; + int retValue; if (regOperPtr->optype == ZINSERT) { jam(); setNullBits(pagePtr, regTabPtr, regOperPtr->pageOffset); @@ -1111,7 +1111,7 @@ Dbtup::updateStartLab(Signal* signal, regOperPtr->pageOffset, &cinBuffer[0], regOperPtr->attrinbufLen); - if (retValue == (Uint32)-1) { + if (retValue == -1) { tupkeyErrorLab(signal); }//if } else { @@ -1215,7 +1215,7 @@ int Dbtup::interpreterStartLab(Signal* signal, { Operationrec * const regOperPtr = operPtr.p; Uint32 RtotalLen; - Uint32 TnoDataRW; + int TnoDataRW; Uint32 RinitReadLen = cinBuffer[0]; Uint32 RexecRegionLen = cinBuffer[1]; @@ -1273,7 +1273,7 @@ int Dbtup::interpreterStartLab(Signal* signal, &dst[0], dstLen, false); - if (TnoDataRW != (Uint32)-1) { + if (TnoDataRW != -1) { RattroutCounter = TnoDataRW; RinstructionCounter += RinitReadLen; } else { @@ -1300,7 +1300,7 @@ int Dbtup::interpreterStartLab(Signal* signal, RsubLen, &coutBuffer[0], sizeof(coutBuffer) / 4); - if (TnoDataRW != (Uint32)-1) { + if (TnoDataRW != -1) { RinstructionCounter += RexecRegionLen; RlogSize = TnoDataRW; } else { @@ -1319,7 +1319,7 @@ int Dbtup::interpreterStartLab(Signal* signal, TupHeadOffset, &cinBuffer[RinstructionCounter], RfinalUpdateLen); - if (TnoDataRW != (Uint32)-1) { + if (TnoDataRW != -1) { MEMCOPY_NO_WORDS(&clogMemBuffer[RlogSize], &cinBuffer[RinstructionCounter], RfinalUpdateLen); @@ -1347,7 +1347,7 @@ int Dbtup::interpreterStartLab(Signal* signal, &dst[RattroutCounter], (dstLen - RattroutCounter), false); - if (TnoDataRW != (Uint32)-1) { + if (TnoDataRW != -1) { RattroutCounter += TnoDataRW; } else { jam(); @@ -1480,14 +1480,13 @@ int Dbtup::interpreterNextLab(Signal* signal, /* ---------------------------------------------------------------- */ { Uint32 theAttrinfo = theInstruction; - Uint32 TnoDataRW; - TnoDataRW = readAttributes(pagePtr, - TupHeadOffset, - &theAttrinfo, - (Uint32)1, - &TregMemBuffer[theRegister], - (Uint32)3, - false); + int TnoDataRW= readAttributes(pagePtr, + TupHeadOffset, + &theAttrinfo, + (Uint32)1, + &TregMemBuffer[theRegister], + (Uint32)3, + false); if (TnoDataRW == 2) { /* ------------------------------------------------------------- */ // Two words read means that we get the instruction plus one 32 @@ -1511,7 +1510,7 @@ int Dbtup::interpreterNextLab(Signal* signal, TregMemBuffer[theRegister] = 0; TregMemBuffer[theRegister + 2] = 0; TregMemBuffer[theRegister + 3] = 0; - } else if (TnoDataRW == (Uint32)-1) { + } else if (TnoDataRW == -1) { jam(); tupkeyErrorLab(signal); return -1; @@ -1564,12 +1563,11 @@ int Dbtup::interpreterNextLab(Signal* signal, ah.setNULL(); Tlen = 1; }//if - Uint32 TnoDataRW; - TnoDataRW = updateAttributes(pagePtr, - TupHeadOffset, - &TdataForUpdate[0], - Tlen); - if (TnoDataRW != (Uint32)-1) { + int TnoDataRW= updateAttributes(pagePtr, + TupHeadOffset, + &TdataForUpdate[0], + Tlen); + if (TnoDataRW != -1) { /* --------------------------------------------------------- */ // Write the written data also into the log buffer so that it // will be logged. diff --git a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp index 2dd707ebafc..5a8642c4d2e 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp @@ -166,7 +166,7 @@ Dbtup::tuxReadAttrs(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32 tu fragptr = fragptr_old; operPtr = operPtr_old; // done - if (ret == (Uint32)-1) { + if (ret == -1) { ret = terrorCode ? (-(int)terrorCode) : -1; } return ret; @@ -200,13 +200,14 @@ Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* data operPtr.i = RNIL; operPtr.p = NULL; // do it - int ret = readAttributes(pagePtr.p, pageOffset, attrIds, numAttrs, dataOut, ZNIL, true); + int ret = readAttributes(pagePtr.p, pageOffset, attrIds, + numAttrs, dataOut, ZNIL, true); // restore globals tabptr = tabptr_old; fragptr = fragptr_old; operPtr = operPtr_old; // done - if (ret != (Uint32)-1) { + if (ret != -1) { // remove headers Uint32 n = 0; Uint32 i = 0; @@ -220,7 +221,7 @@ Dbtup::tuxReadPk(Uint32 fragPtrI, Uint32 pageId, Uint32 pageOffset, Uint32* data n += 1; i += 1 + size; } - ndbrequire(i == ret); + ndbrequire((int)i == ret); ret -= numAttrs; } else { ret = terrorCode ? (-(int)terrorCode) : -1; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp b/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp index f8f2b9bdbd2..370ef4c4ba5 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupLCP.cpp @@ -265,7 +265,8 @@ void Dbtup::lcpSaveCopyListLab(Signal* signal, CheckpointInfoPtr ciPtr) // We ensure that we have actually allocated the tuple header and // also found it. Otherwise we will fill the undo log with garbage. /* ---------------------------------------------------------------- */ - if (regOpPtr.p->optype == ZUPDATE) { + if (regOpPtr.p->optype == ZUPDATE || + (regOpPtr.p->optype == ZINSERT && regOpPtr.p->deleteInsertFlag)) { ljam(); if (regOpPtr.p->realPageIdC != RNIL) { /* ---------------------------------------------------------------- */ diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index a4e7cb47249..e6cc6f68842 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -156,12 +156,12 @@ Dbtup::setUpQueryRoutines(Tablerec* const regTabPtr) // tabptr.p Table record pointer /* ---------------------------------------------------------------- */ int Dbtup::readAttributes(Page* const pagePtr, - Uint32 tupHeadOffset, - const Uint32* inBuffer, - Uint32 inBufLen, - Uint32* outBuffer, - Uint32 maxRead, - bool xfrmFlag) + Uint32 tupHeadOffset, + const Uint32* inBuffer, + Uint32 inBufLen, + Uint32* outBuffer, + Uint32 maxRead, + bool xfrmFlag) { Tablerec* const regTabPtr = tabptr.p; Uint32 numAttributes = regTabPtr->noOfAttr; @@ -198,7 +198,7 @@ int Dbtup::readAttributes(Page* const pagePtr, attributeOffset)) { continue; } else { - return (Uint32)-1; + return -1; }//if } else if(attributeId & AttributeHeader::PSUEDO){ Uint32 sz = read_psuedo(attributeId, @@ -207,7 +207,7 @@ int Dbtup::readAttributes(Page* const pagePtr, tOutBufIndex = tmpAttrBufIndex + 1 + sz; } else { terrorCode = ZATTRIBUTE_ID_ERROR; - return (Uint32)-1; + return -1; }//if }//while return tOutBufIndex; @@ -256,11 +256,11 @@ int Dbtup::readAttributesWithoutHeader(Page* const pagePtr, attributeOffset)) { continue; } else { - return (Uint32)-1; + return -1; }//if } else { terrorCode = ZATTRIBUTE_ID_ERROR; - return (Uint32)-1; + return -1; }//if }//while ndbrequire(attrBufIndex == inBufLen); @@ -678,12 +678,12 @@ int Dbtup::updateAttributes(Page* const pagePtr, continue; } else { ljam(); - return (Uint32)-1; + return -1; }//if } else { ljam(); terrorCode = ZATTRIBUTE_ID_ERROR; - return (Uint32)-1; + return -1; }//if }//while return 0; diff --git a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp index c0b49364ee6..aac5c326cad 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp @@ -652,6 +652,7 @@ void Dbtup::executeTrigger(Signal* signal, return; default: ndbrequire(false); + executeDirect= false; // remove warning }//switch regOperPtr->noFiredTriggers++; @@ -746,14 +747,15 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, //-------------------------------------------------------------------- // Read Primary Key Values //-------------------------------------------------------------------- - noPrimKey = readAttributes(pagep.p, - tupheadoffset, - &tableDescriptor[regTabPtr->readKeyArray].tabDescr, - regTabPtr->noOfKeyAttr, - keyBuffer, - ZATTR_BUFFER_SIZE, - true); - ndbrequire(noPrimKey != (Uint32)-1); + int ret= readAttributes(pagep.p, + tupheadoffset, + &tableDescriptor[regTabPtr->readKeyArray].tabDescr, + regTabPtr->noOfKeyAttr, + keyBuffer, + ZATTR_BUFFER_SIZE, + true); + ndbrequire(ret != -1); + noPrimKey= ret; Uint32 numAttrsToRead; if ((regOperPtr->optype == ZUPDATE) && @@ -788,14 +790,15 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, if ((regOperPtr->optype != ZDELETE) || (trigPtr->sendBeforeValues)) { ljam(); - noMainWords = readAttributes(pagep.p, - tupheadoffset, - &readBuffer[0], - numAttrsToRead, - mainBuffer, - ZATTR_BUFFER_SIZE, - true); - ndbrequire(noMainWords != (Uint32)-1); + int ret= readAttributes(pagep.p, + tupheadoffset, + &readBuffer[0], + numAttrsToRead, + mainBuffer, + ZATTR_BUFFER_SIZE, + true); + ndbrequire(ret != -1); + noMainWords= ret; } else { ljam(); noMainWords = 0; @@ -813,15 +816,16 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, pagep.i = regOperPtr->realPageIdC; ptrCheckGuard(pagep, cnoOfPage, page); - noCopyWords = readAttributes(pagep.p, - tupheadoffset, - &readBuffer[0], - numAttrsToRead, - copyBuffer, - ZATTR_BUFFER_SIZE, - true); + int ret= readAttributes(pagep.p, + tupheadoffset, + &readBuffer[0], + numAttrsToRead, + copyBuffer, + ZATTR_BUFFER_SIZE, + true); - ndbrequire(noCopyWords != (Uint32)-1); + ndbrequire(ret != -1); + noCopyWords = ret; if ((noMainWords == noCopyWords) && (memcmp(mainBuffer, copyBuffer, noMainWords << 2) == 0)) { //-------------------------------------------------------------------- @@ -1074,6 +1078,7 @@ Dbtup::executeTuxCommitTriggers(Signal* signal, ndbrequire(tupVersion == regOperPtr->tupVersion); } else { ndbrequire(false); + tupVersion= 0; // remove warning } // fill in constant part req->tableId = regOperPtr->tableRef; @@ -1118,6 +1123,7 @@ Dbtup::executeTuxAbortTriggers(Signal* signal, return; } else { ndbrequire(false); + tupVersion= 0; // remove warning } // fill in constant part req->tableId = regOperPtr->tableRef; diff --git a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp index 8dca52cec04..2b4c86e1394 100644 --- a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp +++ b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp @@ -32,7 +32,6 @@ // signal classes #include <signaldata/DictTabInfo.hpp> #include <signaldata/TuxContinueB.hpp> -#include <signaldata/BuildIndx.hpp> #include <signaldata/TupFrag.hpp> #include <signaldata/AlterIndx.hpp> #include <signaldata/DropTab.hpp> @@ -172,12 +171,21 @@ private: * Physical tuple address in TUP. Provides fast access to table tuple * or index node. Valid within the db node and across timeslices. * Not valid between db nodes or across restarts. + * + * To avoid wasting an Uint16 the pageid is split in two. */ struct TupLoc { - Uint32 m_pageId; // page i-value + private: + Uint16 m_pageId1; // page i-value (big-endian) + Uint16 m_pageId2; Uint16 m_pageOffset; // page offset in words + public: TupLoc(); TupLoc(Uint32 pageId, Uint16 pageOffset); + Uint32 getPageId() const; + void setPageId(Uint32 pageId); + Uint32 getPageOffset() const; + void setPageOffset(Uint32 pageOffset); bool operator==(const TupLoc& loc) const; bool operator!=(const TupLoc& loc) const; }; @@ -224,20 +232,15 @@ private: * work entry part 5 * * There are 3 links to other nodes: left child, right child, parent. - * These are in TupLoc format but the pageIds and pageOffsets are - * stored in separate arrays (saves 1 word). - * * Occupancy (number of entries) is at least 1 except temporarily when - * a node is about to be removed. If occupancy is 1, only max entry - * is present but both min and max prefixes are set. + * a node is about to be removed. */ struct TreeNode; friend struct TreeNode; struct TreeNode { - Uint32 m_linkPI[3]; // link to 0-left child 1-right child 2-parent - Uint16 m_linkPO[3]; // page offsets for above real page ids + TupLoc m_link[3]; // link to 0-left child 1-right child 2-parent unsigned m_side : 2; // we are 0-left child 1-right child 2-root - int m_balance : 2; // balance -1, 0, +1 + unsigned m_balance : 2; // balance -1, 0, +1 plus 1 for Solaris CC unsigned pad1 : 4; Uint8 m_occup; // current number of entries Uint32 m_nodeScan; // list of scans at this node @@ -246,8 +249,8 @@ private: static const unsigned NodeHeadSize = sizeof(TreeNode) >> 2; /* - * Tree nodes are not always accessed fully, for cache reasons. There - * are 3 access sizes. + * Tree node "access size" was for an early version with signal + * interface to TUP. It is now used only to compute sizes. */ enum AccSize { AccNone = 0, @@ -280,7 +283,7 @@ private: * m_occup), and whether the position is at an existing entry or * before one (if any). Position m_occup points past the node and is * also represented by position 0 of next node. Includes direction - * and copy of entry used by scan. + * used by scan. */ struct TreePos; friend struct TreePos; @@ -288,8 +291,7 @@ private: TupLoc m_loc; // physical node address Uint16 m_pos; // position 0 to m_occup Uint8 m_match; // at an existing entry - Uint8 m_dir; // from link (0-2) or within node (3) - TreeEnt m_ent; // copy of current entry + Uint8 m_dir; // see scanNext() TreePos(); }; @@ -370,6 +372,10 @@ private: * a separate lock wait flag. It may be for current entry or it may * be for an entry we were moved away from. In any case nothing * happens with current entry before lock wait flag is cleared. + * + * An unfinished scan is always linked to some tree node, and has + * current position and direction (see comments at scanNext). There + * is also a copy of latest entry found. */ struct ScanOp; friend struct ScanOp; @@ -398,8 +404,6 @@ private: Uint32 m_savePointId; // lock waited for or obtained and not yet passed to LQH Uint32 m_accLockOp; - // locks obtained and passed to LQH but not yet returned by LQH - Uint32 m_accLockOps[MaxAccLockOps]; Uint8 m_readCommitted; // no locking Uint8 m_lockMode; Uint8 m_keyInfo; @@ -408,13 +412,20 @@ private: ScanBound* m_bound[2]; // pointers to above 2 Uint16 m_boundCnt[2]; // number of bounds in each TreePos m_scanPos; // position - TreeEnt m_lastEnt; // last entry returned + TreeEnt m_scanEnt; // latest entry found Uint32 m_nodeScan; // next scan at node (single-linked) union { Uint32 nextPool; Uint32 nextList; }; Uint32 prevList; + /* + * Locks obtained and passed to LQH but not yet returned by LQH. + * The max was increased from 16 to 992 (default 64). Record max + * ever used in this scan. TODO fix quadratic behaviour + */ + Uint32 m_maxAccLockOps; + Uint32 m_accLockOps[MaxAccLockOps]; ScanOp(ScanBoundPool& scanBoundPool); }; typedef Ptr<ScanOp> ScanOpPtr; @@ -471,7 +482,7 @@ private: Uint16 m_numAttrs; bool m_storeNullKey; TreeHead m_tree; - TupLoc m_freeLoc; // one node pre-allocated for insert + TupLoc m_freeLoc; // list of free index nodes DLList<ScanOp> m_scanList; // current scans on this fragment Uint32 m_tupIndexFragPtrI; Uint32 m_tupTableFragPtrI[2]; @@ -515,7 +526,6 @@ private: Frag& m_frag; // fragment using the node TupLoc m_loc; // physical node address TreeNode* m_node; // pointer to node storage - AccSize m_acc; // accessed size NodeHandle(Frag& frag); NodeHandle(const NodeHandle& node); NodeHandle& operator=(const NodeHandle& node); @@ -576,18 +586,24 @@ private: * DbtuxNode.cpp */ int allocNode(Signal* signal, NodeHandle& node); - void accessNode(Signal* signal, NodeHandle& node, AccSize acc); - void selectNode(Signal* signal, NodeHandle& node, TupLoc loc, AccSize acc); - void insertNode(Signal* signal, NodeHandle& node, AccSize acc); - void deleteNode(Signal* signal, NodeHandle& node); - void setNodePref(Signal* signal, NodeHandle& node); + void selectNode(NodeHandle& node, TupLoc loc); + void insertNode(NodeHandle& node); + void deleteNode(NodeHandle& node); + void setNodePref(NodeHandle& node); // node operations - void nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt& ent); - void nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent); - void nodePushDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent); - void nodePopUp(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent); - void nodeSlide(Signal* signal, NodeHandle& dstNode, NodeHandle& srcNode, unsigned i); + void nodePushUp(NodeHandle& node, unsigned pos, const TreeEnt& ent, Uint32 scanList); + void nodePushUpScans(NodeHandle& node, unsigned pos); + void nodePopDown(NodeHandle& node, unsigned pos, TreeEnt& en, Uint32* scanList); + void nodePopDownScans(NodeHandle& node, unsigned pos); + void nodePushDown(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32& scanList); + void nodePushDownScans(NodeHandle& node, unsigned pos); + void nodePopUp(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32 scanList); + void nodePopUpScans(NodeHandle& node, unsigned pos); + void nodeSlide(NodeHandle& dstNode, NodeHandle& srcNode, unsigned cnt, unsigned i); // scans linked to node + void addScanList(NodeHandle& node, unsigned pos, Uint32 scanList); + void removeScanList(NodeHandle& node, unsigned pos, Uint32& scanList); + void moveScanList(NodeHandle& node, unsigned pos); void linkScan(NodeHandle& node, ScanOpPtr scanPtr); void unlinkScan(NodeHandle& node, ScanOpPtr scanPtr); bool islinkScan(NodeHandle& node, ScanOpPtr scanPtr); @@ -595,10 +611,21 @@ private: /* * DbtuxTree.cpp */ - void treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent); - void treeRemove(Signal* signal, Frag& frag, TreePos treePos); - void treeRotateSingle(Signal* signal, Frag& frag, NodeHandle& node, unsigned i); - void treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i); + // add entry + void treeAdd(Frag& frag, TreePos treePos, TreeEnt ent); + void treeAddFull(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent); + void treeAddNode(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent, NodeHandle parentNode, unsigned i); + void treeAddRebalance(Frag& frag, NodeHandle node, unsigned i); + // remove entry + void treeRemove(Frag& frag, TreePos treePos); + void treeRemoveInner(Frag& frag, NodeHandle lubNode, unsigned pos); + void treeRemoveSemi(Frag& frag, NodeHandle node, unsigned i); + void treeRemoveLeaf(Frag& frag, NodeHandle node); + void treeRemoveNode(Frag& frag, NodeHandle node); + void treeRemoveRebalance(Frag& frag, NodeHandle node, unsigned i); + // rotate + void treeRotateSingle(Frag& frag, NodeHandle& node, unsigned i); + void treeRotateDouble(Frag& frag, NodeHandle& node, unsigned i); /* * DbtuxScan.cpp @@ -610,9 +637,9 @@ private: void execACCKEYCONF(Signal* signal); void execACCKEYREF(Signal* signal); void execACC_ABORTCONF(Signal* signal); - void scanFirst(Signal* signal, ScanOpPtr scanPtr); - void scanNext(Signal* signal, ScanOpPtr scanPtr); - bool scanVisible(Signal* signal, ScanOpPtr scanPtr, TreeEnt ent); + void scanFirst(ScanOpPtr scanPtr); + void scanNext(ScanOpPtr scanPtr); + bool scanVisible(ScanOpPtr scanPtr, TreeEnt ent); void scanClose(Signal* signal, ScanOpPtr scanPtr); void addAccLockOp(ScanOp& scan, Uint32 accLockOp); void removeAccLockOp(ScanOp& scan, Uint32 accLockOp); @@ -621,9 +648,9 @@ private: /* * DbtuxSearch.cpp */ - void searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos); - void searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos); - void searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos); + void searchToAdd(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos); + void searchToRemove(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos); + void searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos); /* * DbtuxCmp.cpp @@ -647,7 +674,7 @@ private: PrintPar(); }; void printTree(Signal* signal, Frag& frag, NdbOut& out); - void printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par); + void printNode(Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par); friend class NdbOut& operator<<(NdbOut&, const TupLoc&); friend class NdbOut& operator<<(NdbOut&, const TreeEnt&); friend class NdbOut& operator<<(NdbOut&, const TreeNode&); @@ -805,22 +832,52 @@ Dbtux::ConstData::operator=(Data data) inline Dbtux::TupLoc::TupLoc() : - m_pageId(RNIL), + m_pageId1(RNIL >> 16), + m_pageId2(RNIL & 0xFFFF), m_pageOffset(0) { } inline Dbtux::TupLoc::TupLoc(Uint32 pageId, Uint16 pageOffset) : - m_pageId(pageId), + m_pageId1(pageId >> 16), + m_pageId2(pageId & 0xFFFF), m_pageOffset(pageOffset) { } +inline Uint32 +Dbtux::TupLoc::getPageId() const +{ + return (m_pageId1 << 16) | m_pageId2; +} + +inline void +Dbtux::TupLoc::setPageId(Uint32 pageId) +{ + m_pageId1 = (pageId >> 16); + m_pageId2 = (pageId & 0xFFFF); +} + +inline Uint32 +Dbtux::TupLoc::getPageOffset() const +{ + return (Uint32)m_pageOffset; +} + +inline void +Dbtux::TupLoc::setPageOffset(Uint32 pageOffset) +{ + m_pageOffset = (Uint16)pageOffset; +} + inline bool Dbtux::TupLoc::operator==(const TupLoc& loc) const { - return m_pageId == loc.m_pageId && m_pageOffset == loc.m_pageOffset; + return + m_pageId1 == loc.m_pageId1 && + m_pageId2 == loc.m_pageId2 && + m_pageOffset == loc.m_pageOffset; } inline bool @@ -851,13 +908,13 @@ Dbtux::TreeEnt::eq(const TreeEnt ent) const inline int Dbtux::TreeEnt::cmp(const TreeEnt ent) const { - if (m_tupLoc.m_pageId < ent.m_tupLoc.m_pageId) + if (m_tupLoc.getPageId() < ent.m_tupLoc.getPageId()) return -1; - if (m_tupLoc.m_pageId > ent.m_tupLoc.m_pageId) + if (m_tupLoc.getPageId() > ent.m_tupLoc.getPageId()) return +1; - if (m_tupLoc.m_pageOffset < ent.m_tupLoc.m_pageOffset) + if (m_tupLoc.getPageOffset() < ent.m_tupLoc.getPageOffset()) return -1; - if (m_tupLoc.m_pageOffset > ent.m_tupLoc.m_pageOffset) + if (m_tupLoc.getPageOffset() > ent.m_tupLoc.getPageOffset()) return +1; if (m_tupVersion < ent.m_tupVersion) return -1; @@ -875,17 +932,14 @@ Dbtux::TreeEnt::cmp(const TreeEnt ent) const inline Dbtux::TreeNode::TreeNode() : m_side(2), - m_balance(0), + m_balance(0 + 1), pad1(0), m_occup(0), m_nodeScan(RNIL) { - m_linkPI[0] = NullTupLoc.m_pageId; - m_linkPO[0] = NullTupLoc.m_pageOffset; - m_linkPI[1] = NullTupLoc.m_pageId; - m_linkPO[1] = NullTupLoc.m_pageOffset; - m_linkPI[2] = NullTupLoc.m_pageId; - m_linkPO[2] = NullTupLoc.m_pageOffset; + m_link[0] = NullTupLoc; + m_link[1] = NullTupLoc; + m_link[2] = NullTupLoc; } // Dbtux::TreeHead @@ -913,7 +967,6 @@ Dbtux::TreeHead::getSize(AccSize acc) const case AccFull: return m_nodeSize; } - abort(); return 0; } @@ -938,8 +991,7 @@ Dbtux::TreePos::TreePos() : m_loc(), m_pos(ZNIL), m_match(false), - m_dir(255), - m_ent() + m_dir(255) { } @@ -980,16 +1032,19 @@ Dbtux::ScanOp::ScanOp(ScanBoundPool& scanBoundPool) : m_boundMin(scanBoundPool), m_boundMax(scanBoundPool), m_scanPos(), - m_lastEnt(), - m_nodeScan(RNIL) + m_scanEnt(), + m_nodeScan(RNIL), + m_maxAccLockOps(0) { m_bound[0] = &m_boundMin; m_bound[1] = &m_boundMax; m_boundCnt[0] = 0; m_boundCnt[1] = 0; +#ifdef VM_TRACE for (unsigned i = 0; i < MaxAccLockOps; i++) { - m_accLockOps[i] = RNIL; + m_accLockOps[i] = 0x1f1f1f1f; } +#endif } // Dbtux::Index @@ -1054,8 +1109,7 @@ inline Dbtux::NodeHandle::NodeHandle(Frag& frag) : m_frag(frag), m_loc(), - m_node(0), - m_acc(AccNone) + m_node(0) { } @@ -1063,8 +1117,7 @@ inline Dbtux::NodeHandle::NodeHandle(const NodeHandle& node) : m_frag(node.m_frag), m_loc(node.m_loc), - m_node(node.m_node), - m_acc(node.m_acc) + m_node(node.m_node) { } @@ -1074,7 +1127,6 @@ Dbtux::NodeHandle::operator=(const NodeHandle& node) ndbassert(&m_frag == &node.m_frag); m_loc = node.m_loc; m_node = node.m_node; - m_acc = node.m_acc; return *this; } @@ -1088,13 +1140,13 @@ inline Dbtux::TupLoc Dbtux::NodeHandle::getLink(unsigned i) { ndbrequire(i <= 2); - return TupLoc(m_node->m_linkPI[i], m_node->m_linkPO[i]); + return m_node->m_link[i]; } inline unsigned Dbtux::NodeHandle::getChilds() { - return (getLink(0) != NullTupLoc) + (getLink(1) != NullTupLoc); + return (m_node->m_link[0] != NullTupLoc) + (m_node->m_link[1] != NullTupLoc); } inline unsigned @@ -1112,7 +1164,7 @@ Dbtux::NodeHandle::getOccup() inline int Dbtux::NodeHandle::getBalance() { - return m_node->m_balance; + return (int)m_node->m_balance - 1; } inline Uint32 @@ -1125,8 +1177,7 @@ inline void Dbtux::NodeHandle::setLink(unsigned i, TupLoc loc) { ndbrequire(i <= 2); - m_node->m_linkPI[i] = loc.m_pageId; - m_node->m_linkPO[i] = loc.m_pageOffset; + m_node->m_link[i] = loc; } inline void @@ -1148,7 +1199,7 @@ inline void Dbtux::NodeHandle::setBalance(int b) { ndbrequire(abs(b) <= 1); - m_node->m_balance = b; + m_node->m_balance = (unsigned)(b + 1); } inline void @@ -1161,7 +1212,6 @@ inline Dbtux::Data Dbtux::NodeHandle::getPref() { TreeHead& tree = m_frag.m_tree; - ndbrequire(m_acc >= AccPref); return tree.getPref(m_node); } @@ -1172,11 +1222,6 @@ Dbtux::NodeHandle::getEnt(unsigned pos) TreeEnt* entList = tree.getEntList(m_node); const unsigned occup = m_node->m_occup; ndbrequire(pos < occup); - if (pos == 0 || pos == occup - 1) { - ndbrequire(m_acc >= AccPref) - } else { - ndbrequire(m_acc == AccFull) - } return entList[(1 + pos) % occup]; } @@ -1224,7 +1269,7 @@ Dbtux::getTupAddr(const Frag& frag, TreeEnt ent) const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit]; const TupLoc tupLoc = ent.m_tupLoc; Uint32 tupAddr = NullTupAddr; - c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, tupAddr); + c_tup->tuxGetTupAddr(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), tupAddr); jamEntry(); return tupAddr; } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp index 549720cc17c..ddab77b97b5 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp @@ -87,21 +87,23 @@ Dbtux::cmpSearchKey(const Frag& frag, unsigned& start, ConstData searchKey, Cons /* * Scan bound vs node prefix or entry. * - * Compare lower or upper bound and index attribute data. The attribute - * data may be partial in which case CmpUnknown may be returned. - * Returns -1 if the boundary is to the left of the compared key and +1 - * if the boundary is to the right of the compared key. + * Compare lower or upper bound and index entry data. The entry data + * may be partial in which case CmpUnknown may be returned. Otherwise + * returns -1 if the bound is to the left of the entry and +1 if the + * bound is to the right of the entry. * - * To get this behaviour we treat equality a little bit special. If the - * boundary is a lower bound then the boundary is to the left of all - * equal keys and if it is an upper bound then the boundary is to the - * right of all equal keys. + * The routine is similar to cmpSearchKey, but 0 is never returned. + * Suppose all attributes compare equal. Recall that all bounds except + * possibly the last one are non-strict. Use the given bound direction + * (0-lower 1-upper) and strictness of last bound to return -1 or +1. * - * When searching for the first key we are using the lower bound to try - * to find the first key that is to the right of the boundary. Then we - * start scanning from this tuple (including the tuple itself) until we - * find the first key which is to the right of the boundary. Then we - * stop and do not include that key in the scan result. + * Following example illustrates this. We are at (a=2, b=3). + * + * dir bounds strict return + * 0 a >= 2 and b >= 3 no -1 + * 0 a >= 2 and b > 3 yes +1 + * 1 a <= 2 and b <= 3 no +1 + * 1 a <= 2 and b < 3 yes -1 */ int Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigned boundCount, ConstData entryData, unsigned maxlen) @@ -111,12 +113,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne ndbrequire(dir <= 1); // number of words of data left unsigned len2 = maxlen; - /* - * No boundary means full scan, low boundary is to the right of all - * keys. Thus we should always return -1. For upper bound we are to - * the right of all keys, thus we should always return +1. We achieve - * this behaviour by initializing type to 4. - */ + // in case of no bounds, init last type to something non-strict unsigned type = 4; while (boundCount != 0) { if (len2 <= AttributeHeaderSize) { @@ -124,7 +121,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne return NdbSqlUtil::CmpUnknown; } len2 -= AttributeHeaderSize; - // get and skip bound type + // get and skip bound type (it is used after the loop) type = boundInfo[0]; boundInfo += 1; if (! boundInfo.ah().isNULL()) { @@ -166,30 +163,7 @@ Dbtux::cmpScanBound(const Frag& frag, unsigned dir, ConstData boundInfo, unsigne entryData += AttributeHeaderSize + entryData.ah().getDataSize(); boundCount -= 1; } - if (dir == 0) { - jam(); - /* - * Looking for the lower bound. If strict lower bound then the - * boundary is to the right of the compared key and otherwise (equal - * included in range) then the boundary is to the left of the key. - */ - if (type == 1) { - jam(); - return +1; - } - return -1; - } else { - jam(); - /* - * Looking for the upper bound. If strict upper bound then the - * boundary is to the left of all equal keys and otherwise (equal - * included in the range) then the boundary is to the right of all - * equal keys. - */ - if (type == 3) { - jam(); - return -1; - } - return +1; - } + // all attributes were equal + const int strict = (type & 0x1); + return (dir == 0 ? (strict == 0 ? -1 : +1) : (strict == 0 ? +1 : -1)); } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp index 8d31d2c6a55..c5c22264460 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp @@ -98,7 +98,7 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out) strcpy(par.m_path, "."); par.m_side = 2; par.m_parent = NullTupLoc; - printNode(signal, frag, out, tree.m_root, par); + printNode(frag, out, tree.m_root, par); out.m_out->flush(); if (! par.m_ok) { if (debugFile == 0) { @@ -114,7 +114,7 @@ Dbtux::printTree(Signal* signal, Frag& frag, NdbOut& out) } void -Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par) +Dbtux::printNode(Frag& frag, NdbOut& out, TupLoc loc, PrintPar& par) { if (loc == NullTupLoc) { par.m_depth = 0; @@ -122,7 +122,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& } TreeHead& tree = frag.m_tree; NodeHandle node(frag); - selectNode(signal, node, loc, AccFull); + selectNode(node, loc); out << par.m_path << " " << node << endl; // check children PrintPar cpar[2]; @@ -132,7 +132,7 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& cpar[i].m_side = i; cpar[i].m_depth = 0; cpar[i].m_parent = loc; - printNode(signal, frag, out, node.getLink(i), cpar[i]); + printNode(frag, out, node.getLink(i), cpar[i]); if (! cpar[i].m_ok) { par.m_ok = false; } @@ -178,16 +178,19 @@ Dbtux::printNode(Signal* signal, Frag& frag, NdbOut& out, TupLoc loc, PrintPar& out << "occupancy " << node.getOccup() << " of interior node"; out << " less than min " << tree.m_minOccup << endl; } - // check missed half-leaf/leaf merge +#ifdef dbtux_totally_groks_t_trees + // check missed semi-leaf/leaf merge for (unsigned i = 0; i <= 1; i++) { if (node.getLink(i) != NullTupLoc && node.getLink(1 - i) == NullTupLoc && - node.getOccup() + cpar[i].m_occup <= tree.m_maxOccup) { + // our semi-leaf seems to satify interior minOccup condition + node.getOccup() < tree.m_minOccup) { par.m_ok = false; out << par.m_path << sep; out << "missed merge with child " << i << endl; } } +#endif // check inline prefix { ConstData data1 = node.getPref(); Uint32 data2[MaxPrefSize]; @@ -256,8 +259,8 @@ operator<<(NdbOut& out, const Dbtux::TupLoc& loc) if (loc == Dbtux::NullTupLoc) { out << "null"; } else { - out << dec << loc.m_pageId; - out << "." << dec << loc.m_pageOffset; + out << dec << loc.getPageId(); + out << "." << dec << loc.getPageOffset(); } return out; } @@ -274,16 +277,13 @@ operator<<(NdbOut& out, const Dbtux::TreeEnt& ent) NdbOut& operator<<(NdbOut& out, const Dbtux::TreeNode& node) { - Dbtux::TupLoc link0(node.m_linkPI[0], node.m_linkPO[0]); - Dbtux::TupLoc link1(node.m_linkPI[1], node.m_linkPO[1]); - Dbtux::TupLoc link2(node.m_linkPI[2], node.m_linkPO[2]); out << "[TreeNode " << hex << &node; - out << " [left " << link0 << "]"; - out << " [right " << link1 << "]"; - out << " [up " << link2 << "]"; + out << " [left " << node.m_link[0] << "]"; + out << " [right " << node.m_link[1] << "]"; + out << " [up " << node.m_link[2] << "]"; out << " [side " << dec << node.m_side << "]"; out << " [occup " << dec << node.m_occup << "]"; - out << " [balance " << dec << (int)node.m_balance << "]"; + out << " [balance " << dec << (int)node.m_balance - 1 << "]"; out << " [nodeScan " << hex << node.m_nodeScan << "]"; out << "]"; return out; @@ -313,7 +313,6 @@ operator<<(NdbOut& out, const Dbtux::TreePos& pos) out << " [pos " << dec << pos.m_pos << "]"; out << " [match " << dec << pos.m_match << "]"; out << " [dir " << dec << pos.m_dir << "]"; - out << " [ent " << pos.m_ent << "]"; out << "]"; return out; } @@ -350,6 +349,7 @@ operator<<(NdbOut& out, const Dbtux::ScanOp& scan) out << " [lockMode " << dec << scan.m_lockMode << "]"; out << " [keyInfo " << dec << scan.m_keyInfo << "]"; out << " [pos " << scan.m_scanPos << "]"; + out << " [ent " << scan.m_scanEnt << "]"; for (unsigned i = 0; i <= 1; i++) { out << " [bound " << dec << i; Dbtux::ScanBound& bound = *scan.m_bound[i]; @@ -410,27 +410,21 @@ operator<<(NdbOut& out, const Dbtux::NodeHandle& node) const Dbtux::TreeHead& tree = frag.m_tree; out << "[NodeHandle " << hex << &node; out << " [loc " << node.m_loc << "]"; - out << " [acc " << dec << node.m_acc << "]"; out << " [node " << *node.m_node << "]"; - if (node.m_acc >= Dbtux::AccPref) { - const Uint32* data; - out << " [pref"; - data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize; - for (unsigned j = 0; j < tree.m_prefSize; j++) - out << " " << hex << data[j]; - out << "]"; - out << " [entList"; - unsigned numpos = node.m_node->m_occup; - if (node.m_acc < Dbtux::AccFull && numpos > 2) { - numpos = 2; - out << "(" << dec << numpos << ")"; - } - data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize; - const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data; - for (unsigned pos = 0; pos < numpos; pos++) - out << " " << entList[pos]; - out << "]"; - } + const Uint32* data; + out << " [pref"; + data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize; + for (unsigned j = 0; j < tree.m_prefSize; j++) + out << " " << hex << data[j]; + out << "]"; + out << " [entList"; + unsigned numpos = node.m_node->m_occup; + data = (const Uint32*)node.m_node + Dbtux::NodeHeadSize + tree.m_prefSize; + const Dbtux::TreeEnt* entList = (const Dbtux::TreeEnt*)data; + // print entries in logical order + for (unsigned pos = 1; pos <= numpos; pos++) + out << " " << entList[pos % numpos]; + out << "]"; out << "]"; return out; } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp index 39cd8e25184..ded02696a89 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp @@ -245,7 +245,7 @@ Dbtux::readKeyAttrs(const Frag& frag, TreeEnt ent, unsigned start, Data keyData) const Uint32 numAttrs = frag.m_numAttrs - start; // skip to start position in keyAttrs only keyAttrs += start; - int ret = c_tup->tuxReadAttrs(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, tupVersion, keyAttrs, numAttrs, keyData); + int ret = c_tup->tuxReadAttrs(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), tupVersion, keyAttrs, numAttrs, keyData); jamEntry(); // TODO handle error ndbrequire(ret > 0); @@ -256,7 +256,7 @@ Dbtux::readTablePk(const Frag& frag, TreeEnt ent, Data pkData, unsigned& pkSize) { const Uint32 tableFragPtrI = frag.m_tupTableFragPtrI[ent.m_fragBit]; const TupLoc tupLoc = ent.m_tupLoc; - int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.m_pageId, tupLoc.m_pageOffset, pkData); + int ret = c_tup->tuxReadPk(tableFragPtrI, tupLoc.getPageId(), tupLoc.getPageOffset(), pkData); jamEntry(); // TODO handle error ndbrequire(ret > 0); diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp index 24b030bf8ec..30afb51e7d7 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp @@ -117,10 +117,10 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) switch (opCode) { case TuxMaintReq::OpAdd: jam(); - searchToAdd(signal, frag, c_searchKey, ent, treePos); + searchToAdd(frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { - debugOut << treePos << endl; + debugOut << treePos << (treePos.m_match ? " - error" : "") << endl; } #endif if (treePos.m_match) { @@ -133,8 +133,8 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) break; } /* - * At most one new node is inserted in the operation. We keep one - * free node pre-allocated so the operation cannot fail. + * At most one new node is inserted in the operation. Pre-allocate + * it so that the operation cannot fail. */ if (frag.m_freeLoc == NullTupLoc) { jam(); @@ -144,17 +144,19 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) jam(); break; } + // link to freelist + node.setLink(0, frag.m_freeLoc); frag.m_freeLoc = node.m_loc; ndbrequire(frag.m_freeLoc != NullTupLoc); } - treeAdd(signal, frag, treePos, ent); + treeAdd(frag, treePos, ent); break; case TuxMaintReq::OpRemove: jam(); - searchToRemove(signal, frag, c_searchKey, ent, treePos); + searchToRemove(frag, c_searchKey, ent, treePos); #ifdef VM_TRACE if (debugFlags & DebugMaint) { - debugOut << treePos << endl; + debugOut << treePos << (! treePos.m_match ? " - error" : "") << endl; } #endif if (! treePos.m_match) { @@ -166,7 +168,7 @@ Dbtux::execTUX_MAINT_REQ(Signal* signal) } break; } - treeRemove(signal, frag, treePos); + treeRemove(frag, treePos); break; default: ndbrequire(false); diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp index 3c0af3ca79d..1577c5045e0 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp @@ -211,11 +211,7 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) // make these configurable later tree.m_nodeSize = MAX_TTREE_NODE_SIZE; tree.m_prefSize = MAX_TTREE_PREF_SIZE; -#ifdef dbtux_min_occup_less_max_occup const unsigned maxSlack = MAX_TTREE_NODE_SLACK; -#else - const unsigned maxSlack = 0; -#endif // size up to and including first 2 entries const unsigned pref = tree.getSize(AccPref); if (! (pref <= tree.m_nodeSize)) { @@ -235,6 +231,20 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) tree.m_minOccup = tree.m_maxOccup - maxSlack; // root node does not exist (also set by ctor) tree.m_root = NullTupLoc; +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + if (fragOpPtr.p->m_fragNo == 0) { + debugOut << "Index id=" << indexPtr.i; + debugOut << " nodeSize=" << tree.m_nodeSize; + debugOut << " headSize=" << NodeHeadSize; + debugOut << " prefSize=" << tree.m_prefSize; + debugOut << " entrySize=" << TreeEntSize; + debugOut << " minOccup=" << tree.m_minOccup; + debugOut << " maxOccup=" << tree.m_maxOccup; + debugOut << endl; + } + } +#endif // fragment is defined c_fragOpPool.release(fragOpPtr); } diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp index a1bfa2179bb..389192fd0cf 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp @@ -24,8 +24,8 @@ int Dbtux::allocNode(Signal* signal, NodeHandle& node) { Frag& frag = node.m_frag; - Uint32 pageId = NullTupLoc.m_pageId; - Uint32 pageOffset = NullTupLoc.m_pageOffset; + Uint32 pageId = NullTupLoc.getPageId(); + Uint32 pageOffset = NullTupLoc.getPageOffset(); Uint32* node32 = 0; int errorCode = c_tup->tuxAllocNode(signal, frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); jamEntry(); @@ -33,55 +33,39 @@ Dbtux::allocNode(Signal* signal, NodeHandle& node) jam(); node.m_loc = TupLoc(pageId, pageOffset); node.m_node = reinterpret_cast<TreeNode*>(node32); - node.m_acc = AccNone; ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); } return errorCode; } /* - * Access more of the node. - */ -void -Dbtux::accessNode(Signal* signal, NodeHandle& node, AccSize acc) -{ - ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); - if (node.m_acc >= acc) - return; - // XXX could do prefetch - node.m_acc = acc; -} - -/* * Set handle to point to existing node. */ void -Dbtux::selectNode(Signal* signal, NodeHandle& node, TupLoc loc, AccSize acc) +Dbtux::selectNode(NodeHandle& node, TupLoc loc) { Frag& frag = node.m_frag; ndbrequire(loc != NullTupLoc); - Uint32 pageId = loc.m_pageId; - Uint32 pageOffset = loc.m_pageOffset; + Uint32 pageId = loc.getPageId(); + Uint32 pageOffset = loc.getPageOffset(); Uint32* node32 = 0; c_tup->tuxGetNode(frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); jamEntry(); node.m_loc = loc; node.m_node = reinterpret_cast<TreeNode*>(node32); - node.m_acc = AccNone; ndbrequire(node.m_loc != NullTupLoc && node.m_node != 0); - accessNode(signal, node, acc); } /* - * Set handle to point to new node. Uses the pre-allocated node. + * Set handle to point to new node. Uses a pre-allocated node. */ void -Dbtux::insertNode(Signal* signal, NodeHandle& node, AccSize acc) +Dbtux::insertNode(NodeHandle& node) { Frag& frag = node.m_frag; - TupLoc loc = frag.m_freeLoc; - frag.m_freeLoc = NullTupLoc; - selectNode(signal, node, loc, acc); + // unlink from freelist + selectNode(node, frag.m_freeLoc); + frag.m_freeLoc = node.getLink(0); new (node.m_node) TreeNode(); #ifdef VM_TRACE TreeHead& tree = frag.m_tree; @@ -92,20 +76,17 @@ Dbtux::insertNode(Signal* signal, NodeHandle& node, AccSize acc) } /* - * Delete existing node. + * Delete existing node. Simply put it on the freelist. */ void -Dbtux::deleteNode(Signal* signal, NodeHandle& node) +Dbtux::deleteNode(NodeHandle& node) { Frag& frag = node.m_frag; ndbrequire(node.getOccup() == 0); - TupLoc loc = node.m_loc; - Uint32 pageId = loc.m_pageId; - Uint32 pageOffset = loc.m_pageOffset; - Uint32* node32 = reinterpret_cast<Uint32*>(node.m_node); - c_tup->tuxFreeNode(signal, frag.m_tupIndexFragPtrI, pageId, pageOffset, node32); - jamEntry(); - // invalidate handle and storage + // link to freelist + node.setLink(0, frag.m_freeLoc); + frag.m_freeLoc = node.m_loc; + // invalidate the handle node.m_loc = NullTupLoc; node.m_node = 0; } @@ -115,7 +96,7 @@ Dbtux::deleteNode(Signal* signal, NodeHandle& node) * attribute headers for now. XXX use null mask instead */ void -Dbtux::setNodePref(Signal* signal, NodeHandle& node) +Dbtux::setNodePref(NodeHandle& node) { const Frag& frag = node.m_frag; const TreeHead& tree = frag.m_tree; @@ -133,18 +114,45 @@ Dbtux::setNodePref(Signal* signal, NodeHandle& node) * v * A B C D E _ _ => A B C X D E _ * 0 1 2 3 4 5 6 0 1 2 3 4 5 6 + * + * Add list of scans at the new entry. */ void -Dbtux::nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt& ent) +Dbtux::nodePushUp(NodeHandle& node, unsigned pos, const TreeEnt& ent, Uint32 scanList) { Frag& frag = node.m_frag; TreeHead& tree = frag.m_tree; const unsigned occup = node.getOccup(); ndbrequire(occup < tree.m_maxOccup && pos <= occup); - // fix scans + // fix old scans + if (node.getNodeScan() != RNIL) + nodePushUpScans(node, pos); + // fix node + TreeEnt* const entList = tree.getEntList(node.m_node); + entList[occup] = entList[0]; + TreeEnt* const tmpList = entList + 1; + for (unsigned i = occup; i > pos; i--) { + jam(); + tmpList[i] = tmpList[i - 1]; + } + tmpList[pos] = ent; + entList[0] = entList[occup + 1]; + node.setOccup(occup + 1); + // add new scans + if (scanList != RNIL) + addScanList(node, pos, scanList); + // fix prefix + if (occup == 0 || pos == 0) + setNodePref(node); +} + +void +Dbtux::nodePushUpScans(NodeHandle& node, unsigned pos) +{ + const unsigned occup = node.getOccup(); ScanOpPtr scanPtr; scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + do { jam(); c_scanOpPool.getPtr(scanPtr); TreePos& scanPos = scanPtr.p->m_scanPos; @@ -160,21 +168,7 @@ Dbtux::nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt& scanPos.m_pos++; } scanPtr.i = scanPtr.p->m_nodeScan; - } - // fix node - TreeEnt* const entList = tree.getEntList(node.m_node); - entList[occup] = entList[0]; - TreeEnt* const tmpList = entList + 1; - for (unsigned i = occup; i > pos; i--) { - jam(); - tmpList[i] = tmpList[i - 1]; - } - tmpList[pos] = ent; - entList[0] = entList[occup + 1]; - node.setOccup(occup + 1); - // fix prefix - if (occup == 0 || pos == 0) - setNodePref(signal, node); + } while (scanPtr.i != RNIL); } /* @@ -185,42 +179,55 @@ Dbtux::nodePushUp(Signal* signal, NodeHandle& node, unsigned pos, const TreeEnt& * ^ ^ * A B C D E F _ => A B C E F _ _ * 0 1 2 3 4 5 6 0 1 2 3 4 5 6 + * + * Scans at removed entry are returned if non-zero location is passed or + * else moved forward. */ void -Dbtux::nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) +Dbtux::nodePopDown(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32* scanList) { Frag& frag = node.m_frag; TreeHead& tree = frag.m_tree; const unsigned occup = node.getOccup(); ndbrequire(occup <= tree.m_maxOccup && pos < occup); - ScanOpPtr scanPtr; - // move scans whose entry disappears - scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + if (node.getNodeScan() != RNIL) { + // remove or move scans at this position + if (scanList == 0) + moveScanList(node, pos); + else + removeScanList(node, pos, *scanList); + // fix other scans + if (node.getNodeScan() != RNIL) + nodePopDownScans(node, pos); + } + // fix node + TreeEnt* const entList = tree.getEntList(node.m_node); + entList[occup] = entList[0]; + TreeEnt* const tmpList = entList + 1; + ent = tmpList[pos]; + for (unsigned i = pos; i < occup - 1; i++) { jam(); - c_scanOpPool.getPtr(scanPtr); - TreePos& scanPos = scanPtr.p->m_scanPos; - ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup); - const Uint32 nextPtrI = scanPtr.p->m_nodeScan; - if (scanPos.m_pos == pos) { - jam(); -#ifdef VM_TRACE - if (debugFlags & DebugScan) { - debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl; - debugOut << "At popDown pos=" << pos << " " << node << endl; - } -#endif - scanNext(signal, scanPtr); - } - scanPtr.i = nextPtrI; + tmpList[i] = tmpList[i + 1]; } - // fix other scans + entList[0] = entList[occup - 1]; + node.setOccup(occup - 1); + // fix prefix + if (occup != 1 && pos == 0) + setNodePref(node); +} + +void +Dbtux::nodePopDownScans(NodeHandle& node, unsigned pos) +{ + const unsigned occup = node.getOccup(); + ScanOpPtr scanPtr; scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + do { jam(); c_scanOpPool.getPtr(scanPtr); TreePos& scanPos = scanPtr.p->m_scanPos; ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup); + // handled before ndbrequire(scanPos.m_pos != pos); if (scanPos.m_pos > pos) { jam(); @@ -233,21 +240,7 @@ Dbtux::nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) scanPos.m_pos--; } scanPtr.i = scanPtr.p->m_nodeScan; - } - // fix node - TreeEnt* const entList = tree.getEntList(node.m_node); - entList[occup] = entList[0]; - TreeEnt* const tmpList = entList + 1; - ent = tmpList[pos]; - for (unsigned i = pos; i < occup - 1; i++) { - jam(); - tmpList[i] = tmpList[i + 1]; - } - entList[0] = entList[occup - 1]; - node.setOccup(occup - 1); - // fix prefix - if (occup != 1 && pos == 0) - setNodePref(signal, node); + } while (scanPtr.i != RNIL); } /* @@ -258,43 +251,52 @@ Dbtux::nodePopDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) * ^ v ^ * A B C D E _ _ => B C D X E _ _ * 0 1 2 3 4 5 6 0 1 2 3 4 5 6 + * + * Return list of scans at the removed position 0. */ void -Dbtux::nodePushDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) +Dbtux::nodePushDown(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32& scanList) { Frag& frag = node.m_frag; TreeHead& tree = frag.m_tree; const unsigned occup = node.getOccup(); ndbrequire(occup <= tree.m_maxOccup && pos < occup); - ScanOpPtr scanPtr; - // move scans whose entry disappears - scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + if (node.getNodeScan() != RNIL) { + // remove scans at 0 + removeScanList(node, 0, scanList); + // fix other scans + if (node.getNodeScan() != RNIL) + nodePushDownScans(node, pos); + } + // fix node + TreeEnt* const entList = tree.getEntList(node.m_node); + entList[occup] = entList[0]; + TreeEnt* const tmpList = entList + 1; + TreeEnt oldMin = tmpList[0]; + for (unsigned i = 0; i < pos; i++) { jam(); - c_scanOpPool.getPtr(scanPtr); - TreePos& scanPos = scanPtr.p->m_scanPos; - ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup); - const Uint32 nextPtrI = scanPtr.p->m_nodeScan; - if (scanPos.m_pos == 0) { - jam(); -#ifdef VM_TRACE - if (debugFlags & DebugScan) { - debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl; - debugOut << "At pushDown pos=" << pos << " " << node << endl; - } -#endif - // here we may miss a valid entry "X" XXX known bug - scanNext(signal, scanPtr); - } - scanPtr.i = nextPtrI; + tmpList[i] = tmpList[i + 1]; } - // fix other scans + tmpList[pos] = ent; + ent = oldMin; + entList[0] = entList[occup]; + // fix prefix + if (true) + setNodePref(node); +} + +void +Dbtux::nodePushDownScans(NodeHandle& node, unsigned pos) +{ + const unsigned occup = node.getOccup(); + ScanOpPtr scanPtr; scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + do { jam(); c_scanOpPool.getPtr(scanPtr); TreePos& scanPos = scanPtr.p->m_scanPos; ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup); + // handled before ndbrequire(scanPos.m_pos != 0); if (scanPos.m_pos <= pos) { jam(); @@ -307,22 +309,7 @@ Dbtux::nodePushDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent scanPos.m_pos--; } scanPtr.i = scanPtr.p->m_nodeScan; - } - // fix node - TreeEnt* const entList = tree.getEntList(node.m_node); - entList[occup] = entList[0]; - TreeEnt* const tmpList = entList + 1; - TreeEnt oldMin = tmpList[0]; - for (unsigned i = 0; i < pos; i++) { - jam(); - tmpList[i] = tmpList[i + 1]; - } - tmpList[pos] = ent; - ent = oldMin; - entList[0] = entList[occup]; - // fix prefix - if (true) - setNodePref(signal, node); + } while (scanPtr.i != RNIL); } /* @@ -334,39 +321,50 @@ Dbtux::nodePushDown(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent * v ^ ^ * A B C D E _ _ => X A B C E _ _ * 0 1 2 3 4 5 6 0 1 2 3 4 5 6 + * + * Move scans at removed entry and add scans at the new entry. */ void -Dbtux::nodePopUp(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) +Dbtux::nodePopUp(NodeHandle& node, unsigned pos, TreeEnt& ent, Uint32 scanList) { Frag& frag = node.m_frag; TreeHead& tree = frag.m_tree; const unsigned occup = node.getOccup(); ndbrequire(occup <= tree.m_maxOccup && pos < occup); - ScanOpPtr scanPtr; - // move scans whose entry disappears - scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + if (node.getNodeScan() != RNIL) { + // move scans whose entry disappears + moveScanList(node, pos); + // fix other scans + if (node.getNodeScan() != RNIL) + nodePopUpScans(node, pos); + } + // fix node + TreeEnt* const entList = tree.getEntList(node.m_node); + entList[occup] = entList[0]; + TreeEnt* const tmpList = entList + 1; + TreeEnt newMin = ent; + ent = tmpList[pos]; + for (unsigned i = pos; i > 0; i--) { jam(); - c_scanOpPool.getPtr(scanPtr); - TreePos& scanPos = scanPtr.p->m_scanPos; - ndbrequire(scanPos.m_loc == node.m_loc && scanPos.m_pos < occup); - const Uint32 nextPtrI = scanPtr.p->m_nodeScan; - if (scanPos.m_pos == pos) { - jam(); -#ifdef VM_TRACE - if (debugFlags & DebugScan) { - debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl; - debugOut << "At popUp pos=" << pos << " " << node << endl; - } -#endif - // here we may miss a valid entry "X" XXX known bug - scanNext(signal, scanPtr); - } - scanPtr.i = nextPtrI; + tmpList[i] = tmpList[i - 1]; } - // fix other scans + tmpList[0] = newMin; + entList[0] = entList[occup]; + // add scans + if (scanList != RNIL) + addScanList(node, 0, scanList); + // fix prefix + if (true) + setNodePref(node); +} + +void +Dbtux::nodePopUpScans(NodeHandle& node, unsigned pos) +{ + const unsigned occup = node.getOccup(); + ScanOpPtr scanPtr; scanPtr.i = node.getNodeScan(); - while (scanPtr.i != RNIL) { + do { jam(); c_scanOpPool.getPtr(scanPtr); TreePos& scanPos = scanPtr.p->m_scanPos; @@ -383,41 +381,123 @@ Dbtux::nodePopUp(Signal* signal, NodeHandle& node, unsigned pos, TreeEnt& ent) scanPos.m_pos++; } scanPtr.i = scanPtr.p->m_nodeScan; - } - // fix node - TreeEnt* const entList = tree.getEntList(node.m_node); - entList[occup] = entList[0]; - TreeEnt* const tmpList = entList + 1; - TreeEnt newMin = ent; - ent = tmpList[pos]; - for (unsigned i = pos; i > 0; i--) { - jam(); - tmpList[i] = tmpList[i - 1]; - } - tmpList[0] = newMin; - entList[0] = entList[occup]; - // fix prefix - if (true) - setNodePref(signal, node); + } while (scanPtr.i != RNIL); } /* - * Move all possible entries from another node before the min (i=0) or - * after the max (i=1). XXX can be optimized + * Move number of entries from another node to this node before the min + * (i=0) or after the max (i=1). Expensive but not often used. */ void -Dbtux::nodeSlide(Signal* signal, NodeHandle& dstNode, NodeHandle& srcNode, unsigned i) +Dbtux::nodeSlide(NodeHandle& dstNode, NodeHandle& srcNode, unsigned cnt, unsigned i) { Frag& frag = dstNode.m_frag; TreeHead& tree = frag.m_tree; ndbrequire(i <= 1); - while (dstNode.getOccup() < tree.m_maxOccup && srcNode.getOccup() != 0) { + while (cnt != 0) { TreeEnt ent; - nodePopDown(signal, srcNode, i == 0 ? srcNode.getOccup() - 1 : 0, ent); - nodePushUp(signal, dstNode, i == 0 ? 0 : dstNode.getOccup(), ent); + Uint32 scanList = RNIL; + nodePopDown(srcNode, i == 0 ? srcNode.getOccup() - 1 : 0, ent, &scanList); + nodePushUp(dstNode, i == 0 ? 0 : dstNode.getOccup(), ent, scanList); + cnt--; } } +// scans linked to node + + +/* + * Add list of scans to node at given position. + */ +void +Dbtux::addScanList(NodeHandle& node, unsigned pos, Uint32 scanList) +{ + ScanOpPtr scanPtr; + scanPtr.i = scanList; + do { + jam(); + c_scanOpPool.getPtr(scanPtr); +#ifdef VM_TRACE + if (debugFlags & DebugScan) { + debugOut << "Add scan " << scanPtr.i << " " << *scanPtr.p << endl; + debugOut << "To pos=" << pos << " " << node << endl; + } +#endif + const Uint32 nextPtrI = scanPtr.p->m_nodeScan; + scanPtr.p->m_nodeScan = RNIL; + linkScan(node, scanPtr); + TreePos& scanPos = scanPtr.p->m_scanPos; + // set position but leave direction alone + scanPos.m_loc = node.m_loc; + scanPos.m_pos = pos; + scanPtr.i = nextPtrI; + } while (scanPtr.i != RNIL); +} + +/* + * Remove list of scans from node at given position. The return + * location must point to existing list (in fact RNIL always). + */ +void +Dbtux::removeScanList(NodeHandle& node, unsigned pos, Uint32& scanList) +{ + ScanOpPtr scanPtr; + scanPtr.i = node.getNodeScan(); + do { + jam(); + c_scanOpPool.getPtr(scanPtr); + const Uint32 nextPtrI = scanPtr.p->m_nodeScan; + TreePos& scanPos = scanPtr.p->m_scanPos; + ndbrequire(scanPos.m_loc == node.m_loc); + if (scanPos.m_pos == pos) { + jam(); +#ifdef VM_TRACE + if (debugFlags & DebugScan) { + debugOut << "Remove scan " << scanPtr.i << " " << *scanPtr.p << endl; + debugOut << "Fron pos=" << pos << " " << node << endl; + } +#endif + unlinkScan(node, scanPtr); + scanPtr.p->m_nodeScan = scanList; + scanList = scanPtr.i; + // unset position but leave direction alone + scanPos.m_loc = NullTupLoc; + scanPos.m_pos = ZNIL; + } + scanPtr.i = nextPtrI; + } while (scanPtr.i != RNIL); +} + +/* + * Move list of scans away from entry about to be removed. Uses scan + * method scanNext(). + */ +void +Dbtux::moveScanList(NodeHandle& node, unsigned pos) +{ + ScanOpPtr scanPtr; + scanPtr.i = node.getNodeScan(); + do { + jam(); + c_scanOpPool.getPtr(scanPtr); + TreePos& scanPos = scanPtr.p->m_scanPos; + const Uint32 nextPtrI = scanPtr.p->m_nodeScan; + ndbrequire(scanPos.m_loc == node.m_loc); + if (scanPos.m_pos == pos) { + jam(); +#ifdef VM_TRACE + if (debugFlags & DebugScan) { + debugOut << "Move scan " << scanPtr.i << " " << *scanPtr.p << endl; + debugOut << "At pos=" << pos << " " << node << endl; + } +#endif + scanNext(scanPtr); + ndbrequire(! (scanPos.m_loc == node.m_loc && scanPos.m_pos == pos)); + } + scanPtr.i = nextPtrI; + } while (scanPtr.i != RNIL); +} + /* * Link scan to the list under the node. The list is single-linked and * ordering does not matter. diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp index 5b161d3c4ce..afde88c47a2 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp @@ -108,15 +108,23 @@ Dbtux::execACC_SCANREQ(Signal* signal) /* * Receive bounds for scan in single direct call. The bounds can arrive * in any order. Attribute ids are those of index table. + * + * Replace EQ by equivalent LE + GE. Check for conflicting bounds. + * Check that sets of lower and upper bounds are on initial sequences of + * keys and that all but possibly last bound is non-strict. + * + * Finally save the sets of lower and upper bounds (i.e. start key and + * end key). Full bound type (< 4) is included but only the strict bit + * is used since lower and upper have now been separated. */ void Dbtux::execTUX_BOUND_INFO(Signal* signal) { jamEntry(); struct BoundInfo { + int type; unsigned offset; unsigned size; - int type; }; TuxBoundInfo* const sig = (TuxBoundInfo*)signal->getDataPtrSend(); const TuxBoundInfo reqCopy = *(const TuxBoundInfo*)sig; @@ -124,19 +132,12 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) // get records ScanOp& scan = *c_scanOpPool.getPtr(req->tuxScanPtrI); Index& index = *c_indexPool.getPtr(scan.m_indexId); - // collect bound info for each index attribute - BoundInfo boundInfo[MaxIndexAttributes][2]; + // collect lower and upper bounds + BoundInfo boundInfo[2][MaxIndexAttributes]; // largest attrId seen plus one - Uint32 maxAttrId = 0; - // skip 5 words - if (req->boundAiLength < 5) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidAttrInfo; - return; - } + Uint32 maxAttrId[2] = { 0, 0 }; + unsigned offset = 0; const Uint32* const data = (Uint32*)sig + TuxBoundInfo::SignalLength; - unsigned offset = 5; // walk through entries while (offset + 2 <= req->boundAiLength) { jam(); @@ -156,32 +157,35 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) sig->errorCode = TuxBoundInfo::InvalidAttrInfo; return; } - while (maxAttrId <= attrId) { - BoundInfo* b = boundInfo[maxAttrId++]; - b[0].type = b[1].type = -1; - } - BoundInfo* b = boundInfo[attrId]; - if (type == 0 || type == 1 || type == 4) { - if (b[0].type != -1) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidBounds; - return; + for (unsigned j = 0; j <= 1; j++) { + // check if lower/upper bit matches + const unsigned luBit = (j << 1); + if ((type & 0x2) != luBit && type != 4) + continue; + // EQ -> LE, GE + const unsigned type2 = (type & 0x1) | luBit; + // fill in any gap + while (maxAttrId[j] <= attrId) { + BoundInfo& b = boundInfo[j][maxAttrId[j]++]; + b.type = -1; } - b[0].offset = offset; - b[0].size = 2 + dataSize; - b[0].type = type; - } - if (type == 2 || type == 3 || type == 4) { - if (b[1].type != -1) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::InvalidBounds; - return; + BoundInfo& b = boundInfo[j][attrId]; + if (b.type != -1) { + // compare with previous bound + if (b.type != type2 || + b.size != 2 + dataSize || + memcmp(&data[b.offset + 2], &data[offset + 2], dataSize << 2) != 0) { + jam(); + scan.m_state = ScanOp::Invalid; + sig->errorCode = TuxBoundInfo::InvalidBounds; + return; + } + } else { + // enter new bound + b.type = type2; + b.offset = offset; + b.size = 2 + dataSize; } - b[1].offset = offset; - b[1].size = 2 + dataSize; - b[1].type = type; } // jump to next offset += 2 + dataSize; @@ -192,34 +196,27 @@ Dbtux::execTUX_BOUND_INFO(Signal* signal) sig->errorCode = TuxBoundInfo::InvalidAttrInfo; return; } - // save the bounds in index attribute id order - scan.m_boundCnt[0] = 0; - scan.m_boundCnt[1] = 0; - for (unsigned i = 0; i < maxAttrId; i++) { - jam(); - const BoundInfo* b = boundInfo[i]; - // current limitation - check all but last is equality - if (i + 1 < maxAttrId) { - if (b[0].type != 4 || b[1].type != 4) { + for (unsigned j = 0; j <= 1; j++) { + // save lower/upper bound in index attribute id order + for (unsigned i = 0; i < maxAttrId[j]; i++) { + jam(); + const BoundInfo& b = boundInfo[j][i]; + // check for gap or strict bound before last + if (b.type == -1 || (i + 1 < maxAttrId[j] && (b.type & 0x1))) { jam(); scan.m_state = ScanOp::Invalid; sig->errorCode = TuxBoundInfo::InvalidBounds; return; } - } - for (unsigned j = 0; j <= 1; j++) { - if (b[j].type != -1) { + bool ok = scan.m_bound[j]->append(&data[b.offset], b.size); + if (! ok) { jam(); - bool ok = scan.m_bound[j]->append(&data[b[j].offset], b[j].size); - if (! ok) { - jam(); - scan.m_state = ScanOp::Invalid; - sig->errorCode = TuxBoundInfo::OutOfBuffers; - return; - } - scan.m_boundCnt[j]++; + scan.m_state = ScanOp::Invalid; + sig->errorCode = TuxBoundInfo::OutOfBuffers; + return; } } + scan.m_boundCnt[j] = maxAttrId[j]; } // no error sig->errorCode = 0; @@ -278,7 +275,7 @@ Dbtux::execNEXT_SCANREQ(Signal* signal) jam(); const TupLoc loc = scan.m_scanPos.m_loc; NodeHandle node(frag); - selectNode(signal, node, loc, AccHead); + selectNode(node, loc); unlinkScan(node, scanPtr); scan.m_scanPos.m_loc = NullTupLoc; } @@ -353,7 +350,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) if (scan.m_lockwait) { jam(); // LQH asks if we are waiting for lock and we tell it to ask again - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); conf->scanPtr = scan.m_userPtr; conf->accOperationPtr = RNIL; // no tuple returned @@ -367,7 +364,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) if (scan.m_state == ScanOp::First) { jam(); // search is done only once in single range scan - scanFirst(signal, scanPtr); + scanFirst(scanPtr); #ifdef VM_TRACE if (debugFlags & DebugScan) { debugOut << "First scan " << scanPtr.i << " " << scan << endl; @@ -377,7 +374,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) if (scan.m_state == ScanOp::Next) { jam(); // look for next - scanNext(signal, scanPtr); + scanNext(scanPtr); } // for reading tuple key in Current or Locked state Data pkData = c_dataBuffer; @@ -388,7 +385,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) ndbrequire(scan.m_accLockOp == RNIL); if (! scan.m_readCommitted) { jam(); - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; // read tuple key readTablePk(frag, ent, pkData, pkSize); // get read lock or exclusive lock @@ -476,7 +473,7 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) // we have lock or do not need one jam(); // read keys if not already done (uses signal) - const TreeEnt ent = scan.m_scanPos.m_ent; + const TreeEnt ent = scan.m_scanEnt; if (scan.m_keyInfo) { jam(); if (pkSize == 0) { @@ -539,8 +536,6 @@ Dbtux::execACC_CHECK_SCAN(Signal* signal) total += length; } } - // remember last entry returned - scan.m_lastEnt = ent; // next time look for next entry scan.m_state = ScanOp::Next; return; @@ -685,7 +680,7 @@ Dbtux::execACC_ABORTCONF(Signal* signal) * by scanNext. */ void -Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr) +Dbtux::scanFirst(ScanOpPtr scanPtr) { ScanOp& scan = *scanPtr.p; Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI); @@ -703,7 +698,7 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr) } // search for scan start position TreePos treePos; - searchToScan(signal, frag, c_dataBuffer, scan.m_boundCnt[0], treePos); + searchToScan(frag, c_dataBuffer, scan.m_boundCnt[0], treePos); if (treePos.m_loc == NullTupLoc) { // empty tree jam(); @@ -715,23 +710,27 @@ Dbtux::scanFirst(Signal* signal, ScanOpPtr scanPtr) scan.m_state = ScanOp::Next; // link the scan to node found NodeHandle node(frag); - selectNode(signal, node, treePos.m_loc, AccFull); + selectNode(node, treePos.m_loc); linkScan(node, scanPtr); } /* * Move to next entry. The scan is already linked to some node. When - * we leave, if any entry was found, it will be linked to a possibly - * different node. The scan has a direction, one of: + * we leave, if an entry was found, it will be linked to a possibly + * different node. The scan has a position, and a direction which tells + * from where we came to this position. This is one of: + * + * 0 - up from left child (scan this node next) + * 1 - up from right child (proceed to parent) + * 2 - up from root (the scan ends) + * 3 - left to right within node (at end proceed to right child) + * 4 - down from parent (proceed to left child) * - * 0 - coming up from left child - * 1 - coming up from right child (proceed to parent immediately) - * 2 - coming up from root (the scan ends) - * 3 - left to right within node - * 4 - coming down from parent to left or right child + * If an entry was found, scan direction is 3. Therefore tree + * re-organizations need not worry about scan direction. */ void -Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) +Dbtux::scanNext(ScanOpPtr scanPtr) { ScanOp& scan = *scanPtr.p; Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI); @@ -740,22 +739,8 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) debugOut << "Next in scan " << scanPtr.i << " " << scan << endl; } #endif - if (scan.m_state == ScanOp::Locked) { - jam(); - // version of a tuple locked by us cannot disappear (assert only) -#ifdef dbtux_wl_1942_is_done - ndbassert(false); -#endif - AccLockReq* const lockReq = (AccLockReq*)signal->getDataPtrSend(); - lockReq->returnCode = RNIL; - lockReq->requestInfo = AccLockReq::Unlock; - lockReq->accOpPtr = scan.m_accLockOp; - EXECUTE_DIRECT(DBACC, GSN_ACC_LOCKREQ, signal, AccLockReq::UndoSignalLength); - jamEntry(); - ndbrequire(lockReq->returnCode == AccLockReq::Success); - scan.m_accLockOp = RNIL; - scan.m_state = ScanOp::Current; - } + // cannot be moved away from tuple we have locked + ndbrequire(scan.m_state != ScanOp::Locked); // set up index keys for this operation setKeyAttrs(frag); // unpack upper bound into c_dataBuffer @@ -771,10 +756,12 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) TreePos pos = scan.m_scanPos; // get and remember original node NodeHandle origNode(frag); - selectNode(signal, origNode, pos.m_loc, AccHead); + selectNode(origNode, pos.m_loc); ndbrequire(islinkScan(origNode, scanPtr)); // current node in loop NodeHandle node = origNode; + // copy of entry found + TreeEnt ent; while (true) { jam(); if (pos.m_dir == 2) { @@ -786,7 +773,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) } if (node.m_loc != pos.m_loc) { jam(); - selectNode(signal, node, pos.m_loc, AccHead); + selectNode(node, pos.m_loc); } if (pos.m_dir == 4) { // coming down from parent proceed to left child @@ -802,7 +789,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_dir = 0; } if (pos.m_dir == 0) { - // coming from left child scan current node + // coming up from left child scan current node jam(); pos.m_pos = 0; pos.m_match = false; @@ -813,8 +800,6 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) jam(); unsigned occup = node.getOccup(); ndbrequire(occup >= 1); - // access full node - accessNode(signal, node, AccFull); // advance position if (! pos.m_match) pos.m_match = true; @@ -822,10 +807,10 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_pos++; if (pos.m_pos < occup) { jam(); - pos.m_ent = node.getEnt(pos.m_pos); + ent = node.getEnt(pos.m_pos); pos.m_dir = 3; // unchanged // read and compare all attributes - readKeyAttrs(frag, pos.m_ent, 0, c_entryKey); + readKeyAttrs(frag, ent, 0, c_entryKey); int ret = cmpScanBound(frag, 1, c_dataBuffer, scan.m_boundCnt[1], c_entryKey); ndbrequire(ret != NdbSqlUtil::CmpUnknown); if (ret < 0) { @@ -836,7 +821,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) break; } // can we see it - if (! scanVisible(signal, scanPtr, pos.m_ent)) { + if (! scanVisible(scanPtr, ent)) { jam(); continue; } @@ -856,7 +841,7 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) pos.m_dir = 1; } if (pos.m_dir == 1) { - // coming from right child proceed to parent + // coming up from right child proceed to parent jam(); pos.m_loc = node.getLink(2); pos.m_dir = node.getSide(); @@ -868,12 +853,15 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) scan.m_scanPos = pos; // relink if (scan.m_state == ScanOp::Current) { + ndbrequire(pos.m_match == true && pos.m_dir == 3); ndbrequire(pos.m_loc == node.m_loc); if (origNode.m_loc != node.m_loc) { jam(); unlinkScan(origNode, scanPtr); linkScan(node, scanPtr); } + // copy found entry + scan.m_scanEnt = ent; } else if (scan.m_state == ScanOp::Last) { jam(); ndbrequire(pos.m_loc == NullTupLoc); @@ -891,12 +879,12 @@ Dbtux::scanNext(Signal* signal, ScanOpPtr scanPtr) /* * Check if an entry is visible to the scan. * - * There is a special check to never return same tuple twice in a row. + * There is a special check to never accept same tuple twice in a row. * This is faster than asking TUP. It also fixes some special cases * which are not analyzed or handled yet. */ bool -Dbtux::scanVisible(Signal* signal, ScanOpPtr scanPtr, TreeEnt ent) +Dbtux::scanVisible(ScanOpPtr scanPtr, TreeEnt ent) { const ScanOp& scan = *scanPtr.p; const Frag& frag = *c_fragPool.getPtr(scan.m_fragPtrI); @@ -906,8 +894,8 @@ Dbtux::scanVisible(Signal* signal, ScanOpPtr scanPtr, TreeEnt ent) Uint32 tupAddr = getTupAddr(frag, ent); Uint32 tupVersion = ent.m_tupVersion; // check for same tuple twice in row - if (scan.m_lastEnt.m_tupLoc == ent.m_tupLoc && - scan.m_lastEnt.m_fragBit == fragBit) { + if (scan.m_scanEnt.m_tupLoc == ent.m_tupLoc && + scan.m_scanEnt.m_fragBit == fragBit) { jam(); return false; } @@ -929,7 +917,7 @@ Dbtux::scanClose(Signal* signal, ScanOpPtr scanPtr) ScanOp& scan = *scanPtr.p; ndbrequire(! scan.m_lockwait && scan.m_accLockOp == RNIL); // unlock all not unlocked by LQH - for (unsigned i = 0; i < MaxAccLockOps; i++) { + for (unsigned i = 0; i < scan.m_maxAccLockOps; i++) { if (scan.m_accLockOps[i] != RNIL) { jam(); AccLockReq* const lockReq = (AccLockReq*)signal->getDataPtrSend(); @@ -959,7 +947,7 @@ Dbtux::addAccLockOp(ScanOp& scan, Uint32 accLockOp) ndbrequire(accLockOp != RNIL); Uint32* list = scan.m_accLockOps; bool ok = false; - for (unsigned i = 0; i < MaxAccLockOps; i++) { + for (unsigned i = 0; i < scan.m_maxAccLockOps; i++) { ndbrequire(list[i] != accLockOp); if (! ok && list[i] == RNIL) { list[i] = accLockOp; @@ -967,6 +955,14 @@ Dbtux::addAccLockOp(ScanOp& scan, Uint32 accLockOp) // continue check for duplicates } } + if (! ok) { + unsigned i = scan.m_maxAccLockOps; + if (i < MaxAccLockOps) { + list[i] = accLockOp; + ok = true; + scan.m_maxAccLockOps = i + 1; + } + } ndbrequire(ok); } @@ -976,7 +972,7 @@ Dbtux::removeAccLockOp(ScanOp& scan, Uint32 accLockOp) ndbrequire(accLockOp != RNIL); Uint32* list = scan.m_accLockOps; bool ok = false; - for (unsigned i = 0; i < MaxAccLockOps; i++) { + for (unsigned i = 0; i < scan.m_maxAccLockOps; i++) { if (list[i] == accLockOp) { list[i] = RNIL; ok = true; diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp index bffbb8f5594..7057d74c3ad 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp @@ -25,16 +25,17 @@ * TODO optimize for initial equal attrs in node min/max */ void -Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) +Dbtux::searchToAdd(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) { const TreeHead& tree = frag.m_tree; const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; + // assume success + treePos.m_match = false; if (currNode.m_loc == NullTupLoc) { // empty tree jam(); - treePos.m_match = false; return; } NodeHandle glbNode(frag); // potential g.l.b of final node @@ -45,7 +46,7 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear NodeHandle bottomNode(frag); while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; @@ -93,16 +94,22 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; + // failed treePos.m_match = true; return; } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); - for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) { + // anticipate + treePos.m_loc = currNode.m_loc; + // binary search + int lo = -1; + unsigned hi = currNode.getOccup(); + int ret; + while (1) { jam(); - int ret; + // hi - lo > 1 implies lo < j < hi + int j = (hi + lo) / 2; // read and compare attributes unsigned start = 0; readKeyAttrs(frag, currNode.getEnt(j), start, c_entryKey); @@ -113,25 +120,38 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear // keys are equal, compare entry values ret = searchEnt.cmp(currNode.getEnt(j)); } - if (ret <= 0) { - jam(); - treePos.m_loc = currNode.m_loc; + if (ret < 0) + hi = j; + else if (ret > 0) + lo = j; + else { treePos.m_pos = j; - treePos.m_match = (ret == 0); + // failed + treePos.m_match = true; return; } + if (hi - lo == 1) + break; } - if (! bottomNode.isNull()) { + if (ret < 0) { jam(); - // backwards compatible for now - treePos.m_loc = bottomNode.m_loc; - treePos.m_pos = 0; - treePos.m_match = false; + treePos.m_pos = hi; return; } - treePos.m_loc = currNode.m_loc; - treePos.m_pos = currNode.getOccup(); - treePos.m_match = false; + if (hi < currNode.getOccup()) { + jam(); + treePos.m_pos = hi; + return; + } + if (bottomNode.isNull()) { + jam(); + treePos.m_pos = hi; + return; + } + jam(); + // backwards compatible for now + treePos.m_loc = bottomNode.m_loc; + treePos.m_pos = 0; } /* @@ -139,27 +159,30 @@ Dbtux::searchToAdd(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt sear * * Compares search key to each node min. A move to right subtree can * overshoot target node. The last such node is saved. The final node - * is a half-leaf or leaf. If search key is less than final node min + * is a semi-leaf or leaf. If search key is less than final node min * then the saved node is the g.l.b of the final node and we move back * to it. */ void -Dbtux::searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) +Dbtux::searchToRemove(Frag& frag, ConstData searchKey, TreeEnt searchEnt, TreePos& treePos) { const TreeHead& tree = frag.m_tree; const unsigned numAttrs = frag.m_numAttrs; NodeHandle currNode(frag); currNode.m_loc = tree.m_root; + // assume success + treePos.m_match = true; if (currNode.m_loc == NullTupLoc) { // empty tree jam(); + // failed treePos.m_match = false; return; } NodeHandle glbNode(frag); // potential g.l.b of final node while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(currNode, currNode.m_loc); int ret; // compare prefix unsigned start = 0; @@ -206,27 +229,24 @@ Dbtux::searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt s jam(); treePos.m_loc = currNode.m_loc; treePos.m_pos = 0; - treePos.m_match = true; return; } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); + // anticipate + treePos.m_loc = currNode.m_loc; // pos 0 was handled above for (unsigned j = 1, occup = currNode.getOccup(); j < occup; j++) { jam(); // compare only the entry if (searchEnt.eq(currNode.getEnt(j))) { jam(); - treePos.m_loc = currNode.m_loc; treePos.m_pos = j; - treePos.m_match = true; return; } } - treePos.m_loc = currNode.m_loc; treePos.m_pos = currNode.getOccup(); + // failed treePos.m_match = false; } @@ -236,7 +256,7 @@ Dbtux::searchToRemove(Signal* signal, Frag& frag, ConstData searchKey, TreeEnt s * Similar to searchToAdd. */ void -Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos) +Dbtux::searchToScan(Frag& frag, ConstData boundInfo, unsigned boundCount, TreePos& treePos) { const TreeHead& tree = frag.m_tree; NodeHandle currNode(frag); @@ -251,7 +271,7 @@ Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned bo NodeHandle bottomNode(frag); while (true) { jam(); - selectNode(signal, currNode, currNode.m_loc, AccPref); + selectNode(currNode, currNode.m_loc); int ret; // compare prefix ret = cmpScanBound(frag, 0, boundInfo, boundCount, currNode.getPref(), tree.m_prefSize); @@ -300,8 +320,6 @@ Dbtux::searchToScan(Signal* signal, Frag& frag, ConstData boundInfo, unsigned bo } break; } - // access rest of current node - accessNode(signal, currNode, AccFull); for (unsigned j = 0, occup = currNode.getOccup(); j < occup; j++) { jam(); int ret; diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp index 3baa62998db..b9e3b593a00 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp @@ -18,74 +18,105 @@ #include "Dbtux.hpp" /* - * Add entry. + * Add entry. Handle the case when there is room for one more. This + * is the common case given slack in nodes. */ void -Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) +Dbtux::treeAdd(Frag& frag, TreePos treePos, TreeEnt ent) { TreeHead& tree = frag.m_tree; - unsigned pos = treePos.m_pos; NodeHandle node(frag); - // check for empty tree - if (treePos.m_loc == NullTupLoc) { - jam(); - insertNode(signal, node, AccPref); - nodePushUp(signal, node, 0, ent); - node.setSide(2); - tree.m_root = node.m_loc; - return; - } - // access full node - selectNode(signal, node, treePos.m_loc, AccFull); - // check if it is bounding node - if (pos != 0 && pos != node.getOccup()) { + if (treePos.m_loc != NullTupLoc) { + // non-empty tree jam(); - // check if room for one more + selectNode(node, treePos.m_loc); + unsigned pos = treePos.m_pos; if (node.getOccup() < tree.m_maxOccup) { + // node has room jam(); - nodePushUp(signal, node, pos, ent); + nodePushUp(node, pos, ent, RNIL); return; } - // returns min entry - nodePushDown(signal, node, pos - 1, ent); - // find position to add the removed min entry - TupLoc childLoc = node.getLink(0); - if (childLoc == NullTupLoc) { + treeAddFull(frag, node, pos, ent); + return; + } + jam(); + insertNode(node); + nodePushUp(node, 0, ent, RNIL); + node.setSide(2); + tree.m_root = node.m_loc; +} + +/* + * Add entry when node is full. Handle the case when there is g.l.b + * node in left subtree with room for one more. It will receive the min + * entry of this node. The min entry could be the entry to add. + */ +void +Dbtux::treeAddFull(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent) +{ + TreeHead& tree = frag.m_tree; + TupLoc loc = lubNode.getLink(0); + if (loc != NullTupLoc) { + // find g.l.b node + NodeHandle glbNode(frag); + do { jam(); - // left child will be added - pos = 0; - } else { + selectNode(glbNode, loc); + loc = glbNode.getLink(1); + } while (loc != NullTupLoc); + if (glbNode.getOccup() < tree.m_maxOccup) { + // g.l.b node has room jam(); - // find glb node - while (childLoc != NullTupLoc) { + Uint32 scanList = RNIL; + if (pos != 0) { jam(); - selectNode(signal, node, childLoc, AccHead); - childLoc = node.getLink(1); + // add the new entry and return min entry + nodePushDown(lubNode, pos - 1, ent, scanList); } - // access full node again - accessNode(signal, node, AccFull); - pos = node.getOccup(); + // g.l.b node receives min entry from l.u.b node + nodePushUp(glbNode, glbNode.getOccup(), ent, scanList); + return; } - // fall thru to next case - } - // adding new min or max - unsigned i = (pos == 0 ? 0 : 1); - ndbrequire(node.getLink(i) == NullTupLoc); - // check if the half-leaf/leaf has room for one more - if (node.getOccup() < tree.m_maxOccup) { - jam(); - nodePushUp(signal, node, pos, ent); + treeAddNode(frag, lubNode, pos, ent, glbNode, 1); return; } - // add a new node - NodeHandle childNode(frag); - insertNode(signal, childNode, AccPref); - nodePushUp(signal, childNode, 0, ent); + treeAddNode(frag, lubNode, pos, ent, lubNode, 0); +} + +/* + * Add entry when there is no g.l.b node in left subtree or the g.l.b + * node is full. We must add a new left or right child node which + * becomes the new g.l.b node. + */ +void +Dbtux::treeAddNode(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent, NodeHandle parentNode, unsigned i) +{ + NodeHandle glbNode(frag); + insertNode(glbNode); // connect parent and child - node.setLink(i, childNode.m_loc); - childNode.setLink(2, node.m_loc); - childNode.setSide(i); - // re-balance tree at each node + parentNode.setLink(i, glbNode.m_loc); + glbNode.setLink(2, parentNode.m_loc); + glbNode.setSide(i); + Uint32 scanList = RNIL; + if (pos != 0) { + jam(); + // add the new entry and return min entry + nodePushDown(lubNode, pos - 1, ent, scanList); + } + // g.l.b node receives min entry from l.u.b node + nodePushUp(glbNode, 0, ent, scanList); + // re-balance the tree + treeAddRebalance(frag, parentNode, i); +} + +/* + * Re-balance tree after adding a node. The process starts with the + * parent of the added node. + */ +void +Dbtux::treeAddRebalance(Frag& frag, NodeHandle node, unsigned i) +{ while (true) { // height of subtree i has increased by 1 int j = (i == 0 ? -1 : +1); @@ -105,14 +136,14 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) // height of longer subtree increased jam(); NodeHandle childNode(frag); - selectNode(signal, childNode, node.getLink(i), AccHead); + selectNode(childNode, node.getLink(i)); int b2 = childNode.getBalance(); if (b2 == b) { jam(); - treeRotateSingle(signal, frag, node, i); + treeRotateSingle(frag, node, i); } else if (b2 == -b) { jam(); - treeRotateDouble(signal, frag, node, i); + treeRotateDouble(frag, node, i); } else { // height of subtree increased so it cannot be perfectly balanced ndbrequire(false); @@ -129,118 +160,169 @@ Dbtux::treeAdd(Signal* signal, Frag& frag, TreePos treePos, TreeEnt ent) break; } i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); + selectNode(node, parentLoc); } } /* - * Remove entry. + * Remove entry. Optimize for nodes with slack. Handle the case when + * there is no underflow i.e. occupancy remains at least minOccup. For + * interior nodes this is a requirement. For others it means that we do + * not need to consider merge of semi-leaf and leaf. */ void -Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) +Dbtux::treeRemove(Frag& frag, TreePos treePos) { TreeHead& tree = frag.m_tree; unsigned pos = treePos.m_pos; NodeHandle node(frag); - // access full node - selectNode(signal, node, treePos.m_loc, AccFull); + selectNode(node, treePos.m_loc); TreeEnt ent; - // check interior node first - if (node.getChilds() == 2) { + if (node.getOccup() > tree.m_minOccup) { + // no underflow in any node type jam(); - ndbrequire(node.getOccup() >= tree.m_minOccup); - // check if no underflow - if (node.getOccup() > tree.m_minOccup) { - jam(); - nodePopDown(signal, node, pos, ent); - return; - } - // save current handle - NodeHandle parentNode = node; - // find glb node - TupLoc childLoc = node.getLink(0); - while (childLoc != NullTupLoc) { - jam(); - selectNode(signal, node, childLoc, AccHead); - childLoc = node.getLink(1); - } - // access full node again - accessNode(signal, node, AccFull); - // use glb max as new parent min - ent = node.getEnt(node.getOccup() - 1); - nodePopUp(signal, parentNode, pos, ent); - // set up to remove glb max - pos = node.getOccup() - 1; - // fall thru to next case + nodePopDown(node, pos, ent, 0); + return; } - // remove the element - nodePopDown(signal, node, pos, ent); - ndbrequire(node.getChilds() <= 1); - // handle half-leaf - unsigned i; - for (i = 0; i <= 1; i++) { + if (node.getChilds() == 2) { + // underflow in interior node jam(); - TupLoc childLoc = node.getLink(i); - if (childLoc != NullTupLoc) { - // move to child - selectNode(signal, node, childLoc, AccFull); - // balance of half-leaf parent requires child to be leaf - break; - } + treeRemoveInner(frag, node, pos); + return; } - ndbrequire(node.getChilds() == 0); - // get parent if any - TupLoc parentLoc = node.getLink(2); - NodeHandle parentNode(frag); - i = node.getSide(); - // move all that fits into parent - if (parentLoc != NullTupLoc) { + // remove entry in semi/leaf + nodePopDown(node, pos, ent, 0); + if (node.getLink(0) != NullTupLoc) { jam(); - selectNode(signal, parentNode, node.getLink(2), AccFull); - nodeSlide(signal, parentNode, node, i); - // fall thru to next case + treeRemoveSemi(frag, node, 0); + return; } - // non-empty leaf - if (node.getOccup() >= 1) { + if (node.getLink(1) != NullTupLoc) { jam(); + treeRemoveSemi(frag, node, 1); return; } - // remove empty leaf - deleteNode(signal, node); - if (parentLoc == NullTupLoc) { + treeRemoveLeaf(frag, node); +} + +/* + * Remove entry when interior node underflows. There is g.l.b node in + * left subtree to borrow an entry from. The max entry of the g.l.b + * node becomes the min entry of this node. + */ +void +Dbtux::treeRemoveInner(Frag& frag, NodeHandle lubNode, unsigned pos) +{ + TreeHead& tree = frag.m_tree; + TreeEnt ent; + // find g.l.b node + NodeHandle glbNode(frag); + TupLoc loc = lubNode.getLink(0); + do { + jam(); + selectNode(glbNode, loc); + loc = glbNode.getLink(1); + } while (loc != NullTupLoc); + // borrow max entry from semi/leaf + Uint32 scanList = RNIL; + nodePopDown(glbNode, glbNode.getOccup() - 1, ent, &scanList); + nodePopUp(lubNode, pos, ent, scanList); + if (glbNode.getLink(0) != NullTupLoc) { jam(); - // tree is now empty - tree.m_root = NullTupLoc; + treeRemoveSemi(frag, glbNode, 0); return; } - node = parentNode; - node.setLink(i, NullTupLoc); -#ifdef dbtux_min_occup_less_max_occup - // check if we created a half-leaf - if (node.getBalance() == 0) { + treeRemoveLeaf(frag, glbNode); +} + +/* + * Handle semi-leaf after removing an entry. Move entries from leaf to + * semi-leaf to bring semi-leaf occupancy above minOccup, if possible. + * The leaf may become empty. + */ +void +Dbtux::treeRemoveSemi(Frag& frag, NodeHandle semiNode, unsigned i) +{ + TreeHead& tree = frag.m_tree; + ndbrequire(semiNode.getChilds() < 2); + TupLoc leafLoc = semiNode.getLink(i); + NodeHandle leafNode(frag); + selectNode(leafNode, leafLoc); + if (semiNode.getOccup() < tree.m_minOccup) { + jam(); + unsigned cnt = min(leafNode.getOccup(), tree.m_minOccup - semiNode.getOccup()); + nodeSlide(semiNode, leafNode, cnt, i); + if (leafNode.getOccup() == 0) { + // remove empty leaf + jam(); + treeRemoveNode(frag, leafNode); + } + } +} + +/* + * Handle leaf after removing an entry. If parent is semi-leaf, move + * entries to it as in the semi-leaf case. If parent is interior node, + * do nothing. + */ +void +Dbtux::treeRemoveLeaf(Frag& frag, NodeHandle leafNode) +{ + TreeHead& tree = frag.m_tree; + TupLoc parentLoc = leafNode.getLink(2); + if (parentLoc != NullTupLoc) { jam(); - // move entries from the other child - TupLoc childLoc = node.getLink(1 - i); - NodeHandle childNode(frag); - selectNode(signal, childNode, childLoc, AccFull); - nodeSlide(signal, node, childNode, 1 - i); - if (childNode.getOccup() == 0) { + NodeHandle parentNode(frag); + selectNode(parentNode, parentLoc); + unsigned i = leafNode.getSide(); + if (parentNode.getLink(1 - i) == NullTupLoc) { + // parent is semi-leaf jam(); - deleteNode(signal, childNode); - node.setLink(1 - i, NullTupLoc); - // we are balanced again but our parent balance changes by -1 - parentLoc = node.getLink(2); - if (parentLoc == NullTupLoc) { + if (parentNode.getOccup() < tree.m_minOccup) { jam(); - return; + unsigned cnt = min(leafNode.getOccup(), tree.m_minOccup - parentNode.getOccup()); + nodeSlide(parentNode, leafNode, cnt, i); } - // fix side and become parent - i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); } } -#endif - // re-balance tree at each node + if (leafNode.getOccup() == 0) { + jam(); + // remove empty leaf + treeRemoveNode(frag, leafNode); + } +} + +/* + * Remove empty leaf. + */ +void +Dbtux::treeRemoveNode(Frag& frag, NodeHandle leafNode) +{ + TreeHead& tree = frag.m_tree; + ndbrequire(leafNode.getChilds() == 0); + TupLoc parentLoc = leafNode.getLink(2); + unsigned i = leafNode.getSide(); + deleteNode(leafNode); + if (parentLoc != NullTupLoc) { + jam(); + NodeHandle parentNode(frag); + selectNode(parentNode, parentLoc); + parentNode.setLink(i, NullTupLoc); + // re-balance the tree + treeRemoveRebalance(frag, parentNode, i); + return; + } + // tree is now empty + tree.m_root = NullTupLoc; +} + +/* + * Re-balance tree after removing a node. The process starts with the + * parent of the removed node. + */ +void +Dbtux::treeRemoveRebalance(Frag& frag, NodeHandle node, unsigned i) +{ while (true) { // height of subtree i has decreased by 1 int j = (i == 0 ? -1 : +1); @@ -261,19 +343,19 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) jam(); // child on the other side NodeHandle childNode(frag); - selectNode(signal, childNode, node.getLink(1 - i), AccHead); + selectNode(childNode, node.getLink(1 - i)); int b2 = childNode.getBalance(); if (b2 == b) { jam(); - treeRotateSingle(signal, frag, node, 1 - i); + treeRotateSingle(frag, node, 1 - i); // height of tree decreased and propagates up } else if (b2 == -b) { jam(); - treeRotateDouble(signal, frag, node, 1 - i); + treeRotateDouble(frag, node, 1 - i); // height of tree decreased and propagates up } else { jam(); - treeRotateSingle(signal, frag, node, 1 - i); + treeRotateSingle(frag, node, 1 - i); // height of tree did not change - done return; } @@ -287,7 +369,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) return; } i = node.getSide(); - selectNode(signal, node, parentLoc, AccHead); + selectNode(node, parentLoc); } } @@ -308,10 +390,7 @@ Dbtux::treeRemove(Signal* signal, Frag& frag, TreePos treePos) * all optional. If 4 are there it changes side. */ void -Dbtux::treeRotateSingle(Signal* signal, - Frag& frag, - NodeHandle& node, - unsigned i) +Dbtux::treeRotateSingle(Frag& frag, NodeHandle& node, unsigned i) { ndbrequire(i <= 1); /* @@ -331,7 +410,7 @@ Dbtux::treeRotateSingle(Signal* signal, */ TupLoc loc3 = node5.getLink(i); NodeHandle node3(frag); - selectNode(signal, node3, loc3, AccHead); + selectNode(node3, loc3); const int bal3 = node3.getBalance(); /* 2 must always be there but is not changed. Thus we mereley check that it @@ -348,7 +427,7 @@ Dbtux::treeRotateSingle(Signal* signal, NodeHandle node4(frag); if (loc4 != NullTupLoc) { jam(); - selectNode(signal, node4, loc4, AccHead); + selectNode(node4, loc4); ndbrequire(node4.getSide() == (1 - i) && node4.getLink(2) == loc3); node4.setSide(i); @@ -383,7 +462,7 @@ Dbtux::treeRotateSingle(Signal* signal, if (loc0 != NullTupLoc) { jam(); NodeHandle node0(frag); - selectNode(signal, node0, loc0, AccHead); + selectNode(node0, loc0); node0.setLink(side5, loc3); } else { jam(); @@ -520,8 +599,10 @@ Dbtux::treeRotateSingle(Signal* signal, * */ void -Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i) +Dbtux::treeRotateDouble(Frag& frag, NodeHandle& node, unsigned i) { + TreeHead& tree = frag.m_tree; + // old top node NodeHandle node6 = node; const TupLoc loc6 = node6.m_loc; @@ -532,13 +613,13 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i // level 1 TupLoc loc2 = node6.getLink(i); NodeHandle node2(frag); - selectNode(signal, node2, loc2, AccHead); + selectNode(node2, loc2); const int bal2 = node2.getBalance(); // level 2 TupLoc loc4 = node2.getLink(1 - i); NodeHandle node4(frag); - selectNode(signal, node4, loc4, AccHead); + selectNode(node4, loc4); const int bal4 = node4.getBalance(); ndbrequire(i <= 1); @@ -555,25 +636,26 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i // fill up leaf before it becomes internal if (loc3 == NullTupLoc && loc5 == NullTupLoc) { jam(); - TreeHead& tree = frag.m_tree; - accessNode(signal, node2, AccFull); - accessNode(signal, node4, AccFull); - nodeSlide(signal, node4, node2, i); - // implied by rule of merging half-leaves with leaves - ndbrequire(node4.getOccup() >= tree.m_minOccup); - ndbrequire(node2.getOccup() != 0); + if (node4.getOccup() < tree.m_minOccup) { + jam(); + unsigned cnt = tree.m_minOccup - node4.getOccup(); + ndbrequire(cnt < node2.getOccup()); + nodeSlide(node4, node2, cnt, i); + ndbrequire(node4.getOccup() >= tree.m_minOccup); + ndbrequire(node2.getOccup() != 0); + } } else { if (loc3 != NullTupLoc) { jam(); NodeHandle node3(frag); - selectNode(signal, node3, loc3, AccHead); + selectNode(node3, loc3); node3.setLink(2, loc2); node3.setSide(1 - i); } if (loc5 != NullTupLoc) { jam(); NodeHandle node5(frag); - selectNode(signal, node5, loc5, AccHead); + selectNode(node5, loc5); node5.setLink(2, node6.m_loc); node5.setSide(i); } @@ -596,7 +678,7 @@ Dbtux::treeRotateDouble(Signal* signal, Frag& frag, NodeHandle& node, unsigned i if (loc0 != NullTupLoc) { jam(); - selectNode(signal, node0, loc0, AccHead); + selectNode(node0, loc0); node0.setLink(side6, loc4); } else { jam(); diff --git a/ndb/src/kernel/blocks/dbtux/Times.txt b/ndb/src/kernel/blocks/dbtux/Times.txt index 03473353a52..1e6d0a0a329 100644 --- a/ndb/src/kernel/blocks/dbtux/Times.txt +++ b/ndb/src/kernel/blocks/dbtux/Times.txt @@ -13,7 +13,7 @@ case c: full scan: index on PK Unsigned testOIBasic -case v -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -subloop 1 -nologging case d: scan 1 tuple via EQ: index on PK Unsigned -testOIBasic -case w -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -samples 10000 -subloop 1 -nologging -v2 +testOIBasic -case w -table 1 -index 1 -fragtype small -threads 10 -rows 100000 -samples 50000 -subloop 1 -nologging -v2 a, b 1 million rows, pk update without index, pk update with index @@ -29,6 +29,7 @@ shows ms / 1000 rows for each and index time overhead samples 10% of all PKs (100,000 pk reads, 100,000 scans) the "pct" values are from more accurate total times (not shown) +comments [ ... ] are after the case 040616 mc02/a 40 ms 87 ms 114 pct mc02/b 51 ms 128 ms 148 pct @@ -76,13 +77,12 @@ optim 13 mc02/a 40 ms 57 ms 42 pct mc02/c 9 ms 13 ms 50 pct mc02/d 170 ms 256 ms 50 pct -after wl-1884 store all-NULL keys (the tests have pctnull=10 per column) - optim 13 mc02/a 39 ms 59 ms 50 pct mc02/b 47 ms 77 ms 61 pct mc02/c 9 ms 12 ms 44 pct mc02/d 246 ms 289 ms 17 pct +[ after wl-1884 store all-NULL keys (the tests have pctnull=10 per column) ] [ case d: bug in testOIBasic killed PK read performance ] optim 14 mc02/a 41 ms 60 ms 44 pct @@ -98,8 +98,7 @@ none mc02/a 35 ms 60 ms 71 pct mc02/c 5 ms 12 ms 106 pct mc02/d 165 ms 238 ms 44 pct -[ johan re-installed mc02 as fedora gcc-3.3.2 ] -[ case c: table scan has improved... ] +[ johan re-installed mc02 as fedora gcc-3.3.2, tux uses more C++ stuff than tup] charsets mc02/a 35 ms 60 ms 71 pct mc02/b 42 ms 84 ms 97 pct @@ -108,4 +107,37 @@ charsets mc02/a 35 ms 60 ms 71 pct [ case b: TUX can no longer use pointers to TUP data ] +optim 15 mc02/a 34 ms 60 ms 72 pct + mc02/b 42 ms 85 ms 100 pct + mc02/c 5 ms 12 ms 110 pct + mc02/d 178 ms 242 ms 35 pct + +[ corrected wasted space in index node ] + +optim 16 mc02/a 34 ms 53 ms 53 pct + mc02/b 42 ms 75 ms 75 pct + +[ binary search of bounding node when adding entry ] + +none mc02/a 35 ms 53 ms 51 pct + mc02/b 42 ms 75 ms 76 pct + +[ rewrote treeAdd / treeRemove ] + +optim 17 mc02/a 35 ms 52 ms 49 pct + mc02/b 43 ms 75 ms 75 pct + +[ allow slack (2) in interior nodes - almost no effect?? ] + +wl-1942 mc02/a 35 ms 52 ms 49 pct + mc02/b 42 ms 75 ms 76 pct + +before mc02/c 5 ms 13 ms 126 pct + mc02/d 134 ms 238 ms 78 pct + +after mc02/c 5 ms 10 ms 70 pct + mc02/d 178 ms 242 ms 69 pct + +[ prelim preformance fix for max batch size 16 -> 992 ] + vim: set et: diff --git a/ndb/src/kernel/blocks/dbutil/DbUtil.cpp b/ndb/src/kernel/blocks/dbutil/DbUtil.cpp index 554fc693fb8..f5379689a5f 100644 --- a/ndb/src/kernel/blocks/dbutil/DbUtil.cpp +++ b/ndb/src/kernel/blocks/dbutil/DbUtil.cpp @@ -1059,6 +1059,7 @@ DbUtil::prepareOperation(Signal* signal, PreparePtr prepPtr) ndbrequire(prepPagesReader.getValueLen() <= MAX_ATTR_NAME_SIZE); prepPagesReader.getString(attrNameRequested); + attrIdRequested= ~0u; } else { jam(); attrIdRequested = prepPagesReader.getUint32(); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp index 1069cf93b06..43044eeebcd 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp @@ -37,10 +37,10 @@ void Ndbcntr::initRecords() Ndbcntr::Ndbcntr(const class Configuration & conf): SimulatedBlock(NDBCNTR, conf), - c_stopRec(* this), - c_missra(* this), cnoWaitrep6(0), - cnoWaitrep7(0) + cnoWaitrep7(0), + c_stopRec(* this), + c_missra(* this) { BLOCK_CONSTRUCTOR(Ndbcntr); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 568ed6c6566..089cf613b03 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -135,42 +135,42 @@ void Ndbcntr::execSYSTEM_ERROR(Signal* signal) jamEntry(); switch (sysErr->errorCode){ case SystemError::StartInProgressError: - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " "master start in progress error", killingNode); break; case SystemError::GCPStopDetected: - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " "GCP stop was detected", killingNode); break; case SystemError::ScanfragTimeout: - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " "a fragment scan timed out and could not be stopped", killingNode); break; case SystemError::ScanfragStateError: - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " "the state of a fragment scan was out of sync.", killingNode); break; case SystemError::CopyFragRefError: - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Node %d killed this node because " "it could not copy a fragment during node restart", killingNode); break; default: - snprintf(buf, sizeof(buf), "System error %d, " + BaseString::snprintf(buf, sizeof(buf), "System error %d, " " this node was killed by node %d", sysErr->errorCode, killingNode); break; diff --git a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index c61fccad22a..a02bfd459b3 100644 --- a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -119,7 +119,7 @@ AsyncFile::doStart(Uint32 nodeId, char buf[16]; numAsyncFiles++; - snprintf(buf, sizeof(buf), "AsyncFile%d", numAsyncFiles); + BaseString::snprintf(buf, sizeof(buf), "AsyncFile%d", numAsyncFiles); theStartMutexPtr = NdbMutex_Create(); theStartConditionPtr = NdbCondition_Create(); @@ -816,7 +816,7 @@ AsyncFile::rmrfReq(Request * request, char * path, bool removePath){ struct dirent * dp; while ((dp = readdir(dirp)) != NULL){ if ((strcmp(".", dp->d_name) != 0) && (strcmp("..", dp->d_name) != 0)) { - snprintf(path_add, (size_t)path_max_copy, "%s%s", + BaseString::snprintf(path_add, (size_t)path_max_copy, "%s%s", DIR_SEPARATOR, dp->d_name); if(remove((const char*)path) == 0){ path[path_len] = 0; diff --git a/ndb/src/kernel/blocks/ndbfs/Filename.cpp b/ndb/src/kernel/blocks/ndbfs/Filename.cpp index 28aa1d23df4..15158ec19ef 100644 --- a/ndb/src/kernel/blocks/ndbfs/Filename.cpp +++ b/ndb/src/kernel/blocks/ndbfs/Filename.cpp @@ -56,7 +56,7 @@ Filename::init(Uint32 nodeid, return; } - snprintf(theFileSystemDirectory, sizeof(theFileSystemDirectory), + BaseString::snprintf(theFileSystemDirectory, sizeof(theFileSystemDirectory), "%sndb_%u_fs%s", pFileSystemPath, nodeid, DIR_SEPARATOR); strncpy(theBackupDirectory, pBackupDirPath, sizeof(theBackupDirectory)); @@ -101,7 +101,7 @@ Filename::set(BlockReference blockReference, const Uint32 P_val = FsOpenReq::v1_getP(filenumber); if (diskNo < 0xff){ - snprintf(buf, sizeof(buf), "D%d%s", diskNo, DIR_SEPARATOR); + BaseString::snprintf(buf, sizeof(buf), "D%d%s", diskNo, DIR_SEPARATOR); strcat(theName, buf); theLevelDepth++; } @@ -112,31 +112,31 @@ Filename::set(BlockReference blockReference, ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","No Block Name"); return; } - snprintf(buf, sizeof(buf), "%s%s", blockName, DIR_SEPARATOR); + BaseString::snprintf(buf, sizeof(buf), "%s%s", blockName, DIR_SEPARATOR); strcat(theName, buf); theLevelDepth++; } if (table < 0xffffffff){ - snprintf(buf, sizeof(buf), "T%d%s", table, DIR_SEPARATOR); + BaseString::snprintf(buf, sizeof(buf), "T%d%s", table, DIR_SEPARATOR); strcat(theName, buf); theLevelDepth++; } if (frag < 0xffffffff){ - snprintf(buf, sizeof(buf), "F%d%s", frag, DIR_SEPARATOR); + BaseString::snprintf(buf, sizeof(buf), "F%d%s", frag, DIR_SEPARATOR); strcat(theName, buf); theLevelDepth++; } if (S_val < 0xffffffff){ - snprintf(buf, sizeof(buf), "S%d", S_val); + BaseString::snprintf(buf, sizeof(buf), "S%d", S_val); strcat(theName, buf); } if (P_val < 0xff){ - snprintf(buf, sizeof(buf), "P%d", P_val); + BaseString::snprintf(buf, sizeof(buf), "P%d", P_val); strcat(theName, buf); } @@ -147,14 +147,14 @@ Filename::set(BlockReference blockReference, const Uint32 nodeId = FsOpenReq::v2_getNodeId(filenumber); const Uint32 count = FsOpenReq::v2_getCount(filenumber); - snprintf(buf, sizeof(buf), "BACKUP%sBACKUP-%d%s", + BaseString::snprintf(buf, sizeof(buf), "BACKUP%sBACKUP-%d%s", DIR_SEPARATOR, seq, DIR_SEPARATOR); strcat(theName, buf); if(count == 0xffffffff) { - snprintf(buf, sizeof(buf), "BACKUP-%d.%d", + BaseString::snprintf(buf, sizeof(buf), "BACKUP-%d.%d", seq, nodeId); strcat(theName, buf); } else { - snprintf(buf, sizeof(buf), "BACKUP-%d-%d.%d", + BaseString::snprintf(buf, sizeof(buf), "BACKUP-%d-%d.%d", seq, count, nodeId); strcat(theName, buf); } theLevelDepth = 2; @@ -168,7 +168,7 @@ Filename::set(BlockReference blockReference, ERROR_SET(ecError, AFS_ERROR_PARAMETER,"","Invalid disk specification"); } - snprintf(buf, sizeof(buf), "D%d%s", diskNo, DIR_SEPARATOR); + BaseString::snprintf(buf, sizeof(buf), "D%d%s", diskNo, DIR_SEPARATOR); strcat(theName, buf); theLevelDepth++; } diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp index 6017365a463..41deb3403c8 100644 --- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp +++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp @@ -592,7 +592,7 @@ void Qmgr::execCM_REGCONF(Signal* signal) if (!ndbCompatible_ndb_ndb(NDB_VERSION, cmRegConf->presidentVersion)) { jam(); char buf[128]; - snprintf(buf,sizeof(buf),"incompatible version own=0x%x other=0x%x, shutting down", NDB_VERSION, cmRegConf->presidentVersion); + BaseString::snprintf(buf,sizeof(buf),"incompatible version own=0x%x other=0x%x, shutting down", NDB_VERSION, cmRegConf->presidentVersion); systemErrorLab(signal, buf); return; } @@ -1666,7 +1666,7 @@ void Qmgr::checkStartInterface(Signal* signal) } else { if(((nodePtr.p->alarmCount + 1) % 60) == 0){ char buf[100]; - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Failure handling of node %d has not completed in %d min." " - state = %d", nodePtr.i, @@ -1760,8 +1760,8 @@ void Qmgr::execAPI_FAILCONF(Signal* signal) } else { jam(); #ifdef VM_TRACE - ndbout << "failedNodePtr.p->failState = " << failedNodePtr.p->failState - << endl; + ndbout << "failedNodePtr.p->failState = " + << (Uint32)(failedNodePtr.p->failState) << endl; #endif systemErrorLab(signal); }//if @@ -1932,10 +1932,6 @@ void Qmgr::execAPI_REGREQ(Signal* signal) bool compatability_check; switch(getNodeInfo(apiNodePtr.i).getType()){ - case NodeInfo::DB: - case NodeInfo::INVALID: - sendApiRegRef(signal, ref, ApiRegRef::WrongType); - return; case NodeInfo::API: compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version); break; @@ -1945,6 +1941,11 @@ void Qmgr::execAPI_REGREQ(Signal* signal) case NodeInfo::REP: compatability_check = ndbCompatible_ndb_api(NDB_VERSION, version); break; + case NodeInfo::DB: + case NodeInfo::INVALID: + default: + sendApiRegRef(signal, ref, ApiRegRef::WrongType); + return; } if (!compatability_check) { @@ -2672,7 +2673,7 @@ void Qmgr::systemErrorBecauseOtherNodeFailed(Signal* signal, failReport(signal, getOwnNodeId(), (UintR)ZTRUE, FailRep::ZOWN_FAILURE); char buf[100]; - snprintf(buf, 100, + BaseString::snprintf(buf, 100, "Node was shutdown during startup because node %d failed", failedNodeId); diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp index 052809cb084..d11d5f7176a 100644 --- a/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/ndb/src/kernel/blocks/suma/Suma.cpp @@ -98,7 +98,7 @@ Suma::getNodeGroupMembers(Signal* signal) { } // ndbout_c("c_noNodesInGroup=%d", c_noNodesInGroup); - ndbrequire(c_noNodesInGroup >= 0); // at least 1 node in the nodegroup + ndbrequire(c_noNodesInGroup > 0); // at least 1 node in the nodegroup #ifdef NODEFAIL_DEBUG for (Uint32 i = 0; i < c_noNodesInGroup; i++) { @@ -1891,7 +1891,7 @@ SumaParticipant::SyncRecord::nextScan(Signal* signal){ ScanFragReq::setHoldLockFlag(req->requestInfo, 0); ScanFragReq::setKeyinfoFlag(req->requestInfo, 0); ScanFragReq::setAttrLen(req->requestInfo, attrLen); - req->fragmentNo = fd.m_fragDesc.m_fragmentNo; + req->fragmentNoKeyLen = fd.m_fragDesc.m_fragmentNo; req->schemaVersion = tabPtr.p->m_schemaVersion; req->transId1 = 0; req->transId2 = (SUMA << 20) + (suma.getOwnNodeId() << 8); @@ -2713,6 +2713,7 @@ Suma::getResponsibleSumaNodeId(Uint32 D) id = RNIL; } else { jam(); + id = RNIL; const Uint32 n = c_noNodesInGroup; // Number nodes in node group const Uint32 C1 = D / n; const Uint32 C2 = D - C1*n; // = D % n; diff --git a/ndb/src/kernel/error/ErrorReporter.cpp b/ndb/src/kernel/error/ErrorReporter.cpp index d43001ef1f5..35c99b30994 100644 --- a/ndb/src/kernel/error/ErrorReporter.cpp +++ b/ndb/src/kernel/error/ErrorReporter.cpp @@ -60,7 +60,7 @@ ErrorReporter::formatTimeStampString(){ DateTime.setTimeStamp(); - snprintf(theDateTimeString, 39, "%s %d %s %d - %s:%s:%s", + BaseString::snprintf(theDateTimeString, 39, "%s %d %s %d - %s:%s:%s", DateTime.getDayName(), DateTime.getDayOfMonth(), DateTime.getMonthName(), DateTime.getYear(), DateTime.getHour(), DateTime.getMinute(), DateTime.getSecond()); @@ -126,7 +126,7 @@ ErrorReporter::formatMessage(ErrorCategory type, processId = NdbHost_GetProcessId(); - snprintf(messptr, MESSAGE_LENGTH, + BaseString::snprintf(messptr, MESSAGE_LENGTH, "Date/Time: %s\nType of error: %s\n" "Message: %s\nFault ID: %d\nProblem data: %s" "\nObject of reference: %s\nProgramName: %s\n" @@ -157,13 +157,13 @@ ErrorReporter::handleAssert(const char* message, const char* file, int line) char refMessage[100]; #ifdef NO_EMULATED_JAM - snprintf(refMessage, 100, "file: %s lineNo: %d", + BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d", file, line); #else const Uint32 blockNumber = theEmulatedJamBlockNumber; const char *blockName = getBlockName(blockNumber); - snprintf(refMessage, 100, "%s line: %d (block: %s)", + BaseString::snprintf(refMessage, 100, "%s line: %d (block: %s)", file, line, blockName); #endif WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, @@ -178,7 +178,7 @@ ErrorReporter::handleThreadAssert(const char* message, int line) { char refMessage[100]; - snprintf(refMessage, 100, "file: %s lineNo: %d - %s", + BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", file, line, message); NdbShutdown(NST_ErrorHandler); diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 9c25da79065..fa44704807d 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -363,6 +363,6 @@ handler_error(int signum){ g_eventLogger.info("Received signal %d. Running error handler.", signum); // restart the system char errorData[40]; - snprintf(errorData, 40, "Signal %d received", signum); + BaseString::snprintf(errorData, 40, "Signal %d received", signum); ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__); } diff --git a/ndb/src/kernel/vm/ClusterConfiguration.cpp b/ndb/src/kernel/vm/ClusterConfiguration.cpp index 3a6478380d1..d5bd03f69d5 100644 --- a/ndb/src/kernel/vm/ClusterConfiguration.cpp +++ b/ndb/src/kernel/vm/ClusterConfiguration.cpp @@ -358,7 +358,7 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ for(int i = 0; i<sz; i++){ if(!db.get(tmp[i].attrib, tmp[i].storage)){ char buf[255]; - snprintf(buf, sizeof(buf), "%s not found", tmp[i].attrib); + BaseString::snprintf(buf, sizeof(buf), "%s not found", tmp[i].attrib); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } } @@ -406,7 +406,7 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ for(unsigned j = 0; j<nodeNo; j++){ if(cd.nodeData[j].nodeId == nodeId){ char buf[255]; - snprintf(buf, sizeof(buf), "Two node can not have the same node id"); + BaseString::snprintf(buf, sizeof(buf), "Two node can not have the same node id"); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } } @@ -429,12 +429,12 @@ void ClusterConfiguration::init(const Properties & p, const Properties & db){ if(nodeId > MAX_NDB_NODES){ char buf[255]; - snprintf(buf, sizeof(buf), "Maximum node id for a ndb node is: %d", MAX_NDB_NODES); + BaseString::snprintf(buf, sizeof(buf), "Maximum node id for a ndb node is: %d", MAX_NDB_NODES); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } if(cd.SizeAltData.noOfNDBNodes > MAX_NDB_NODES){ char buf[255]; - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Maximum %d ndb nodes is allowed in the cluster", MAX_NDB_NODES); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index fd5d79b92e7..706f60fd9cf 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -203,7 +203,7 @@ Configuration::fetch_configuration(LocalConfig &local_config){ /* Set stop on error to true otherwise NDB will go into an restart loop... */ - ERROR_SET(fatal, ERR_INVALID_CONFIG, "Could connect to ndb_mgmd", s); + ERROR_SET(fatal, ERR_INVALID_CONFIG, "Could not connect to ndb_mgmd", s); } m_mgmd_port= m_config_retriever->get_mgmd_port(); @@ -487,7 +487,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ if (tmp[i].computable) { *tmp[i].storage = 0; } else { - snprintf(buf, sizeof(buf),"ConfigParam: %d not found", tmp[i].paramId); + BaseString::snprintf(buf, sizeof(buf),"ConfigParam: %d not found", tmp[i].paramId); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } } @@ -497,12 +497,12 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ ndb_mgm_get_int64_parameter(&db, CFG_DB_DATA_MEM, &dataMem); ndb_mgm_get_int64_parameter(&db, CFG_DB_INDEX_MEM, &indexMem); if(dataMem == 0){ - snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_DATA_MEM); + BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_DATA_MEM); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } if(indexMem == 0){ - snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_INDEX_MEM); + BaseString::snprintf(buf, sizeof(buf), "ConfigParam: %d not found", CFG_DB_INDEX_MEM); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } @@ -535,13 +535,13 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ } if(nodeId > MAX_NODES || nodeId == 0){ - snprintf(buf, sizeof(buf), + BaseString::snprintf(buf, sizeof(buf), "Invalid node id: %d", nodeId); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } if(nodes.get(nodeId)){ - snprintf(buf, sizeof(buf), "Two node can not have the same node id: %d", + BaseString::snprintf(buf, sizeof(buf), "Two node can not have the same node id: %d", nodeId); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } @@ -568,7 +568,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ case NODE_TYPE_EXT_REP: break; default: - snprintf(buf, sizeof(buf), "Unknown node type: %d", nodeType); + BaseString::snprintf(buf, sizeof(buf), "Unknown node type: %d", nodeType); ERROR_SET(fatal, ERR_INVALID_CONFIG, msg, buf); } } diff --git a/ndb/src/kernel/vm/SignalCounter.hpp b/ndb/src/kernel/vm/SignalCounter.hpp index ea770324aa6..62242cb65bd 100644 --- a/ndb/src/kernel/vm/SignalCounter.hpp +++ b/ndb/src/kernel/vm/SignalCounter.hpp @@ -151,7 +151,7 @@ const char * SignalCounter::getText() const { static char buf[255]; static char nodes[NodeBitmask::TextLength+1]; - snprintf(buf, sizeof(buf), "[SignalCounter: m_count=%d %s]", m_count, m_nodes.getText(nodes)); + BaseString::snprintf(buf, sizeof(buf), "[SignalCounter: m_count=%d %s]", m_count, m_nodes.getText(nodes)); return buf; } diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index 18b7f474ddc..e6b97771d36 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -68,25 +68,25 @@ SimulatedBlock::SimulatedBlock(BlockNumber blockNumber, char buf[255]; count = 10; - snprintf(buf, 255, "%s.FragmentSendPool", getBlockName(blockNumber)); + BaseString::snprintf(buf, 255, "%s.FragmentSendPool", getBlockName(blockNumber)); if(!p->get(buf, &count)) p->get("FragmentSendPool", &count); c_fragmentSendPool.setSize(count); count = 10; - snprintf(buf, 255, "%s.FragmentInfoPool", getBlockName(blockNumber)); + BaseString::snprintf(buf, 255, "%s.FragmentInfoPool", getBlockName(blockNumber)); if(!p->get(buf, &count)) p->get("FragmentInfoPool", &count); c_fragmentInfoPool.setSize(count); count = 10; - snprintf(buf, 255, "%s.FragmentInfoHash", getBlockName(blockNumber)); + BaseString::snprintf(buf, 255, "%s.FragmentInfoHash", getBlockName(blockNumber)); if(!p->get(buf, &count)) p->get("FragmentInfoHash", &count); c_fragmentInfoHash.setSize(count); count = 5; - snprintf(buf, 255, "%s.ActiveMutexes", getBlockName(blockNumber)); + BaseString::snprintf(buf, 255, "%s.ActiveMutexes", getBlockName(blockNumber)); if(!p->get(buf, &count)) p->get("ActiveMutexes", &count); c_mutexMgr.setSize(count); @@ -147,7 +147,7 @@ SimulatedBlock::addRecSignalImpl(GlobalSignalNumber gsn, ExecFunction f, bool force){ if(gsn > MAX_GSN || (!force && theExecArray[gsn] != 0)){ char errorMsg[255]; - snprintf(errorMsg, 255, + BaseString::snprintf(errorMsg, 255, "Illeagal signal (%d %d)", gsn, MAX_GSN); ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); } @@ -159,9 +159,9 @@ SimulatedBlock::signal_error(Uint32 gsn, Uint32 len, Uint32 recBlockNo, const char* filename, int lineno) const { char objRef[255]; - snprintf(objRef, 255, "%s:%d", filename, lineno); + BaseString::snprintf(objRef, 255, "%s:%d", filename, lineno); char probData[255]; - snprintf(probData, 255, + BaseString::snprintf(probData, 255, "Signal (GSN: %d, Length: %d, Rec Block No: %d)", gsn, len, recBlockNo); @@ -664,9 +664,9 @@ SimulatedBlock::allocRecord(const char * type, size_t s, size_t n, bool clear) if (p == NULL){ char buf1[255]; char buf2[255]; - snprintf(buf1, sizeof(buf1), "%s could not allocate memory for %s", + BaseString::snprintf(buf1, sizeof(buf1), "%s could not allocate memory for %s", getBlockName(number()), type); - snprintf(buf2, sizeof(buf2), "Requested: %ux%u = %u bytes", + BaseString::snprintf(buf2, sizeof(buf2), "Requested: %ux%u = %u bytes", (Uint32)s, (Uint32)n, (Uint32)size); ERROR_SET(fatal, ERR_MEMALLOC, buf1, buf2); } @@ -722,7 +722,7 @@ SimulatedBlock::progError(int line, int err_code, const char* extra) const { /* Add line number to block name */ char buf[100]; - snprintf(&buf[0], 100, "%s (Line: %d) 0x%.8x", + BaseString::snprintf(&buf[0], 100, "%s (Line: %d) 0x%.8x", aBlockName, line, magicStatus); ErrorReporter::handleError(ecError, err_code, extra, buf); @@ -740,7 +740,7 @@ SimulatedBlock::infoEvent(const char * msg, ...) const { va_list ap; va_start(ap, msg); - vsnprintf(buf, 96, msg, ap); // 96 = 100 - 4 + BaseString::vsnprintf(buf, 96, msg, ap); // 96 = 100 - 4 va_end(ap); int len = strlen(buf) + 1; @@ -781,7 +781,7 @@ SimulatedBlock::warningEvent(const char * msg, ...) const { va_list ap; va_start(ap, msg); - vsnprintf(buf, 96, msg, ap); // 96 = 100 - 4 + BaseString::vsnprintf(buf, 96, msg, ap); // 96 = 100 - 4 va_end(ap); int len = strlen(buf) + 1; diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index 6d46e9cc377..7972cb39746 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -472,11 +472,11 @@ SimulatedBlock::executeFunction(GlobalSignalNumber gsn, Signal* signal){ */ char errorMsg[255]; if (!(gsn <= MAX_GSN)) { - snprintf(errorMsg, 255, "Illegal signal received (GSN %d too high)", gsn); + BaseString::snprintf(errorMsg, 255, "Illegal signal received (GSN %d too high)", gsn); ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); } if (!(theExecArray[gsn] != 0)) { - snprintf(errorMsg, 255, "Illegal signal received (GSN %d not added)", gsn); + BaseString::snprintf(errorMsg, 255, "Illegal signal received (GSN %d not added)", gsn); ERROR_SET(fatal, ERR_ERROR_PRGERR, errorMsg, errorMsg); } ndbrequire(false); diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index fccd5c7983b..4b62df968b3 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -15,6 +15,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <ndb_global.h> +#include <my_sys.h> + +#include <NdbAutoPtr.hpp> #include <NdbTCP.h> #include "mgmapi.h" @@ -107,7 +110,7 @@ setError(NdbMgmHandle h, int error, int error_line, const char * msg, ...){ va_list ap; va_start(ap, msg); - vsnprintf(h->last_error_desc, sizeof(h->last_error_desc), msg, ap); + BaseString::vsnprintf(h->last_error_desc, sizeof(h->last_error_desc), msg, ap); va_end(ap); } @@ -137,7 +140,8 @@ extern "C" NdbMgmHandle ndb_mgm_create_handle() { - NdbMgmHandle h = (NdbMgmHandle)malloc(sizeof(ndb_mgm_handle)); + NdbMgmHandle h = + (NdbMgmHandle)my_malloc(sizeof(ndb_mgm_handle),MYF(MY_WME)); h->connected = 0; h->last_error = 0; h->last_error_line = 0; @@ -166,16 +170,14 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle) if((* handle)->connected){ ndb_mgm_disconnect(* handle); } - if((* handle)->hostname != 0){ - free((* handle)->hostname); - } + my_free((* handle)->hostname,MYF(MY_ALLOW_ZERO_PTR)); #ifdef MGMAPI_LOG if ((* handle)->logfile != 0){ fclose((* handle)->logfile); (* handle)->logfile = 0; } #endif - free(* handle); + my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR)); * handle = 0; } @@ -228,7 +230,8 @@ parse_connect_string(const char * connect_string, return -1; } - char * line = strdup(connect_string); + char * line = my_strdup(connect_string,MYF(MY_WME)); + My_auto_ptr<char> ap1(line); if(line == 0){ SET_ERROR(handle, NDB_MGM_OUT_OF_MEMORY, ""); return -1; @@ -236,7 +239,6 @@ parse_connect_string(const char * connect_string, char * tmp = strchr(line, ':'); if(tmp == 0){ - free(line); SET_ERROR(handle, NDB_MGM_OUT_OF_MEMORY, ""); return -1; } @@ -244,17 +246,13 @@ parse_connect_string(const char * connect_string, int port = 0; if(sscanf(tmp, "%d", &port) != 1){ - free(line); SET_ERROR(handle, NDB_MGM_ILLEGAL_PORT_NUMBER, ""); return -1; } - if(handle->hostname != 0) - free(handle->hostname); - - handle->hostname = strdup(line); + my_free(handle->hostname,MYF(MY_ALLOW_ZERO_PTR)); + handle->hostname = my_strdup(line,MYF(MY_WME)); handle->port = port; - free(line); return 0; } @@ -361,7 +359,7 @@ ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv) * Open the log file */ char logname[64]; - snprintf(logname, 64, "mgmapi.log"); + BaseString::snprintf(logname, 64, "mgmapi.log"); handle->logfile = fopen(logname, "w"); #endif @@ -1153,11 +1151,14 @@ ndb_mgm_dump_state(NdbMgmHandle handle, int nodeId, int* _args, CHECK_CONNECTED(handle, -1); char buf[256]; - char buf2[6]; buf[0] = 0; for (int i = 0; i < _num_args; i++){ - snprintf(buf2, 6, "%d ", _args[i]); - strncat(buf, buf2, 256); + unsigned n = strlen(buf); + if (n + 20 > sizeof(buf)) { + SET_ERROR(handle, NDB_MGM_USAGE_ERROR, "arguments too long"); + return -1; + } + sprintf(buf + n, "%s%d", i ? " " : "", _args[i]); } Properties args; @@ -1653,8 +1654,11 @@ ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, unsigned *pnodei do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ + BaseString err; + err.assfmt("Could not alloc node id at %s port %d: %s", + handle->hostname, handle->port, buf); setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, - "Could not alloc node id: %s",buf); + err.c_str()); break; } if(!prop->get("nodeid", pnodeid) != 0){ diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index 7560a59a1ef..e0935c2104e 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -828,6 +828,8 @@ CommandInterpreter::executeShow(char* parameters) case NDB_MGM_NODE_TYPE_UNKNOWN: ndbout << "Error: Unknown Node Type" << endl; return; + case NDB_MGM_NODE_TYPE_REP: + abort(); } } @@ -1363,36 +1365,29 @@ CommandInterpreter::executeLog(int processId, if (! parseBlockSpecification(parameters, blocks)) { return; } - int len=0; + int len=1; Uint32 i; for(i=0; i<blocks.size(); i++) { - ndbout_c("blocks %s %d",blocks[i], strlen(blocks[i])); - len += strlen(blocks[i]); + len += strlen(blocks[i]) + 1; } - len += blocks.size()*2; char * blockNames = (char*)my_malloc(len,MYF(MY_WME)); My_auto_ptr<char> ap1(blockNames); + blockNames[0] = 0; for(i=0; i<blocks.size(); i++) { strcat(blockNames, blocks[i]); strcat(blockNames, "|"); } - strcat(blockNames, "\0"); - ndbout_c("blocknames %s", blockNames); - /*int res =*/ndb_mgm_log_signals(m_mgmsrv, + int result = ndb_mgm_log_signals(m_mgmsrv, processId, NDB_MGM_SIGNAL_LOG_MODE_INOUT, blockNames, &reply); - -#if 0 - int result = - _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::InOut, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute LOG on node %d failed.", processId); + printError(); } -#endif } //***************************************************************************** @@ -1401,17 +1396,7 @@ void CommandInterpreter::executeLogIn(int /* processId */, const char* parameters, bool /* all */) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGIN not implemented." << endl; } //***************************************************************************** @@ -1420,19 +1405,7 @@ void CommandInterpreter::executeLogOut(int /*processId*/, const char* parameters, bool /*all*/) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out, - blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGOUT not implemented." << endl; } //***************************************************************************** @@ -1441,57 +1414,45 @@ void CommandInterpreter::executeLogOff(int /*processId*/, const char* parameters, bool /*all*/) { - Vector<const char*> blocks; - if (! parseBlockSpecification(parameters, blocks)) { - return; - } - - -#if 0 - int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off, - blocks); - if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; - } -#endif + ndbout << "Command LOGOFF not implemented." << endl; } //***************************************************************************** //***************************************************************************** void -CommandInterpreter::executeTestOn(int /*processId*/, +CommandInterpreter::executeTestOn(int processId, const char* parameters, bool /*all*/) { if (! emptyString(parameters)) { ndbout << "No parameters expected to this command." << endl; return; } - -#if 0 - int result = _mgmtSrvr.startSignalTracing(processId); + connect(); + struct ndb_mgm_reply reply; + int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute TESTON failed."); + printError(); } -#endif } //***************************************************************************** //***************************************************************************** void -CommandInterpreter::executeTestOff(int /*processId*/, +CommandInterpreter::executeTestOff(int processId, const char* parameters, bool /*all*/) { if (! emptyString(parameters)) { ndbout << "No parameters expected to this command." << endl; return; } - -#if 0 - int result = _mgmtSrvr.stopSignalTracing(processId); + connect(); + struct ndb_mgm_reply reply; + int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout_c("Execute TESTOFF failed."); + printError(); } -#endif } @@ -1679,7 +1640,7 @@ CommandInterpreter::executeStartBackup(char* /*parameters*/) if(tmp) { ndbout << tmp; - int id; + unsigned int id; if(sscanf(tmp, "%*[^:]: Backup %d ", &id) == 1 && id == backupId){ count++; } @@ -2059,46 +2020,46 @@ CmdBackupCallback(const MgmtSrvr::BackupEvent & event){ switch(event.Event){ case MgmtSrvr::BackupEvent::BackupStarted: ok = true; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), "Backup %d started", event.Started.BackupId); break; case MgmtSrvr::BackupEvent::BackupFailedToStart: ok = true; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), "Backup failed to start (Error %d)", event.FailedToStart.ErrorCode); break; case MgmtSrvr::BackupEvent::BackupCompleted: ok = true; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), "Backup %d completed", event.Completed.BackupId); ndbout << str << endl; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), " StartGCP: %d StopGCP: %d", event.Completed.startGCP, event.Completed.stopGCP); ndbout << str << endl; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), " #Records: %d #LogRecords: %d", event.Completed.NoOfRecords, event.Completed.NoOfLogRecords); ndbout << str << endl; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), " Data: %d bytes Log: %d bytes", event.Completed.NoOfBytes, event.Completed.NoOfLogBytes); break; case MgmtSrvr::BackupEvent::BackupAborted: ok = true; - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), "Backup %d has been aborted reason %d", event.Aborted.BackupId, event.Aborted.Reason); break; } if(!ok){ - snprintf(str, sizeof(str), + BaseString::snprintf(str, sizeof(str), "Unknown backup event: %d", event.Event); diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp index 69f968677cd..cc6d4bf600e 100644 --- a/ndb/src/mgmclient/main.cpp +++ b/ndb/src/mgmclient/main.cpp @@ -85,7 +85,7 @@ int main(int argc, const char** argv){ } char buf[MAXHOSTNAMELEN+10]; - snprintf(buf, sizeof(buf), "%s:%d", _host, _port); + BaseString::snprintf(buf, sizeof(buf), "%s:%d", _host, _port); ndbout << "-- NDB Cluster -- Management Client --" << endl; printf("Connecting to Management Server: %s\n", buf); diff --git a/ndb/src/mgmsrv/CommandInterpreter.cpp b/ndb/src/mgmsrv/CommandInterpreter.cpp index 2c2aeda21ed..2a054a01f1e 100644 --- a/ndb/src/mgmsrv/CommandInterpreter.cpp +++ b/ndb/src/mgmsrv/CommandInterpreter.cpp @@ -647,6 +647,7 @@ versionCallback(int nodeId, int version, void * anyData, int errCode){ } break; case NDB_MGM_NODE_TYPE_UNKNOWN: + case NDB_MGM_NODE_TYPE_REP: abort(); }; diff --git a/ndb/src/mgmsrv/Config.cpp b/ndb/src/mgmsrv/Config.cpp index b8a494cb759..f9c6a23f909 100644 --- a/ndb/src/mgmsrv/Config.cpp +++ b/ndb/src/mgmsrv/Config.cpp @@ -85,6 +85,9 @@ Config::printAllNameValuePairs(NdbOut &out, MGM_REQUIRE(prop->get(n, &str_value)); out << str_value; break; + case ConfigInfo::SECTION: + out << "SECTION"; + break; } out << endl; } diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index bff7f9be0e6..ad346b30ead 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -2189,7 +2189,7 @@ ConfigInfo::ConfigInfo() break; } case SECTION: - pinfo.put("SectionType", (Uint32)param._default); + pinfo.put("SectionType", (Uint32)UintPtr(param._default)); break; case STRING: break; @@ -2504,7 +2504,7 @@ transformNode(InitConfigFileParser::Context & ctx, const char * data){ } ctx.m_userProperties.put("AllocatedNodeId_", id, id); - snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id); ctx.m_currentSection->put("Type", ctx.fname); @@ -2569,7 +2569,7 @@ fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data){ const Properties * computer; char tmp[255]; - snprintf(tmp, sizeof(tmp), "Computer_%s", compId); + BaseString::snprintf(tmp, sizeof(tmp), "Computer_%s", compId); if(!ctx.m_config->get(tmp, &computer)){ ctx.reportError("Computer \"%s\" not declared" "- [%s] starting at line: %d", @@ -2647,7 +2647,7 @@ transformExtNode(InitConfigFileParser::Context & ctx, const char * data){ ctx.m_userProperties.get("ExtNoOfNodes", &nodes); require(ctx.m_userProperties.put("ExtNoOfNodes",++nodes, true)); - snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s:Node_%d", + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s:Node_%d", systemName, id); return true; @@ -2661,7 +2661,7 @@ transformConnection(InitConfigFileParser::Context & ctx, const char * data){ Uint32 connections = 0; ctx.m_userProperties.get("NoOfConnections", &connections); - snprintf(ctx.pname, sizeof(ctx.pname), "Connection_%d", connections); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Connection_%d", connections); ctx.m_userProperties.put("NoOfConnections", ++connections, true); ctx.m_currentSection->put("Type", ctx.fname); @@ -2684,7 +2684,7 @@ transformSystem(InitConfigFileParser::Context & ctx, const char * data){ ndbout << "transformSystem " << name << endl; - snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name); return true; } @@ -2701,7 +2701,7 @@ transformExternalSystem(InitConfigFileParser::Context & ctx, const char * data){ ctx.fname, ctx.m_sectionLineno); return false; } - snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s", name); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s", name); return true; } @@ -2718,7 +2718,7 @@ transformComputer(InitConfigFileParser::Context & ctx, const char * data){ ctx.fname, ctx.m_sectionLineno); return false; } - snprintf(ctx.pname, sizeof(ctx.pname), "Computer_%s", id); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Computer_%s", id); Uint32 computers = 0; ctx.m_userProperties.get("NoOfComputers", &computers); @@ -2894,7 +2894,7 @@ fixExtConnection(InitConfigFileParser::Context & ctx, const char * data){ require(ctx.m_userProperties.put("ExtNoOfConnections",++connections, true)); char tmpLine1[MAX_LINE_LENGTH]; - snprintf(tmpLine1, MAX_LINE_LENGTH, "Connection_%d", connections-1); + BaseString::snprintf(tmpLine1, MAX_LINE_LENGTH, "Connection_%d", connections-1); /** * Section: EXTERNAL SYSTEM_<Ext System Name> @@ -3405,9 +3405,9 @@ add_node_connections(Vector<ConfigInfo::ConfigRuleSection>§ions, s.m_sectionType= BaseString("TCP"); s.m_sectionData= new Properties(true); char buf[16]; - snprintf(buf, sizeof(buf), "%u", nodeId1); + BaseString::snprintf(buf, sizeof(buf), "%u", nodeId1); s.m_sectionData->put("NodeId1", buf); - snprintf(buf, sizeof(buf), "%u", nodeId2); + BaseString::snprintf(buf, sizeof(buf), "%u", nodeId2); s.m_sectionData->put("NodeId2", buf); sections.push_back(s); } @@ -3422,9 +3422,9 @@ add_node_connections(Vector<ConfigInfo::ConfigRuleSection>§ions, s.m_sectionType= BaseString("TCP"); s.m_sectionData= new Properties(true); char buf[16]; - snprintf(buf, sizeof(buf), "%u", nodeId1); + BaseString::snprintf(buf, sizeof(buf), "%u", nodeId1); s.m_sectionData->put("NodeId1", buf); - snprintf(buf, sizeof(buf), "%u", nodeId2); + BaseString::snprintf(buf, sizeof(buf), "%u", nodeId2); s.m_sectionData->put("NodeId2", buf); sections.push_back(s); } @@ -3559,7 +3559,7 @@ check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>§ions, { unsigned c= 0; p_db_hosts.get(str.c_str(),&c); - if (c+1 == (1 << (replicas-1))) // all nodes on same machine + if (c+1 == (1u << (replicas-1))) // all nodes on same machine node_group_warning.append(".\n Host failure will " "cause complete cluster shutdown."); else if (c > 0) diff --git a/ndb/src/mgmsrv/InitConfigFileParser.cpp b/ndb/src/mgmsrv/InitConfigFileParser.cpp index 652e0f96190..fdfe7823fc2 100644 --- a/ndb/src/mgmsrv/InitConfigFileParser.cpp +++ b/ndb/src/mgmsrv/InitConfigFileParser.cpp @@ -42,7 +42,7 @@ InitConfigFileParser::~InitConfigFileParser() { // Read Config File //**************************************************************************** InitConfigFileParser::Context::Context(const ConfigInfo * info) - : m_configValues(1000, 20), m_userProperties(true) { + : m_userProperties(true), m_configValues(1000, 20) { m_config = new Properties(true); m_defaults = new Properties(true); @@ -110,7 +110,7 @@ InitConfigFileParser::parseConfig(FILE * file) { "of configuration file."); return 0; } - snprintf(ctx.fname, sizeof(ctx.fname), section); free(section); + BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section); ctx.type = InitConfigFileParser::DefaultSection; ctx.m_sectionLineno = ctx.m_lineno; ctx.m_currentSection = new Properties(true); @@ -130,7 +130,7 @@ InitConfigFileParser::parseConfig(FILE * file) { "of configuration file."); return 0; } - snprintf(ctx.fname, sizeof(ctx.fname), section); + BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section); ctx.type = InitConfigFileParser::Section; ctx.m_sectionLineno = ctx.m_lineno; @@ -172,7 +172,7 @@ InitConfigFileParser::parseConfig(FILE * file) { return 0; for(size_t j = 0; j<tmp.size(); j++){ - snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str()); + BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str()); ctx.type = InitConfigFileParser::Section; ctx.m_currentSection = tmp[j].m_sectionData; ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults); @@ -198,7 +198,7 @@ InitConfigFileParser::parseConfig(FILE * file) { ctx.m_config->put("NoOfNodes", nNodes); char tmpLine[MAX_LINE_LENGTH]; - snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_"); + BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_"); strncat(tmpLine, system, MAX_LINE_LENGTH); strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH); ctx.m_config->put(tmpLine, nExtConnections); @@ -349,6 +349,8 @@ InitConfigFileParser::storeNameValuePair(Context& ctx, case ConfigInfo::STRING: MGM_REQUIRE(ctx.m_currentSection->put(pname, value)); break; + case ConfigInfo::SECTION: + abort(); } return true; } @@ -547,13 +549,13 @@ InitConfigFileParser::storeSection(Context& ctx){ for(int i = strlen(ctx.fname) - 1; i>=0; i--){ ctx.fname[i] = toupper(ctx.fname[i]); } - snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname); + BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname); char buf[255]; if(ctx.type == InitConfigFileParser::Section) - snprintf(buf, sizeof(buf), "%s", ctx.fname); + BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname); if(ctx.type == InitConfigFileParser::DefaultSection) - snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname); - snprintf(ctx.fname, sizeof(ctx.fname), buf); + BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname); + BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf); if(ctx.type == InitConfigFileParser::Section){ for(int i = 0; i<m_info->m_NoOfRules; i++){ const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i]; @@ -579,7 +581,7 @@ InitConfigFileParser::Context::reportError(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); ndbout << "Error line " << m_lineno << ": " << buf << endl; va_end(ap); @@ -593,7 +595,7 @@ InitConfigFileParser::Context::reportWarning(const char * fmt, ...){ va_start(ap, fmt); if (fmt != 0) - vsnprintf(buf, sizeof(buf)-1, fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); ndbout << "Warning line " << m_lineno << ": " << buf << endl; va_end(ap); } diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 92a8025295f..fdaa61973d8 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -123,7 +123,7 @@ MgmtSrvr::signalRecvThreadRun() while(!_isStopThread) { SigMatch *handler = NULL; NdbApiSignal *signal = NULL; - if(m_signalRecvQueue.waitFor(siglist, handler, signal)) { + if(m_signalRecvQueue.waitFor(siglist, handler, signal, DEFAULT_TIMEOUT)) { if(handler->function != 0) (this->*handler->function)(signal); } @@ -1825,7 +1825,7 @@ const char* MgmtSrvr::getErrorText(int errorCode) } } - snprintf(text, 255, "Unknown management server error code %d", errorCode); + BaseString::snprintf(text, 255, "Unknown management server error code %d", errorCode); return text; } diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 5242237a638..201168c1726 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -1008,8 +1008,9 @@ MgmApiSession::stop(Parser<MgmApiSession>::Context &, } int stop_self= 0; + size_t i; - for(size_t i=0; i < nodes.size(); i++) { + for(i=0; i < nodes.size(); i++) { if (nodes[i] == m_mgmsrv.getOwnNodeId()) { stop_self= 1; if (i != nodes.size()-1) { @@ -1023,7 +1024,7 @@ MgmApiSession::stop(Parser<MgmApiSession>::Context &, int stopped = 0, result = 0; - for(size_t i=0; i < nodes.size(); i++) + for(i=0; i < nodes.size(); i++) if (nodes[i] != m_mgmsrv.getOwnNodeId()) { if((result = m_mgmsrv.stopNode(nodes[i], abort != 0)) == 0) stopped++; @@ -1122,7 +1123,7 @@ MgmApiSession::logSignals(Parser<MgmApiSession>::Context &, args.get("blocks", blockList); // fast fix - pekka char buf[200]; - snprintf(buf, 200, "%s", blockList.c_str()); + BaseString::snprintf(buf, 200, "%s", blockList.c_str()); Vector<BaseString> blocks; blockName=strtok(buf,"|"); @@ -1252,8 +1253,9 @@ MgmStatService::log(int eventType, const Uint32* theData, NodeId nodeId){ Uint32 threshold = 0; LogLevel::EventCategory cat; - - for(unsigned i = 0; i<EventLogger::matrixSize; i++){ + int i; + + for(i = 0; (unsigned)i<EventLogger::matrixSize; i++){ if(EventLogger::matrix[i].eventType == eventType){ cat = EventLogger::matrix[i].eventCategory; threshold = EventLogger::matrix[i].threshold; @@ -1266,7 +1268,6 @@ MgmStatService::log(int eventType, const Uint32* theData, NodeId nodeId){ Vector<NDB_SOCKET_TYPE> copy; m_clients.lock(); - int i; for(i = m_clients.size() - 1; i >= 0; i--){ if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat)){ if(m_clients[i].m_socket >= 0 && @@ -1279,14 +1280,14 @@ MgmStatService::log(int eventType, const Uint32* theData, NodeId nodeId){ } m_clients.unlock(); - for(i = 0; (unsigned)i<copy.size(); i++){ + for(i = 0; (unsigned)i < copy.size(); i++){ NDB_CLOSE_SOCKET(copy[i]); } if(copy.size()){ LogLevel tmp; tmp.clear(); m_clients.lock(); - for(i = 0; i < m_clients.size(); i++){ + for(i = 0; (unsigned)i < m_clients.size(); i++){ tmp.set_max(m_clients[i].m_logLevel); } m_clients.unlock(); diff --git a/ndb/src/mgmsrv/SignalQueue.cpp b/ndb/src/mgmsrv/SignalQueue.cpp index 7003f5c0a89..08ad5f363a6 100644 --- a/ndb/src/mgmsrv/SignalQueue.cpp +++ b/ndb/src/mgmsrv/SignalQueue.cpp @@ -14,8 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <string.h> - +#include <ndb_global.h> #include "SignalQueue.hpp" SignalQueue::SignalQueue() { diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 1a2b95391a9..51282416c24 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -131,6 +131,7 @@ int num_args = sizeof(args) / sizeof(args[0]); */ NDB_MAIN(mgmsrv){ ndb_init(); + /** * OSE specific. Enable shared ownership of file system resources. * This is needed in order to use the cluster log since the events @@ -266,12 +267,12 @@ NDB_MAIN(mgmsrv){ mapi->setMgm(glob.mgmObject); char msg[256]; - snprintf(msg, sizeof(msg), + BaseString::snprintf(msg, sizeof(msg), "NDB Cluster Management Server. %s", NDB_VERSION_STRING); ndbout_c(msg); g_EventLogger.info(msg); - snprintf(msg, 256, "Id: %d, Command port: %d", + BaseString::snprintf(msg, 256, "Id: %d, Command port: %d", glob.localNodeId, glob.port); ndbout_c(msg); g_EventLogger.info(msg); diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index be8ba86c817..be0445bceb3 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -330,7 +330,7 @@ Ndb::startTransaction(Uint32 aPriority, const char * keyData, Uint32 keyLen) { NdbConnection *trans= startTransactionLocal(aPriority, nodeId); DBUG_PRINT("exit",("start trans: 0x%x transid: 0x%llx", - trans, trans->getTransactionId())); + trans, trans ? trans->getTransactionId() : 0)); DBUG_RETURN(trans); } } else { @@ -371,6 +371,7 @@ Ndb::hupp(NdbConnection* pBuddyTrans) // We could not get a connection to the desired node // release the connection and return NULL closeTransaction(pCon); + theError.code = 4006; DBUG_RETURN(NULL); } pCon->setTransactionId(pBuddyTrans->getTransactionId()); @@ -1157,10 +1158,10 @@ const char * Ndb::getCatalogName() const void Ndb::setCatalogName(const char * a_catalog_name) { if (a_catalog_name) { - snprintf(theDataBase, sizeof(theDataBase), "%s", + BaseString::snprintf(theDataBase, sizeof(theDataBase), "%s", a_catalog_name ? a_catalog_name : ""); - int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + int len = BaseString::snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", theDataBase, table_name_separator, theDataBaseSchema, table_name_separator); prefixEnd = prefixName + (len < (int) sizeof(prefixName) ? len : @@ -1176,10 +1177,10 @@ const char * Ndb::getSchemaName() const void Ndb::setSchemaName(const char * a_schema_name) { if (a_schema_name) { - snprintf(theDataBaseSchema, sizeof(theDataBase), "%s", + BaseString::snprintf(theDataBaseSchema, sizeof(theDataBase), "%s", a_schema_name ? a_schema_name : ""); - int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + int len = BaseString::snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", theDataBase, table_name_separator, theDataBaseSchema, table_name_separator); prefixEnd = prefixName + (len < (int) sizeof(prefixName) ? len : diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp index d7b2b74b2bf..a1d34896968 100644 --- a/ndb/src/ndbapi/NdbApiSignal.cpp +++ b/ndb/src/ndbapi/NdbApiSignal.cpp @@ -168,7 +168,7 @@ NdbApiSignal::setSignal(int aNdbSignalType) theTrace = TestOrd::TraceAPI; theReceiversBlockNumber = DBTC; theVerId_signalNumber = GSN_TC_COMMITREQ; - theLength = 5; + theLength = 3; } break; diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index 7939f54d846..feab95d8ca5 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -867,7 +867,7 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); if (tOp == NULL || - tOp->readTuple() == -1 || + tOp->committedRead() == -1 || setPartKeyValue(tOp, part + n) == -1 || tOp->getValue((Uint32)3, buf) == NULL) { setErrorCode(tOp); @@ -1440,11 +1440,11 @@ NdbOut& operator<<(NdbOut& out, const NdbBlob& blob) { ndbout << dec << "o=" << blob.getOperationType(); - ndbout << dec << " s=" << blob.theState; + ndbout << dec << " s=" << (Uint32) blob.theState; ndbout << dec << " n=" << blob.theNullFlag;; ndbout << dec << " l=" << blob.theLength; ndbout << dec << " p=" << blob.thePos; - ndbout << dec << " u=" << blob.theHeadInlineUpdateFlag; + ndbout << dec << " u=" << (Uint32) blob.theHeadInlineUpdateFlag; return out; } #endif diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index 8ab0d13c67f..1457792cf28 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -83,6 +83,11 @@ NdbConnection::NdbConnection( Ndb* aNdb ) : theListState = NotInList; theError.code = 0; theId = theNdb->theNdbObjectIdMap->map(this); + +#define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz) + + CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size); + CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size); }//NdbConnection::NdbConnection() /***************************************************************************** @@ -308,8 +313,8 @@ NdbConnection::execute(ExecType aTypeOfExec, tPrepOp = tPrepOp->next(); } // save rest of prepared ops if batch - NdbOperation* tRestOp; - NdbOperation* tLastOp; + NdbOperation* tRestOp= 0; + NdbOperation* tLastOp= 0; if (tPrepOp != NULL) { tRestOp = tPrepOp->next(); tPrepOp->next(NULL); @@ -490,11 +495,6 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theListState = InPreparedList; tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1; - if(tCommitStatus == Committed){ - tCommitStatus = Started; - tTransactionIsStarted = false; - } - if ((tCommitStatus != Started) || (aTypeOfExec == Rollback)) { /***************************************************************************** @@ -503,7 +503,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, * same action. ****************************************************************************/ if (aTypeOfExec == Rollback) { - if (theTransactionIsStarted == false) { + if (theTransactionIsStarted == false || theSimpleState) { theCommitStatus = Aborted; theSendStatus = sendCompleted; } else { @@ -528,7 +528,7 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, tLastOp->theCommitIndicator = 1; }//if } else { - if (aTypeOfExec == Commit) { + if (aTypeOfExec == Commit && !theSimpleState) { /********************************************************************** * A Transaction have been started and no more operations exist. * We will use the commit method. @@ -610,6 +610,8 @@ NdbConnection::executeAsynchPrepare( ExecType aTypeOfExec, theNoOfOpSent = 0; theNoOfOpCompleted = 0; theSendStatus = sendOperations; + NdbNodeBitmask::clear(m_db_nodes); + NdbNodeBitmask::clear(m_failed_db_nodes); DBUG_VOID_RETURN; }//NdbConnection::executeAsynchPrepare() @@ -728,7 +730,8 @@ NdbConnection::doSend() theNdb->insert_completed_list(this); DBUG_RETURN(0); default: - ndbout << "Inconsistent theSendStatus = " << theSendStatus << endl; + ndbout << "Inconsistent theSendStatus = " + << (Uint32) theSendStatus << endl; abort(); break; }//switch @@ -1115,15 +1118,8 @@ NdbConnection::getNdbScanOperation(const NdbTableImpl * tab) if (tOp == NULL) goto getNdbOp_error1; - // Link scan operation into list of cursor operations - if (m_theLastScanOperation == NULL) - m_theFirstScanOperation = m_theLastScanOperation = tOp; - else { - m_theLastScanOperation->next(tOp); - m_theLastScanOperation = tOp; - } - tOp->next(NULL); if (tOp->init(tab, this) != -1) { + define_scan_op(tOp); return tOp; } else { theNdb->releaseScanOperation(tOp); @@ -1135,6 +1131,31 @@ getNdbOp_error1: return NULL; }//NdbConnection::getNdbScanOperation() +void +NdbConnection::remove_list(NdbOperation*& list, NdbOperation* op){ + NdbOperation* tmp= list; + if(tmp == op) + list = op->next(); + else { + while(tmp && tmp->next() != op) tmp = tmp->next(); + if(tmp) + tmp->next(op->next()); + } + op->next(NULL); +} + +void +NdbConnection::define_scan_op(NdbIndexScanOperation * tOp){ + // Link scan operation into list of cursor operations + if (m_theLastScanOperation == NULL) + m_theFirstScanOperation = m_theLastScanOperation = tOp; + else { + m_theLastScanOperation->next(tOp); + m_theLastScanOperation = tOp; + } + tOp->next(NULL); +} + NdbScanOperation* NdbConnection::getNdbScanOperation(const NdbDictionary::Table * table) { @@ -1517,12 +1538,21 @@ from other transactions. const Uint32* tPtr = (Uint32 *)&keyConf->operations[0]; Uint32 tNoComp = theNoOfOpCompleted; for (Uint32 i = 0; i < tNoOfOperations ; i++) { - tOp = theNdb->void2rec(theNdb->int2void(*tPtr)); - tPtr++; - const Uint32 tAttrInfoLen = *tPtr; - tPtr++; + tOp = theNdb->void2rec(theNdb->int2void(*tPtr++)); + const Uint32 tAttrInfoLen = *tPtr++; if (tOp && tOp->checkMagicNumber()) { - tNoComp += tOp->execTCOPCONF(tAttrInfoLen); + Uint32 done = tOp->execTCOPCONF(tAttrInfoLen); + if(tAttrInfoLen > TcKeyConf::SimpleReadBit){ + Uint32 node = tAttrInfoLen & (~TcKeyConf::SimpleReadBit); + NdbNodeBitmask::set(m_db_nodes, node); + if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done) + { + done = 1; + tOp->setErrorCode(4119); + theCompletionStatus = CompletedFailure; + } + } + tNoComp += done; } else { return -1; }//if @@ -1614,6 +1644,10 @@ NdbConnection::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf) setOperationErrorCodeAbort(4115); tOp = NULL; break; + case NdbOperation::NotDefined: + case NdbOperation::NotDefined2: + assert(false); + break; }//if }//while theReleaseOnClose = true; @@ -1772,7 +1806,7 @@ Parameters: aErrorCode: The error code. Remark: An operation was completed with failure. *******************************************************************************/ int -NdbConnection::OpCompleteFailure() +NdbConnection::OpCompleteFailure(Uint8 abortOption) { Uint32 tNoComp = theNoOfOpCompleted; Uint32 tNoSent = theNoOfOpSent; @@ -1786,10 +1820,7 @@ NdbConnection::OpCompleteFailure() //decide the success of the whole transaction since a simple //operation is not really part of that transaction. //------------------------------------------------------------------------ - if (theSimpleState == 1) { - theCommitStatus = NdbConnection::Aborted; - }//if - if (m_abortOption == IgnoreError){ + if (abortOption == IgnoreError){ /** * There's always a TCKEYCONF when using IgnoreError */ @@ -1824,9 +1855,6 @@ NdbConnection::OpCompleteSuccess() tNoComp++; theNoOfOpCompleted = tNoComp; if (tNoComp == tNoSent) { // Last operation completed - if (theSimpleState == 1) { - theCommitStatus = NdbConnection::Committed; - }//if return 0; } else if (tNoComp < tNoSent) { return -1; // Continue waiting for more signals @@ -1901,14 +1929,14 @@ NdbConnection::printState() CASE(Connected); CASE(DisConnecting); CASE(ConnectFailure); - default: ndbout << theStatus; + default: ndbout << (Uint32) theStatus; } switch (theListState) { CASE(NotInList); CASE(InPreparedList); CASE(InSendList); CASE(InCompletedList); - default: ndbout << theListState; + default: ndbout << (Uint32) theListState; } switch (theSendStatus) { CASE(NotInit); @@ -1921,7 +1949,7 @@ NdbConnection::printState() CASE(sendTC_ROLLBACK); CASE(sendTC_COMMIT); CASE(sendTC_OP); - default: ndbout << theSendStatus; + default: ndbout << (Uint32) theSendStatus; } switch (theCommitStatus) { CASE(NotStarted); @@ -1929,16 +1957,56 @@ NdbConnection::printState() CASE(Committed); CASE(Aborted); CASE(NeedAbort); - default: ndbout << theCommitStatus; + default: ndbout << (Uint32) theCommitStatus; } switch (theCompletionStatus) { CASE(NotCompleted); CASE(CompletedSuccess); CASE(CompletedFailure); CASE(DefinitionFailure); - default: ndbout << theCompletionStatus; + default: ndbout << (Uint32) theCompletionStatus; } ndbout << endl; } #undef CASE #endif + +int +NdbConnection::report_node_failure(Uint32 id){ + NdbNodeBitmask::set(m_failed_db_nodes, id); + if(!NdbNodeBitmask::get(m_db_nodes, id)) + { + return 0; + } + + /** + * Arrived + * TCKEYCONF TRANSIDAI + * 1) - - + * 2) - X + * 3) X - + * 4) X X + */ + NdbOperation* tmp = theFirstExecOpInList; + const Uint32 len = TcKeyConf::SimpleReadBit | id; + Uint32 tNoComp = theNoOfOpCompleted; + Uint32 tNoSent = theNoOfOpSent; + while(tmp != 0) + { + if(tmp->theReceiver.m_expected_result_length == len && + tmp->theReceiver.m_received_result_length == 0) + { + tNoComp++; + tmp->theError.code = 4119; + } + tmp = tmp->next(); + } + theNoOfOpCompleted = tNoComp; + if(tNoComp == tNoSent) + { + theError.code = 4119; + theCompletionStatus = NdbConnection::CompletedFailure; + return 1; + } + return 0; +} diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 5e640cdebd5..cf51a30fe0b 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -148,6 +148,9 @@ NdbColumnImpl::init(Type t) m_length = 4; m_cs = default_cs; break; + case Undefined: + assert(false); + break; } m_pk = false; m_nullable = false; @@ -1466,7 +1469,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, impl.m_internalName.assign(internalName); UtilBufferWriter w(m_buffer); DictTabInfo::Table tmpTab; tmpTab.init(); - snprintf(tmpTab.TableName, + BaseString::snprintf(tmpTab.TableName, sizeof(tmpTab.TableName), internalName); @@ -1522,7 +1525,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, continue; DictTabInfo::Attribute tmpAttr; tmpAttr.init(); - snprintf(tmpAttr.AttributeName, sizeof(tmpAttr.AttributeName), + BaseString::snprintf(tmpAttr.AttributeName, sizeof(tmpAttr.AttributeName), col->m_name.c_str()); tmpAttr.AttributeId = i; tmpAttr.AttributeKeyFlag = col->m_pk || col->m_tupleKey; @@ -1557,7 +1560,7 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, (void)tmpAttr.translateExtType(); tmpAttr.AttributeAutoIncrement = col->m_autoIncrement; - snprintf(tmpAttr.AttributeDefaultValue, + BaseString::snprintf(tmpAttr.AttributeDefaultValue, sizeof(tmpAttr.AttributeDefaultValue), col->m_defaultValue.c_str()); s = SimpleProperties::pack(w, diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp index c62f6962e25..83de6d9ef87 100644 --- a/ndb/src/ndbapi/NdbIndexOperation.cpp +++ b/ndb/src/ndbapi/NdbIndexOperation.cpp @@ -87,7 +87,19 @@ NdbIndexOperation::indxInit(const NdbIndexImpl * anIndex, int NdbIndexOperation::readTuple(NdbOperation::LockMode lm) { - return NdbOperation::readTuple(lm); + switch(lm) { + case LM_Read: + return readTuple(); + break; + case LM_Exclusive: + return readTupleExclusive(); + break; + case LM_CommittedRead: + return readTuple(); + break; + default: + return -1; + }; } int NdbIndexOperation::readTuple() @@ -108,21 +120,21 @@ int NdbIndexOperation::simpleRead() { // First check that index is unique - return NdbOperation::simpleRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::dirtyRead() { // First check that index is unique - return NdbOperation::dirtyRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::committedRead() { // First check that index is unique - return NdbOperation::committedRead(); + return NdbOperation::readTuple(); } int NdbIndexOperation::updateTuple() @@ -536,7 +548,7 @@ NdbIndexOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransactionId) //------------------------------------------------------------- Uint8 tReadInd = (theOperationType == ReadRequest); Uint8 tSimpleState = tReadInd & tSimpleAlt; - theNdbCon->theSimpleState = tSimpleState; + //theNdbCon->theSimpleState = tSimpleState; tcIndxReq->transId1 = tTransId1; tcIndxReq->transId2 = tTransId2; @@ -723,23 +735,10 @@ NdbIndexOperation::receiveTCINDXREF( NdbApiSignal* aSignal) theStatus = Finished; theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; - //--------------------------------------------------------------------------// - // If the transaction this operation belongs to consists only of simple reads - // we set the error code on the transaction object. - // If the transaction consists of other types of operations we set - // the error code only on the operation since the simple read is not really - // part of this transaction and we can not decide the status of the whole - // transaction based on this operation. - //--------------------------------------------------------------------------// Uint32 errorCode = tcIndxRef->errorCode; - if (theNdbCon->theSimpleState == 0) { - theError.code = errorCode; - theNdbCon->setOperationErrorCodeAbort(errorCode); - return theNdbCon->OpCompleteFailure(); - } else { - theError.code = errorCode; - return theNdbCon->OpCompleteSuccess(); - } + theError.code = errorCode; + theNdbCon->setOperationErrorCodeAbort(errorCode); + return theNdbCon->OpCompleteFailure(theNdbCon->m_abortOption); }//NdbIndexOperation::receiveTCINDXREF() diff --git a/ndb/src/ndbapi/NdbOperation.cpp b/ndb/src/ndbapi/NdbOperation.cpp index 53a94d98a5a..b0b95d0ff43 100644 --- a/ndb/src/ndbapi/NdbOperation.cpp +++ b/ndb/src/ndbapi/NdbOperation.cpp @@ -78,7 +78,6 @@ NdbOperation::NdbOperation(Ndb* aNdb) : m_tcReqGSN(GSN_TCKEYREQ), m_keyInfoGSN(GSN_KEYINFO), m_attrInfoGSN(GSN_ATTRINFO), - theBoundATTRINFO(NULL), theBlobList(NULL) { theReceiver.init(NdbReceiver::NDB_OPERATION, this); @@ -167,7 +166,6 @@ NdbOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection){ theScanInfo = 0; theTotalNrOfKeyWordInSignal = 8; theMagicNumber = 0xABCDEF01; - theBoundATTRINFO = NULL; theBlobList = NULL; tSignal = theNdb->getSignal(); @@ -263,14 +261,6 @@ NdbOperation::release() tSubroutine = tSubroutine->theNext; theNdb->releaseNdbSubroutine(tSaveSubroutine); } - tSignal = theBoundATTRINFO; - while (tSignal != NULL) - { - tSaveSignal = tSignal; - tSignal = tSignal->next(); - theNdb->releaseSignal(tSaveSignal); - } - theBoundATTRINFO = NULL; } tBlob = theBlobList; while (tBlob != NULL) diff --git a/ndb/src/ndbapi/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp index 1cbfedd21b1..35abb15b00d 100644 --- a/ndb/src/ndbapi/NdbOperationDefine.cpp +++ b/ndb/src/ndbapi/NdbOperationDefine.cpp @@ -55,6 +55,7 @@ NdbOperation::insertTuple() theOperationType = InsertRequest; tNdbCon->theSimpleState = 0; theErrorLine = tErrorLine++; + theLockMode = LM_Exclusive; return 0; } else { setErrorCode(4200); @@ -74,6 +75,7 @@ NdbOperation::updateTuple() tNdbCon->theSimpleState = 0; theOperationType = UpdateRequest; theErrorLine = tErrorLine++; + theLockMode = LM_Exclusive; return 0; } else { setErrorCode(4200); @@ -93,6 +95,7 @@ NdbOperation::writeTuple() tNdbCon->theSimpleState = 0; theOperationType = WriteRequest; theErrorLine = tErrorLine++; + theLockMode = LM_Exclusive; return 0; } else { setErrorCode(4200); @@ -113,8 +116,10 @@ NdbOperation::readTuple(NdbOperation::LockMode lm) return readTupleExclusive(); break; case LM_CommittedRead: - return readTuple(); + return committedRead(); break; + default: + return -1; }; } /****************************************************************************** @@ -130,6 +135,7 @@ NdbOperation::readTuple() tNdbCon->theSimpleState = 0; theOperationType = ReadRequest; theErrorLine = tErrorLine++; + theLockMode = LM_Read; return 0; } else { setErrorCode(4200); @@ -150,6 +156,7 @@ NdbOperation::deleteTuple() tNdbCon->theSimpleState = 0; theOperationType = DeleteRequest; theErrorLine = tErrorLine++; + theLockMode = LM_Exclusive; return 0; } else { setErrorCode(4200); @@ -170,6 +177,7 @@ NdbOperation::readTupleExclusive() tNdbCon->theSimpleState = 0; theOperationType = ReadExclusive; theErrorLine = tErrorLine++; + theLockMode = LM_Exclusive; return 0; } else { setErrorCode(4200); @@ -183,17 +191,24 @@ NdbOperation::readTupleExclusive() int NdbOperation::simpleRead() { + /** + * Currently/still disabled + */ + return readTuple(); +#if 0 int tErrorLine = theErrorLine; if (theStatus == Init) { theStatus = OperationDefined; theOperationType = ReadRequest; theSimpleIndicator = 1; theErrorLine = tErrorLine++; + theLockMode = LM_Read; return 0; } else { setErrorCode(4200); return -1; }//if +#endif }//NdbOperation::simpleRead() /***************************************************************************** @@ -218,6 +233,7 @@ NdbOperation::committedRead() theSimpleIndicator = 1; theDirtyIndicator = 1; theErrorLine = tErrorLine++; + theLockMode = LM_CommittedRead; return 0; } else { setErrorCode(4200); @@ -240,6 +256,7 @@ NdbOperation::dirtyUpdate() theSimpleIndicator = 1; theDirtyIndicator = 1; theErrorLine = tErrorLine++; + theLockMode = LM_CommittedRead; return 0; } else { setErrorCode(4200); @@ -262,6 +279,7 @@ NdbOperation::dirtyWrite() theSimpleIndicator = 1; theDirtyIndicator = 1; theErrorLine = tErrorLine++; + theLockMode = LM_CommittedRead; return 0; } else { setErrorCode(4200); @@ -282,7 +300,7 @@ NdbOperation::interpretedUpdateTuple() tNdbCon->theSimpleState = 0; theOperationType = UpdateRequest; theAI_LenInCurrAI = 25; - + theLockMode = LM_Exclusive; theErrorLine = tErrorLine++; initInterpreter(); return 0; @@ -307,7 +325,7 @@ NdbOperation::interpretedDeleteTuple() theErrorLine = tErrorLine++; theAI_LenInCurrAI = 25; - + theLockMode = LM_Exclusive; initInterpreter(); return 0; } else { @@ -334,10 +352,6 @@ NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue) if ((tAttrInfo != NULL) && (!tAttrInfo->m_indexOnly) && (theStatus != Init)){ - if (theStatus == SetBound) { - ((NdbIndexScanOperation*)this)->saveBoundATTRINFO(); - theStatus = GetValue; - } if (theStatus != GetValue) { if (theInterpretIndicator == 1) { if (theStatus == FinalGetValue) { diff --git a/ndb/src/ndbapi/NdbOperationExec.cpp b/ndb/src/ndbapi/NdbOperationExec.cpp index cd89f953213..f1338ae01e4 100644 --- a/ndb/src/ndbapi/NdbOperationExec.cpp +++ b/ndb/src/ndbapi/NdbOperationExec.cpp @@ -161,28 +161,17 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tTransId1 = (Uint32) aTransId; tTransId2 = (Uint32) (aTransId >> 32); -//------------------------------------------------------------- -// Simple is simple if simple or both start and commit is set. -//------------------------------------------------------------- -// Temporarily disable simple stuff - Uint8 tSimpleIndicator = 0; -// Uint8 tSimpleIndicator = theSimpleIndicator; + Uint8 tSimpleIndicator = theSimpleIndicator; Uint8 tCommitIndicator = theCommitIndicator; Uint8 tStartIndicator = theStartIndicator; -// if ((theNdbCon->theLastOpInList == this) && (theCommitIndicator == 0)) -// abort(); -// Temporarily disable simple stuff - Uint8 tSimpleAlt = 0; -// Uint8 tSimpleAlt = tStartIndicator & tCommitIndicator; - tSimpleIndicator = tSimpleIndicator | tSimpleAlt; + Uint8 tInterpretIndicator = theInterpretIndicator; //------------------------------------------------------------- // Simple state is set if start and commit is set and it is // a read request. Otherwise it is set to zero. //------------------------------------------------------------- Uint8 tReadInd = (theOperationType == ReadRequest); - Uint8 tSimpleState = tReadInd & tSimpleAlt; - theNdbCon->theSimpleState = tSimpleState; + Uint8 tSimpleState = tReadInd & tSimpleIndicator; tcKeyReq->transId1 = tTransId1; tcKeyReq->transId2 = tTransId2; @@ -197,7 +186,6 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tcKeyReq->setSimpleFlag(tReqInfo, tSimpleIndicator); tcKeyReq->setCommitFlag(tReqInfo, tCommitIndicator); tcKeyReq->setStartFlag(tReqInfo, tStartIndicator); - const Uint8 tInterpretIndicator = theInterpretIndicator; tcKeyReq->setInterpretedFlag(tReqInfo, tInterpretIndicator); Uint8 tDirtyIndicator = theDirtyIndicator; @@ -208,6 +196,9 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint64 aTransId) tcKeyReq->setDirtyFlag(tReqInfo, tDirtyIndicator); tcKeyReq->setOperationType(tReqInfo, tOperationType); tcKeyReq->setKeyLength(tReqInfo, tTupKeyLen); + + // A simple read is always ignore error + abortOption = tSimpleIndicator ? IgnoreError : abortOption; tcKeyReq->setAbortOption(tReqInfo, abortOption); Uint8 tDistrKeyIndicator = theDistrKeyIndicator; @@ -550,27 +541,29 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal) return -1; }//if + AbortOption ao = (AbortOption)theNdbCon->m_abortOption; + theReceiver.m_received_result_length = ~0; + theStatus = Finished; - theNdbCon->theReturnStatus = NdbConnection::ReturnFailure; - //-------------------------------------------------------------------------// - // If the transaction this operation belongs to consists only of simple reads - // we set the error code on the transaction object. - // If the transaction consists of other types of operations we set - // the error code only on the operation since the simple read is not really - // part of this transaction and we can not decide the status of the whole - // transaction based on this operation. - //-------------------------------------------------------------------------// - if (theNdbCon->theSimpleState == 0) { - theError.code = aSignal->readData(4); - theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4)); - return theNdbCon->OpCompleteFailure(); - } else { - theError.code = aSignal->readData(4); - return theNdbCon->OpCompleteSuccess(); + + theError.code = aSignal->readData(4); + theNdbCon->setOperationErrorCodeAbort(aSignal->readData(4)); + + if(theOperationType != ReadRequest || !theSimpleIndicator) // not simple read + return theNdbCon->OpCompleteFailure(ao); + + /** + * If TCKEYCONF has arrived + * op has completed (maybe trans has completed) + */ + if(theReceiver.m_expected_result_length) + { + return theNdbCon->OpCompleteFailure(AbortOnError); } -}//NdbOperation::receiveTCKEYREF() + return -1; +} void diff --git a/ndb/src/ndbapi/NdbOperationInt.cpp b/ndb/src/ndbapi/NdbOperationInt.cpp index f5d334fd79a..ee7b8132cd1 100644 --- a/ndb/src/ndbapi/NdbOperationInt.cpp +++ b/ndb/src/ndbapi/NdbOperationInt.cpp @@ -216,10 +216,6 @@ int NdbOperation::initial_interpreterCheck() { if ((theInterpretIndicator == 1)) { - if (theStatus == SetBound) { - ((NdbIndexScanOperation*)this)->saveBoundATTRINFO(); - theStatus = GetValue; - } if (theStatus == ExecInterpretedValue) { return 0; // Simply continue with interpretation } else if (theStatus == GetValue) { diff --git a/ndb/src/ndbapi/NdbOperationSearch.cpp b/ndb/src/ndbapi/NdbOperationSearch.cpp index e5166fc4a82..0d3130fffd0 100644 --- a/ndb/src/ndbapi/NdbOperationSearch.cpp +++ b/ndb/src/ndbapi/NdbOperationSearch.cpp @@ -543,7 +543,8 @@ NdbOperation::getKeyFromTCREQ(Uint32* data, unsigned size) assert(m_accessTable->m_sizeOfKeysInWords == size); unsigned pos = 0; while (pos < 8 && pos < size) { - data[pos++] = theKEYINFOptr[pos]; + data[pos] = theKEYINFOptr[pos]; + pos++; } NdbApiSignal* tSignal = theFirstKEYINFO; unsigned n = 0; diff --git a/ndb/src/ndbapi/NdbReceiver.cpp b/ndb/src/ndbapi/NdbReceiver.cpp index caeeac80093..14f8d4b8440 100644 --- a/ndb/src/ndbapi/NdbReceiver.cpp +++ b/ndb/src/ndbapi/NdbReceiver.cpp @@ -22,6 +22,7 @@ #include <AttributeHeader.hpp> #include <NdbConnection.hpp> #include <TransporterFacade.hpp> +#include <signaldata/TcKeyConf.hpp> NdbReceiver::NdbReceiver(Ndb *aNdb) : theMagicNumber(0), @@ -91,7 +92,7 @@ NdbReceiver::getValue(const NdbColumnImpl* tAttrInfo, char * user_dst_ptr){ return 0; } -#define KEY_ATTR_ID (~0) +#define KEY_ATTR_ID (~(Uint32)0) void NdbReceiver::calculate_batch_size(Uint32 key_size, @@ -249,10 +250,11 @@ NdbReceiver::execTRANSID_AI(const Uint32* aDataPtr, Uint32 aLength) /** * Update m_received_result_length */ + Uint32 exp = m_expected_result_length; Uint32 tmp = m_received_result_length + aLength; m_received_result_length = tmp; - return (tmp == m_expected_result_length ? 1 : 0); + return (tmp == exp || (exp > TcKeyConf::SimpleReadBit) ? 1 : 0); } int @@ -272,3 +274,11 @@ NdbReceiver::execKEYINFO20(Uint32 info, const Uint32* aDataPtr, Uint32 aLength) return (tmp == m_expected_result_length ? 1 : 0); } + +void +NdbReceiver::setErrorCode(int code) +{ + theMagicNumber = 0; + NdbOperation* op = (NdbOperation*)getOwner(); + op->setErrorCode(code); +} diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 3ff2a32d418..fd63ce96f25 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -32,6 +32,7 @@ #include <signaldata/ScanTab.hpp> #include <signaldata/KeyInfo.hpp> +#include <signaldata/AttrInfo.hpp> #include <signaldata/TcKeyReq.hpp> NdbScanOperation::NdbScanOperation(Ndb* aNdb) : @@ -116,10 +117,8 @@ NdbScanOperation::init(const NdbTableImpl* tab, NdbConnection* myConnection) theStatus = GetValue; theOperationType = OpenScanRequest; - - theTotalBoundAI_Len = 0; - theBoundATTRINFO = NULL; - + theNdbCon->theMagicNumber = 0xFE11DF; + return 0; } @@ -145,6 +144,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, } theNdbCon->theScanningOp = this; + theLockMode = lm; bool lockExcl, lockHoldMode, readCommitted; switch(lm){ @@ -168,7 +168,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, return 0; } - m_keyInfo = lockExcl; + m_keyInfo = lockExcl ? 1 : 0; bool range = false; if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex || @@ -181,7 +181,7 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, } assert (m_currentTable != m_accessTable); // Modify operation state - theStatus = SetBound; + theStatus = GetValue; theOperationType = OpenRangeScanRequest; range = true; } @@ -219,8 +219,17 @@ NdbResultSet* NdbScanOperation::readTuples(NdbScanOperation::LockMode lm, req->transId1 = (Uint32) transId; req->transId2 = (Uint32) (transId >> 32); - getFirstATTRINFOScan(); + NdbApiSignal* tSignal = + theFirstKEYINFO; + theFirstKEYINFO = (tSignal ? tSignal : tSignal = theNdb->getSignal()); + theLastKEYINFO = tSignal; + + tSignal->setSignal(GSN_KEYINFO); + theKEYINFOptr = ((KeyInfo*)tSignal->getDataPtrSend())->keyData; + theTotalNrOfKeyWordInSignal= 0; + + getFirstATTRINFOScan(); return getResultSet(); } @@ -256,18 +265,7 @@ NdbScanOperation::fix_receivers(Uint32 parallel){ m_allocated_receivers = parallel; } - for(Uint32 i = 0; i<parallel; i++){ - m_receivers[i]->m_list_index = i; - m_prepared_receivers[i] = m_receivers[i]->getId(); - m_sent_receivers[i] = m_receivers[i]; - m_conf_receivers[i] = 0; - m_api_receivers[i] = 0; - } - - m_api_receivers_count = 0; - m_current_api_receiver = 0; - m_sent_receivers_count = parallel; - m_conf_receivers_count = 0; + reset_receivers(parallel, 0); return 0; } @@ -355,6 +353,7 @@ NdbScanOperation::getFirstATTRINFOScan() * After setBound() are done, move the accumulated ATTRINFO signals to * a separate list. Then continue with normal scan. */ +#if 0 int NdbIndexScanOperation::saveBoundATTRINFO() { @@ -401,6 +400,7 @@ NdbIndexScanOperation::saveBoundATTRINFO() } return res; } +#endif #define WAITFOR_SCAN_TIMEOUT 120000 @@ -409,14 +409,22 @@ NdbScanOperation::executeCursor(int nodeId){ NdbConnection * tCon = theNdbCon; TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); + + Uint32 magic = tCon->theMagicNumber; Uint32 seq = tCon->theNodeSequence; + if (tp->get_node_alive(nodeId) && (tp->getNodeSequence(nodeId) == seq)) { - - if(prepareSendScan(tCon->theTCConPtr, tCon->theTransactionId) == -1) - return -1; + /** + * Only call prepareSendScan first time (incase of restarts) + * - check with theMagicNumber + */ tCon->theMagicNumber = 0x37412619; + if(magic != 0x37412619 && + prepareSendScan(tCon->theTCConPtr, tCon->theTransactionId) == -1) + return -1; + if (doSendScan(nodeId) == -1) return -1; @@ -428,7 +436,6 @@ NdbScanOperation::executeCursor(int nodeId){ TRACE_DEBUG("The node is hard dead when attempting to start a scan"); setErrorCode(4029); tCon->theReleaseOnClose = true; - abort(); } else { TRACE_DEBUG("The node is stopping when attempting to start a scan"); setErrorCode(4030); @@ -559,6 +566,8 @@ int NdbScanOperation::nextResult(bool fetchAllowed) setErrorCode(4028); // Node fail break; case -3: // send_next_scan -> return fail (set error-code self) + if(theError.code == 0) + setErrorCode(4028); // seq changed = Node fail break; } @@ -635,7 +644,7 @@ NdbScanOperation::doSend(int ProcessorId) void NdbScanOperation::closeScan() { - if(m_transConnection) do { + if(m_transConnection){ if(DEBUG_NEXT_RESULT) ndbout_c("closeScan() theError.code = %d " "m_api_receivers_count = %d " @@ -648,55 +657,8 @@ void NdbScanOperation::closeScan() TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); - - Uint32 seq = theNdbCon->theNodeSequence; - Uint32 nodeId = theNdbCon->theDBnode; - - if(seq != tp->getNodeSequence(nodeId)){ - theNdbCon->theReleaseOnClose = true; - break; - } - - while(theError.code == 0 && m_sent_receivers_count){ - theNdb->theWaiter.m_node = nodeId; - theNdb->theWaiter.m_state = WAIT_SCAN; - int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); - switch(return_code){ - case 0: - break; - case -1: - setErrorCode(4008); - case -2: - m_api_receivers_count = 0; - m_conf_receivers_count = 0; - m_sent_receivers_count = 0; - theNdbCon->theReleaseOnClose = true; - } - } - - if(m_api_receivers_count+m_conf_receivers_count){ - // Send close scan - send_next_scan(0, true); // Close scan - } + close_impl(tp); - /** - * wait for close scan conf - */ - while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count){ - theNdb->theWaiter.m_node = nodeId; - theNdb->theWaiter.m_state = WAIT_SCAN; - int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); - switch(return_code){ - case 0: - break; - case -1: - setErrorCode(4008); - case -2: - m_api_receivers_count = 0; - m_conf_receivers_count = 0; - m_sent_receivers_count = 0; - } - } } while(0); theNdbCon->theScanningOp = 0; @@ -750,11 +712,6 @@ int NdbScanOperation::prepareSendScan(Uint32 aTC_ConnectPtr, return -1; } - if (theStatus == SetBound) { - ((NdbIndexScanOperation*)this)->saveBoundATTRINFO(); - theStatus = GetValue; - } - theErrorLine = 0; // In preapareSendInterpreted we set the sizes (word 4-8) in the @@ -766,26 +723,7 @@ int NdbScanOperation::prepareSendScan(Uint32 aTC_ConnectPtr, ((NdbIndexScanOperation*)this)->fix_get_values(); } - const Uint32 transId1 = (Uint32) (aTransactionId & 0xFFFFFFFF); - const Uint32 transId2 = (Uint32) (aTransactionId >> 32); - - if (theOperationType == OpenRangeScanRequest) { - NdbApiSignal* tSignal = theBoundATTRINFO; - do{ - tSignal->setData(aTC_ConnectPtr, 1); - tSignal->setData(transId1, 2); - tSignal->setData(transId2, 3); - tSignal = tSignal->next(); - } while (tSignal != NULL); - } theCurrentATTRINFO->setLength(theAI_LenInCurrAI); - NdbApiSignal* tSignal = theFirstATTRINFO; - do{ - tSignal->setData(aTC_ConnectPtr, 1); - tSignal->setData(transId1, 2); - tSignal->setData(transId2, 3); - tSignal = tSignal->next(); - } while (tSignal != NULL); /** * Prepare all receivers @@ -808,20 +746,28 @@ int NdbScanOperation::prepareSendScan(Uint32 aTC_ConnectPtr, req->batch_byte_size= batch_byte_size; req->first_batch_size= first_batch_size; + /** + * Set keyinfo flag + * (Always keyinfo when using blobs) + */ + Uint32 reqInfo = req->requestInfo; + ScanTabReq::setKeyinfoFlag(reqInfo, keyInfo); + req->requestInfo = reqInfo; + for(Uint32 i = 0; i<theParallelism; i++){ m_receivers[i]->do_get_value(&theReceiver, batch_size, key_size); } return 0; } -/****************************************************************************** +/***************************************************************************** int doSend() Return Value: Return >0 : send was succesful, returns number of signals sent Return -1: In all other case. Parameters: aProcessorId: Receiving processor node Remark: Sends the ATTRINFO signal(s) -******************************************************************************/ +*****************************************************************************/ int NdbScanOperation::doSendScan(int aProcessorId) { @@ -841,13 +787,18 @@ NdbScanOperation::doSendScan(int aProcessorId) setErrorCode(4001); return -1; } + + Uint32 tupKeyLen = theTupKeyLen; + Uint32 len = theTotalNrOfKeyWordInSignal; + Uint32 aTC_ConnectPtr = theNdbCon->theTCConPtr; + Uint64 transId = theNdbCon->theTransactionId; + // Update the "attribute info length in words" in SCAN_TABREQ before // sending it. This could not be done in openScan because // we created the ATTRINFO signals after the SCAN_TABREQ signal. ScanTabReq * const req = CAST_PTR(ScanTabReq, tSignal->getDataPtrSend()); - req->attrLen = theTotalCurrAI_Len; - if (theOperationType == OpenRangeScanRequest) - req->attrLen += theTotalBoundAI_Len; + req->attrLenKeyLen = (tupKeyLen << 16) | theTotalCurrAI_Len; + TransporterFacade *tp = TransporterFacade::instance(); LinearSectionPtr ptr[3]; ptr[0].p = m_prepared_receivers; @@ -856,22 +807,41 @@ NdbScanOperation::doSendScan(int aProcessorId) setErrorCode(4002); return -1; } - if (theOperationType == OpenRangeScanRequest) { + + if (tupKeyLen > 0){ // must have at least one signal since it contains attrLen for bounds - assert(theBoundATTRINFO != NULL); - tSignal = theBoundATTRINFO; - while (tSignal != NULL) { + assert(theLastKEYINFO != NULL); + tSignal = theLastKEYINFO; + tSignal->setLength(KeyInfo::HeaderLength + theTotalNrOfKeyWordInSignal); + + assert(theFirstKEYINFO != NULL); + tSignal = theFirstKEYINFO; + + NdbApiSignal* last; + do { + KeyInfo * keyInfo = CAST_PTR(KeyInfo, tSignal->getDataPtrSend()); + keyInfo->connectPtr = aTC_ConnectPtr; + keyInfo->transId[0] = Uint32(transId); + keyInfo->transId[1] = Uint32(transId >> 32); + if (tp->sendSignal(tSignal,aProcessorId) == -1){ - setErrorCode(4002); - return -1; + setErrorCode(4002); + return -1; } + tSignalCount++; + last = tSignal; tSignal = tSignal->next(); - } + } while(last != theLastKEYINFO); } tSignal = theFirstATTRINFO; while (tSignal != NULL) { + AttrInfo * attrInfo = CAST_PTR(AttrInfo, tSignal->getDataPtrSend()); + attrInfo->connectPtr = aTC_ConnectPtr; + attrInfo->transId[0] = Uint32(transId); + attrInfo->transId[1] = Uint32(transId >> 32); + if (tp->sendSignal(tSignal,aProcessorId) == -1){ setErrorCode(4002); return -1; @@ -883,7 +853,7 @@ NdbScanOperation::doSendScan(int aProcessorId) return tSignalCount; }//NdbOperation::doSendScan() -/****************************************************************************** +/***************************************************************************** * NdbOperation* takeOverScanOp(NdbConnection* updateTrans); * * Parameters: The update transactions NdbConnection pointer. @@ -902,7 +872,7 @@ NdbScanOperation::doSendScan(int aProcessorId) * This means that the updating transactions can be placed * in separate threads and thus increasing the parallelism during * the scan process. - *****************************************************************************/ + ****************************************************************************/ int NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size) { @@ -940,6 +910,7 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){ if (newOp == NULL){ return NULL; } + pTrans->theSimpleState = 0; const Uint32 len = (tRecAttr->attrSize() * tRecAttr->arraySize() + 3)/4-1; @@ -1011,6 +982,7 @@ NdbScanOperation::takeOverScanOp(OperationType opType, NdbConnection* pTrans){ NdbBlob* NdbScanOperation::getBlobHandle(const char* anAttrName) { + m_keyInfo = 1; return NdbOperation::getBlobHandle(m_transConnection, m_currentTable->getColumn(anAttrName)); } @@ -1018,6 +990,7 @@ NdbScanOperation::getBlobHandle(const char* anAttrName) NdbBlob* NdbScanOperation::getBlobHandle(Uint32 anAttrId) { + m_keyInfo = 1; return NdbOperation::getBlobHandle(m_transConnection, m_currentTable->getColumn(anAttrId)); } @@ -1031,13 +1004,15 @@ NdbIndexScanOperation::~NdbIndexScanOperation(){ } int -NdbIndexScanOperation::setBound(const char* anAttrName, int type, const void* aValue, Uint32 len) +NdbIndexScanOperation::setBound(const char* anAttrName, int type, + const void* aValue, Uint32 len) { return setBound(m_accessTable->getColumn(anAttrName), type, aValue, len); } int -NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len) +NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, + const void* aValue, Uint32 len) { return setBound(m_accessTable->getColumn(anAttrId), type, aValue, len); } @@ -1056,11 +1031,6 @@ NdbIndexScanOperation::getValue_impl(const NdbColumnImpl* attrInfo, return NdbScanOperation::getValue_impl(attrInfo, aValue); } - if (theStatus == SetBound) { - saveBoundATTRINFO(); - theStatus = GetValue; - } - int id = attrInfo->m_attrId; // In "real" table assert(m_accessTable->m_index); int sz = (int)m_accessTable->m_index->m_key_ids.size(); @@ -1101,12 +1071,13 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo, int type, const void* aValue, Uint32 len) { if (theOperationType == OpenRangeScanRequest && - theStatus == SetBound && (0 <= type && type <= 4) && len <= 8000) { // insert bound type - insertATTRINFO(type); + Uint32 currLen = theTotalNrOfKeyWordInSignal; + Uint32 remaining = KeyInfo::DataLength - currLen; Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize; + // normalize char bound CHARSET_INFO* cs = tAttrInfo->m_cs; Uint32 xfrmData[2000]; @@ -1130,19 +1101,34 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo, Uint32 tIndexAttrId = tAttrInfo->m_attrId; Uint32 sizeInWords = (len + 3) / 4; AttributeHeader ah(tIndexAttrId, sizeInWords); - insertATTRINFO(ah.m_value); - if (len != 0) { - // insert attribute data - if ((UintPtr(aValue) & 0x3) == 0 && (len & 0x3) == 0) - insertATTRINFOloop((const Uint32*)aValue, sizeInWords); - else { - Uint32 tempData[2000]; - memcpy(tempData, aValue, len); + const Uint32 ahValue = ah.m_value; + + const bool aligned = (UintPtr(aValue) & 3) == 0; + const bool nobytes = (len & 0x3) == 0; + const Uint32 totalLen = 2 + sizeInWords; + Uint32 tupKeyLen = theTupKeyLen; + if(remaining > totalLen && aligned && nobytes){ + Uint32 * dst = theKEYINFOptr + currLen; + * dst ++ = type; + * dst ++ = ahValue; + memcpy(dst, aValue, 4 * sizeInWords); + theTotalNrOfKeyWordInSignal = currLen + totalLen; + } else { + if(!aligned || !nobytes){ + Uint32 tempData[2002]; + tempData[0] = type; + tempData[1] = ahValue; + memcpy(tempData+2, aValue, len); while ((len & 0x3) != 0) - ((char*)tempData)[len++] = 0; - insertATTRINFOloop(tempData, sizeInWords); + ((char*)&tempData[2])[len++] = 0; + insertBOUNDS(tempData, 2+sizeInWords); + } else { + Uint32 buf[2] = { type, ahValue }; + insertBOUNDS(buf, 2); + insertBOUNDS((Uint32*)aValue, sizeInWords); } } + theTupKeyLen = tupKeyLen + totalLen; /** * Do sorted stuff @@ -1165,6 +1151,46 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo, } } +int +NdbIndexScanOperation::insertBOUNDS(Uint32 * data, Uint32 sz){ + Uint32 len; + Uint32 remaining = KeyInfo::DataLength - theTotalNrOfKeyWordInSignal; + Uint32 * dst = theKEYINFOptr + theTotalNrOfKeyWordInSignal; + do { + len = (sz < remaining ? sz : remaining); + memcpy(dst, data, 4 * len); + + if(sz >= remaining){ + NdbApiSignal* tCurr = theLastKEYINFO; + tCurr->setLength(KeyInfo::MaxSignalLength); + NdbApiSignal* tSignal = tCurr->next(); + if(tSignal) + ; + else if((tSignal = theNdb->getSignal()) != 0) + { + tCurr->next(tSignal); + tSignal->setSignal(GSN_KEYINFO); + } else { + goto error; + } + theLastKEYINFO = tSignal; + theKEYINFOptr = dst = ((KeyInfo*)tSignal->getDataPtrSend())->keyData; + remaining = KeyInfo::DataLength; + sz -= len; + data += len; + } else { + len = (KeyInfo::DataLength - remaining) + len; + break; + } + } while(true); + theTotalNrOfKeyWordInSignal = len; + return 0; + +error: + setErrorCodeAbort(4228); // XXX wrong code + return -1; +} + NdbResultSet* NdbIndexScanOperation::readTuples(LockMode lm, Uint32 batch, @@ -1173,9 +1199,23 @@ NdbIndexScanOperation::readTuples(LockMode lm, NdbResultSet * rs = NdbScanOperation::readTuples(lm, batch, 0); if(rs && order_by){ m_ordered = 1; - m_sort_columns = m_accessTable->getNoOfColumns() - 1; // -1 for NDB$NODE + Uint32 cnt = m_accessTable->getNoOfColumns() - 1; + m_sort_columns = cnt; // -1 for NDB$NODE m_current_api_receiver = m_sent_receivers_count; m_api_receivers_count = m_sent_receivers_count; + + m_sort_columns = cnt; + for(Uint32 i = 0; i<cnt; i++){ + const NdbColumnImpl* key = m_accessTable->m_index->m_columns[i]; + const NdbColumnImpl* col = m_currentTable->getColumn(key->m_keyInfoPos); + NdbRecAttr* tmp = NdbScanOperation::getValue_impl(col, (char*)-1); + UintPtr newVal = UintPtr(tmp); + theTupleKeyDefined[i][0] = FAKE_PTR; + theTupleKeyDefined[i][1] = (newVal & 0xFFFFFFFF); +#if (SIZEOF_CHARP == 8) + theTupleKeyDefined[i][2] = (newVal >> 32); +#endif + } } return rs; } @@ -1396,10 +1436,7 @@ NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ } int -NdbScanOperation::restart(){ - TransporterFacade* tp = TransporterFacade::instance(); - Guard guard(tp->theMutexPtr); - +NdbScanOperation::close_impl(TransporterFacade* tp){ Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; @@ -1407,8 +1444,8 @@ NdbScanOperation::restart(){ theNdbCon->theReleaseOnClose = true; return -1; } - - while(m_sent_receivers_count){ + + while(theError.code == 0 && m_sent_receivers_count){ theNdb->theWaiter.m_node = nodeId; theNdb->theWaiter.m_state = WAIT_SCAN; int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); @@ -1421,14 +1458,17 @@ NdbScanOperation::restart(){ m_api_receivers_count = 0; m_conf_receivers_count = 0; m_sent_receivers_count = 0; + theNdbCon->theReleaseOnClose = true; return -1; } } if(m_api_receivers_count+m_conf_receivers_count){ // Send close scan - if(send_next_scan(0, true) == -1) // Close scan + if(send_next_scan(0, true) == -1){ // Close scan + theNdbCon->theReleaseOnClose = true; return -1; + } } /** @@ -1447,15 +1487,15 @@ NdbScanOperation::restart(){ m_api_receivers_count = 0; m_conf_receivers_count = 0; m_sent_receivers_count = 0; + theNdbCon->theReleaseOnClose = true; return -1; } } + return 0; +} - /** - * Reset receivers - */ - const Uint32 parallell = theParallelism; - +void +NdbScanOperation::reset_receivers(Uint32 parallell, Uint32 ordered){ for(Uint32 i = 0; i<parallell; i++){ m_receivers[i]->m_list_index = i; m_prepared_receivers[i] = m_receivers[i]->getId(); @@ -1470,13 +1510,64 @@ NdbScanOperation::restart(){ m_sent_receivers_count = parallell; m_conf_receivers_count = 0; - if(m_ordered){ + if(ordered){ m_current_api_receiver = parallell; m_api_receivers_count = parallell; } +} + +int +NdbScanOperation::restart() +{ + + TransporterFacade* tp = TransporterFacade::instance(); + Guard guard(tp->theMutexPtr); + Uint32 nodeId = theNdbCon->theDBnode; + + { + int res; + if((res= close_impl(tp))) + { + return res; + } + } + + /** + * Reset receivers + */ + reset_receivers(theParallelism, m_ordered); + theError.code = 0; if (doSendScan(nodeId) == -1) return -1; return 0; } + +int +NdbIndexScanOperation::reset_bounds(){ + int res; + + { + TransporterFacade* tp = TransporterFacade::instance(); + Guard guard(tp->theMutexPtr); + res= close_impl(tp); + } + + if(!res) + { + theError.code = 0; + reset_receivers(theParallelism, m_ordered); + + theLastKEYINFO = theFirstKEYINFO; + theKEYINFOptr = ((KeyInfo*)theFirstKEYINFO->getDataPtrSend())->keyData; + theTupKeyLen = 0; + theTotalNrOfKeyWordInSignal = 0; + m_transConnection + ->remove_list((NdbOperation*&)m_transConnection->m_firstExecutedScanOp, + this); + m_transConnection->define_scan_op(this); + return 0; + } + return res; +} diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index 5c91467f2e5..c011c1a6a26 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -249,6 +249,7 @@ Ndb::report_node_failure(Uint32 node_id) */ the_release_ind[node_id] = 1; theWaiter.nodeFail(node_id); + return; }//Ndb::report_node_failure() @@ -271,9 +272,10 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) Uint32 tNoSentTransactions = theNoOfSentTransactions; for (int i = tNoSentTransactions - 1; i >= 0; i--) { NdbConnection* localCon = theSentTransactionsArray[i]; - if (localCon->getConnectedNodeId() == aNodeId ) { + if (localCon->getConnectedNodeId() == aNodeId) { const NdbConnection::SendStatusType sendStatus = localCon->theSendStatus; - if (sendStatus == NdbConnection::sendTC_OP || sendStatus == NdbConnection::sendTC_COMMIT) { + if (sendStatus == NdbConnection::sendTC_OP || + sendStatus == NdbConnection::sendTC_COMMIT) { /* A transaction was interrupted in the prepare phase by a node failure. Since the transaction was not found in the phase @@ -293,7 +295,7 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) printState("abortTransactionsAfterNodeFailure %x", this); abort(); #endif - }// + } /* All transactions arriving here have no connection to the kernel intact since the node was failing and they were aborted. Thus we @@ -302,7 +304,11 @@ Ndb::abortTransactionsAfterNodeFailure(Uint16 aNodeId) localCon->theCommitStatus = NdbConnection::Aborted; localCon->theReleaseOnClose = true; completedTransaction(localCon); - }//if + } + else if(localCon->report_node_failure(aNodeId)) + { + completedTransaction(localCon); + } }//for return; }//Ndb::abortTransactionsAfterNodeFailure() diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index 8589158ae6a..b8927f2abba 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -107,8 +107,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theOpIdleList= NULL; theScanOpIdleList= NULL; theIndexOpIdleList= NULL; -// theSchemaConIdleList= NULL; -// theSchemaConToNdbList= NULL; theTransactionList= NULL; theConnectionArray= NULL; theRecAttrIdleList= NULL; @@ -134,10 +132,13 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, fullyQualifiedNames = true; +#ifdef POORMANSPURIFY cgetSignals =0; cfreeSignals = 0; cnewSignals = 0; creleaseSignals = 0; +#endif + theError.code = 0; theNdbObjectIdMap = new NdbObjectIdMap(1024,1024); @@ -159,12 +160,12 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theLastTupleId[i] = 0; }//for - snprintf(theDataBase, sizeof(theDataBase), "%s", + BaseString::snprintf(theDataBase, sizeof(theDataBase), "%s", aDataBase ? aDataBase : ""); - snprintf(theDataBaseSchema, sizeof(theDataBaseSchema), "%s", + BaseString::snprintf(theDataBaseSchema, sizeof(theDataBaseSchema), "%s", aSchema ? aSchema : ""); - int len = snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", + int len = BaseString::snprintf(prefixName, sizeof(prefixName), "%s%c%s%c", theDataBase, table_name_separator, theDataBaseSchema, table_name_separator); prefixEnd = prefixName + (len < (int) sizeof(prefixName) ? len : diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index af98aa09280..a5f2a4801d5 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -33,7 +33,7 @@ Ndb::checkFailedNode() DBUG_PRINT("enter", ("theNoOfDBnodes: %d", theNoOfDBnodes)); DBUG_ASSERT(theNoOfDBnodes < MAX_NDB_NODES); - for (int i = 0; i < theNoOfDBnodes; i++){ + for (Uint32 i = 0; i < theNoOfDBnodes; i++){ const NodeId node_id = theDBnodes[i]; DBUG_PRINT("info", ("i: %d, node_id: %d", i, node_id)); @@ -432,11 +432,15 @@ Ndb::getSignal() theSignalIdleList = tSignalNext; } else { tSignal = new NdbApiSignal(theMyRef); +#ifdef POORMANSPURIFY cnewSignals++; +#endif if (tSignal != NULL) tSignal->next(NULL); } +#ifdef POORMANSPURIFY cgetSignals++; +#endif return tSignal; } @@ -605,7 +609,9 @@ Ndb::releaseSignal(NdbApiSignal* aSignal) } #endif #endif +#ifdef POORMANSPURIFY creleaseSignals++; +#endif aSignal->next(theSignalIdleList); theSignalIdleList = aSignal; } @@ -649,8 +655,8 @@ Remark: Always release the first item in the free list void Ndb::freeScanOperation() { - NdbScanOperation* tOp = theScanOpIdleList; - theScanOpIdleList = (NdbIndexScanOperation *) theScanOpIdleList->next(); + NdbIndexScanOperation* tOp = theScanOpIdleList; + theScanOpIdleList = (NdbIndexScanOperation *)tOp->next(); delete tOp; } @@ -769,7 +775,9 @@ Ndb::freeSignal() NdbApiSignal* tSignal = theSignalIdleList; theSignalIdleList = tSignal->next(); delete tSignal; +#ifdef POORMANSPURIFY cfreeSignals++; +#endif } void diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index fdfd8a15fb0..20661b89517 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -16,7 +16,6 @@ #include <ndb_global.h> - #include <ndberror.h> typedef struct ErrorBundle { @@ -92,9 +91,10 @@ ErrorBundle ErrorCodes[] = { { 4031, NR, "Node failure caused abort of transaction" }, { 4033, NR, "Send to NDB failed" }, { 4115, NR, - "Transaction was committed but all read information was not " - "received due to node crash" }, - + "Transaction was committed but all read information was not " + "received due to node crash" }, + { 4119, NR, "Simple/dirty read failed due to node failure" }, + /** * Node shutdown */ @@ -171,7 +171,7 @@ ErrorBundle ErrorCodes[] = { { 677, OL, "Index UNDO buffers overloaded" }, { 891, OL, "Data UNDO buffers overloaded" }, { 1221, OL, "REDO log buffers overloaded" }, - { 4006, AE, "Connect failure - out of connection objects" }, + { 4006, OL, "Connect failure - out of connection objects" }, @@ -491,6 +491,7 @@ static const int NbClassification = sizeof(StatusClassificationMapping)/sizeof(ErrorStatusClassification); +#ifdef NOT_USED /** * Complete all fields of an NdbError given the error code * and details @@ -506,7 +507,7 @@ set(ndberror_struct * error, int code, const char * details, ...){ va_end(ap); } } - +#endif void ndberror_update(ndberror_struct * error){ @@ -592,8 +593,10 @@ int ndb_error_string(int err_no, char *str, unsigned int size) error.code = err_no; ndberror_update(&error); - len = snprintf(str, size-1, "%s: %s: %s", error.message, - ndberror_status_message(error.status), ndberror_classification_message(error.classification)); + len = + snprintf(str, size-1, "%s: %s: %s", error.message, + ndberror_status_message(error.status), + ndberror_classification_message(error.classification)); str[size-1]= '\0'; return len; diff --git a/ndb/test/include/HugoOperations.hpp b/ndb/test/include/HugoOperations.hpp index 6bd8f7204b2..fe22e4b5649 100644 --- a/ndb/test/include/HugoOperations.hpp +++ b/ndb/test/include/HugoOperations.hpp @@ -38,16 +38,8 @@ public: int pkReadRecord(Ndb*, int recordNo, - bool exclusive = false, - int numRecords = 1); - - int pkSimpleReadRecord(Ndb*, - int recordNo, - int numRecords = 1); - - int pkDirtyReadRecord(Ndb*, - int recordNo, - int numRecords = 1); + int numRecords = 1, + NdbOperation::LockMode lm = NdbOperation::LM_Read); int pkUpdateRecord(Ndb*, int recordNo, diff --git a/ndb/test/include/HugoTransactions.hpp b/ndb/test/include/HugoTransactions.hpp index 280d9490f15..19e4cb43336 100644 --- a/ndb/test/include/HugoTransactions.hpp +++ b/ndb/test/include/HugoTransactions.hpp @@ -48,8 +48,8 @@ public: int pkReadRecords(Ndb*, int records, int batchsize = 1, - bool dirty = false); - + NdbOperation::LockMode = NdbOperation::LM_Read); + int scanUpdateRecords(Ndb*, int records, int abort = 0, diff --git a/ndb/test/include/NDBT_ResultRow.hpp b/ndb/test/include/NDBT_ResultRow.hpp index aa54e892da3..6072d0ea510 100644 --- a/ndb/test/include/NDBT_ResultRow.hpp +++ b/ndb/test/include/NDBT_ResultRow.hpp @@ -24,8 +24,9 @@ public: NDBT_ResultRow(const NdbDictionary::Table &tab, char attrib_delimiter='\t'); ~NDBT_ResultRow(); NdbRecAttr * & attributeStore(int i); - const NdbRecAttr * attributeStore(const char* name); - + const NdbRecAttr * attributeStore(int i) const ; + const NdbRecAttr * attributeStore(const char* name) const ; + BaseString c_str(); NdbOut & header (NdbOut &) const; diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp index 6a968c491ae..b0b5fe15960 100644 --- a/ndb/test/include/NDBT_Test.hpp +++ b/ndb/test/include/NDBT_Test.hpp @@ -82,6 +82,12 @@ public: */ int getNoOfRunningSteps() const ; int getNoOfCompletedSteps() const ; + + /** + * Thread sync + */ + void sync_down(const char * key); + void sync_up_and_wait(const char * key, Uint32 count = 0); private: friend class NDBT_Step; friend class NDBT_TestSuite; @@ -245,7 +251,7 @@ public: // Convert to Uint32 in order to be able to print it to screen Uint32 lapTime = (Uint32)m_ticks; Uint32 secTime = lapTime/1000; - snprintf(buf, 255, "%d secs (%d ms)", secTime, lapTime); + BaseString::snprintf(buf, 255, "%d secs (%d ms)", secTime, lapTime); return buf; } private: diff --git a/ndb/test/include/UtilTransactions.hpp b/ndb/test/include/UtilTransactions.hpp index 1298028d591..37cd99550a5 100644 --- a/ndb/test/include/UtilTransactions.hpp +++ b/ndb/test/include/UtilTransactions.hpp @@ -87,19 +87,30 @@ private: int verifyUniqueIndex(Ndb*, - const char* indexName, + const NdbDictionary::Index *, int parallelism = 0, bool transactional = false); - + int scanAndCompareUniqueIndex(Ndb* pNdb, - const char * indexName, + const NdbDictionary::Index *, int parallelism, bool transactional); int readRowFromTableAndIndex(Ndb* pNdb, NdbConnection* pTrans, - const char * indexName, + const NdbDictionary::Index *, NDBT_ResultRow& row ); + + int verifyOrderedIndex(Ndb*, + const NdbDictionary::Index *, + int parallelism = 0, + bool transactional = false); + + + int get_values(NdbOperation* op, NDBT_ResultRow& dst); + int equal(const NdbDictionary::Table*, NdbOperation*, const NDBT_ResultRow&); + int equal(const NdbDictionary::Index*, NdbOperation*, const NDBT_ResultRow&); + protected: int m_defaultClearMethod; const NdbDictionary::Table& tab; diff --git a/ndb/test/ndbapi/asyncGenerator.cpp b/ndb/test/ndbapi/asyncGenerator.cpp index 84a93414712..d91e38dff1a 100644 --- a/ndb/test/ndbapi/asyncGenerator.cpp +++ b/ndb/test/ndbapi/asyncGenerator.cpp @@ -248,7 +248,7 @@ doTransaction_T1(Ndb * pNDB, ThreadData * td, int async) /*----------------*/ getRandomSubscriberNumber(td->transactionData.number); getRandomChangedBy(td->transactionData.changed_by); - snprintf(td->transactionData.changed_time, + BaseString::snprintf(td->transactionData.changed_time, sizeof(td->transactionData.changed_time), "%ld - %d", td->changedTime++, myRandom48(65536*1024)); //getRandomChangedTime(td->transactionData.changed_time); diff --git a/ndb/test/ndbapi/bulk_copy.cpp b/ndb/test/ndbapi/bulk_copy.cpp index 8821a92fb27..b53654ce0fb 100644 --- a/ndb/test/ndbapi/bulk_copy.cpp +++ b/ndb/test/ndbapi/bulk_copy.cpp @@ -263,7 +263,7 @@ int main(int argc, const char** argv){ } char buf[255]; - snprintf(buf, sizeof(buf), "%s.data", (const char*)_tabname); + BaseString::snprintf(buf, sizeof(buf), "%s.data", (const char*)_tabname); if (insertFile(&MyNdb, pTab, buf) != 0){ return NDBT_ProgramExit(NDBT_FAILED); } diff --git a/ndb/test/ndbapi/cdrserver.cpp b/ndb/test/ndbapi/cdrserver.cpp index 8d15061e94b..976319034bf 100644 --- a/ndb/test/ndbapi/cdrserver.cpp +++ b/ndb/test/ndbapi/cdrserver.cpp @@ -501,11 +501,11 @@ server(long int servernum) /* that this program could easily be ported to a host */ /* that does require it. */ - snprintf(msg,sizeof(msg),"Startup from %s port %u",hostname,ntohs(peeraddr_in.sin_port)); + BaseString::snprintf(msg,sizeof(msg),"Startup from %s port %u",hostname,ntohs(peeraddr_in.sin_port)); if ((checkchangelog(fi,temp))==0) c2log(fi,msg); n2log(log,msg); - snprintf(msg,sizeof(msg),"For further information, see log(%s)",lognamn); + BaseString::snprintf(msg,sizeof(msg),"For further information, see log(%s)",lognamn); if ((checkchangelog(fi,temp))==0) c2log(fi,msg); @@ -516,7 +516,7 @@ server(long int servernum) linger.l_onoff =1; linger.l_linger =0; if (setsockopt(s, SOL_SOCKET, SO_LINGER,(const char*)&linger,sizeof(linger)) == -1) { - snprintf(msg,sizeof(msg),"Setting SO_LINGER, l_onoff=%d, l_linger=%d",linger.l_onoff,linger.l_linger); + BaseString::snprintf(msg,sizeof(msg),"Setting SO_LINGER, l_onoff=%d, l_linger=%d",linger.l_onoff,linger.l_linger); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); goto errout; @@ -529,7 +529,7 @@ server(long int servernum) rcvbuf_size=64*1024; if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,(const char*) &rcvbuf_size,sizeof(rcvbuf_size)) == -1) { - snprintf(msg,sizeof(msg),"Setting SO_RCVBUF = %d",rcvbuf_size); + BaseString::snprintf(msg,sizeof(msg),"Setting SO_RCVBUF = %d",rcvbuf_size); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); goto errout; @@ -913,7 +913,7 @@ server(long int servernum) tmpcdrptr->USED_FIELDS |= B_ReroutingIndicator; break; default : - snprintf(msg,sizeof(msg),"ERROR: Redirection information has wrong length %d\n",parmlen); + BaseString::snprintf(msg,sizeof(msg),"ERROR: Redirection information has wrong length %d\n",parmlen); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); break; @@ -1060,7 +1060,7 @@ server(long int servernum) tmpcdrptr->USED_FIELDS |= B_RINParameter; break; default : - snprintf(msg,sizeof(msg),"ERROR: Rin parameter has wrong length %d\n",parmlen); + BaseString::snprintf(msg,sizeof(msg),"ERROR: Rin parameter has wrong length %d\n",parmlen); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); break; @@ -1088,7 +1088,7 @@ server(long int servernum) tmpcdrptr->USED_FIELDS |= B_OriginatingPointCode; break; default : - snprintf(msg,sizeof(msg),"ERROR: OriginatingPointCode parameter has wrong length %d\n",parmlen); + BaseString::snprintf(msg,sizeof(msg),"ERROR: OriginatingPointCode parameter has wrong length %d\n",parmlen); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); break; @@ -1119,7 +1119,7 @@ server(long int servernum) tmpcdrptr->USED_FIELDS |= B_DestinationPointCode; break; default : - snprintf(msg,sizeof(msg),"ERROR: DestinationPointCode parameter has wrong length %d\n",parmlen); + BaseString::snprintf(msg,sizeof(msg),"ERROR: DestinationPointCode parameter has wrong length %d\n",parmlen); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); break; @@ -1146,7 +1146,7 @@ server(long int servernum) break; default: printf("ERROR: Undefined parmtype %d , previous %d, length %d\n",parmtype,parmtype_prev,parmlen); - snprintf(msg,sizeof(msg),"ERROR: Undefined parmtype %d , previous %d, length %d\n",parmtype,parmtype_prev,parmlen); + BaseString::snprintf(msg,sizeof(msg),"ERROR: Undefined parmtype %d , previous %d, length %d\n",parmtype,parmtype_prev,parmlen); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); if (parmlen == 0) { @@ -1289,17 +1289,17 @@ server(long int servernum) /* that this program could easily be ported to a host */ /* that does require it. */ - snprintf(msg,sizeof(msg),"Completed %s port %u, %d requests",hostname,ntohs(peeraddr_in.sin_port), reqcnt); + BaseString::snprintf(msg,sizeof(msg),"Completed %s port %u, %d requests",hostname,ntohs(peeraddr_in.sin_port), reqcnt); if ((checkchangelog(fi,temp))==0) c2log(fi,msg); error_from_client = 1; - snprintf(msg,sizeof(msg),"Communicate with threads"); + BaseString::snprintf(msg,sizeof(msg),"Communicate with threads"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); - snprintf(msg,sizeof(msg),"Waiting for threads to return from work"); + BaseString::snprintf(msg,sizeof(msg),"Waiting for threads to return from work"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); - snprintf(msg,sizeof(msg),"Closing down"); + BaseString::snprintf(msg,sizeof(msg),"Closing down"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); close(s); @@ -1307,19 +1307,19 @@ server(long int servernum) return EXIT_SUCCESS; errout: - snprintf(msg,sizeof(msg),"Connection with %s aborted on error\n", hostname); + BaseString::snprintf(msg,sizeof(msg),"Connection with %s aborted on error\n", hostname); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); if ((checkchangelog(fi,temp))==0) c2log(fi,msg); error_from_client = 1; - snprintf(msg,sizeof(msg),"Communicate with threads"); + BaseString::snprintf(msg,sizeof(msg),"Communicate with threads"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); - snprintf(msg,sizeof(msg),"Waiting for threads to return from work"); + BaseString::snprintf(msg,sizeof(msg),"Waiting for threads to return from work"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); - snprintf(msg,sizeof(msg),"Closing down"); + BaseString::snprintf(msg,sizeof(msg),"Closing down"); if ((checkchangelog(log,lognamn))==0) n2log(log,msg); close(s); diff --git a/ndb/test/ndbapi/flexAsynch.cpp b/ndb/test/ndbapi/flexAsynch.cpp index 8c0ba46130c..1953444d640 100644 --- a/ndb/test/ndbapi/flexAsynch.cpp +++ b/ndb/test/ndbapi/flexAsynch.cpp @@ -710,7 +710,7 @@ static void setAttrNames() int i; for (i = 0; i < MAXATTR ; i++){ - snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); } } @@ -722,10 +722,10 @@ static void setTableNames() int i; for (i = 0; i < MAXTABLES ; i++){ if (theStdTableNameFlag==0){ - snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, (int)(NdbTick_CurrentMillisecond()/1000)); } else { - snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } } } diff --git a/ndb/test/ndbapi/flexBench.cpp b/ndb/test/ndbapi/flexBench.cpp index b19944498f4..2a2388109a1 100644 --- a/ndb/test/ndbapi/flexBench.cpp +++ b/ndb/test/ndbapi/flexBench.cpp @@ -1032,7 +1032,7 @@ static int readArguments(int argc, const char** argv) const char *q = strrchr(p, ':'); if (q == 0) return -1; - snprintf(statHost, sizeof(statHost), "%.*s", q-p, p); + BaseString::snprintf(statHost, sizeof(statHost), "%.*s", q-p, p); statPort = atoi(q+1); statEnable = true; argc -= 1; @@ -1068,17 +1068,17 @@ static int createTables(Ndb* pMyNdb){ int i; for (i = 0; i < tNoOfAttributes; i++){ - snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); } // Note! Uses only uppercase letters in table name's // so that we can look at the tables with SQL for (i = 0; i < tNoOfTables; i++){ if (theStdTableNameFlag == 0){ - snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, (int)(NdbTick_CurrentMillisecond() / 1000)); } else { - snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } } diff --git a/ndb/test/ndbapi/flexHammer.cpp b/ndb/test/ndbapi/flexHammer.cpp index 80cc7c5a53f..688e70d501a 100644 --- a/ndb/test/ndbapi/flexHammer.cpp +++ b/ndb/test/ndbapi/flexHammer.cpp @@ -840,7 +840,7 @@ static int setAttrNames() int retVal = 0; for (i = 0; i < MAXATTR ; i++) { - retVal = snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); if (retVal < 0) { // Error in conversion return(-1); @@ -859,11 +859,11 @@ static int setTableNames() for (i = 0; i < MAXTABLES ; i++) { if (theStandardTableNameFlag == 0) { - retVal = snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, NdbTick_CurrentMillisecond()/1000); } // if else { - retVal = snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } // else if (retVal < 0) { // Error in conversion diff --git a/ndb/test/ndbapi/flexScan.cpp b/ndb/test/ndbapi/flexScan.cpp index b09d71fb010..c7f4041a525 100644 --- a/ndb/test/ndbapi/flexScan.cpp +++ b/ndb/test/ndbapi/flexScan.cpp @@ -713,7 +713,7 @@ static int setAttrNames() int retVal = 0; for (i = 0; i < MAXATTR ; i++) { - retVal = snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); if (retVal < 0) { return(-1); } // if @@ -733,11 +733,11 @@ static int setTableNames() for (i = 0; i < MAXTABLES ; i++) { if (theStdTableNameFlag == 0) { - retVal = snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, (int)(NdbTick_CurrentMillisecond() / 1000)); } // if else { - retVal = snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } // if else if (retVal < 0) { diff --git a/ndb/test/ndbapi/flexTT.cpp b/ndb/test/ndbapi/flexTT.cpp index 162fc080218..3b976f9f87e 100644 --- a/ndb/test/ndbapi/flexTT.cpp +++ b/ndb/test/ndbapi/flexTT.cpp @@ -641,17 +641,17 @@ defineOperation(NdbConnection* localNdbConnection, TransNdb* transNdbRef, static void setAttrNames() { - snprintf(attrName[0], MAXSTRLEN, "VPN_ID"); - snprintf(attrName[1], MAXSTRLEN, "VPN_NB"); - snprintf(attrName[2], MAXSTRLEN, "DIRECTORY_NB"); - snprintf(attrName[3], MAXSTRLEN, "LAST_CALL_PARTY"); - snprintf(attrName[4], MAXSTRLEN, "DESCR"); + BaseString::snprintf(attrName[0], MAXSTRLEN, "VPN_ID"); + BaseString::snprintf(attrName[1], MAXSTRLEN, "VPN_NB"); + BaseString::snprintf(attrName[2], MAXSTRLEN, "DIRECTORY_NB"); + BaseString::snprintf(attrName[3], MAXSTRLEN, "LAST_CALL_PARTY"); + BaseString::snprintf(attrName[4], MAXSTRLEN, "DESCR"); } static void setTableNames() { - snprintf(tableName[0], MAXSTRLEN, "VPN_USERS"); + BaseString::snprintf(tableName[0], MAXSTRLEN, "VPN_USERS"); } static diff --git a/ndb/test/ndbapi/flex_bench_mysql.cpp b/ndb/test/ndbapi/flex_bench_mysql.cpp index 8e1fbcd9058..c8d4d85bedf 100644 --- a/ndb/test/ndbapi/flex_bench_mysql.cpp +++ b/ndb/test/ndbapi/flex_bench_mysql.cpp @@ -1552,7 +1552,7 @@ static int readArguments(int argc, const char** argv) const char *q = strrchr(p, ':'); if (q == 0) return -1; - snprintf(statHost, sizeof(statHost), "%.*s", q-p, p); + BaseString::snprintf(statHost, sizeof(statHost), "%.*s", q-p, p); statPort = atoi(q+1); statEnable = true; argc -= 1; @@ -1618,17 +1618,17 @@ static int createTables(MYSQL* mysqlp){ for (Uint32 i = 0; i < tNoOfAttributes; i++){ - snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); } // Note! Uses only uppercase letters in table name's // so that we can look at the tables with SQL for (Uint32 i = 0; i < tNoOfTables; i++){ if (theStdTableNameFlag == 0){ - snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, (int)(NdbTick_CurrentMillisecond() / 1000)); } else { - snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } } @@ -1663,17 +1663,17 @@ static int createTables(Ndb* pMyNdb){ for (Uint32 i = 0; i < tNoOfAttributes; i++){ - snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); } // Note! Uses only uppercase letters in table name's // so that we can look at the tables with SQL for (Uint32 i = 0; i < tNoOfTables; i++){ if (theStdTableNameFlag == 0){ - snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%d", i, (int)(NdbTick_CurrentMillisecond() / 1000)); } else { - snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); + BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i); } } diff --git a/ndb/test/ndbapi/interpreterInTup.cpp b/ndb/test/ndbapi/interpreterInTup.cpp index 20d84e6e96d..a07d5898213 100644 --- a/ndb/test/ndbapi/interpreterInTup.cpp +++ b/ndb/test/ndbapi/interpreterInTup.cpp @@ -1507,12 +1507,12 @@ void delete_rows(Ndb* pMyNdb, int tupleTest, int opType) { inline void setAttrNames(){ for (int i = 0; i < MAXATTR; i++){ - snprintf(attrName[i], MAXSTRLEN, "COL%d", i); + BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i); } } inline void setTableNames(){ - snprintf(tableName, MAXSTRLEN, "TAB1"); + BaseString::snprintf(tableName, MAXSTRLEN, "TAB1"); } diff --git a/ndb/test/ndbapi/testBasic.cpp b/ndb/test/ndbapi/testBasic.cpp index 7d03016b87a..4d64b15ecfa 100644 --- a/ndb/test/ndbapi/testBasic.cpp +++ b/ndb/test/ndbapi/testBasic.cpp @@ -160,8 +160,8 @@ int runPkDirtyRead(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (i<loops) { g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, - batchSize, dirty) != NDBT_OK){ + if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize, + NdbOperation::LM_CommittedRead) != NDBT_OK){ g_info << endl; return NDBT_FAILED; } @@ -398,14 +398,14 @@ int runNoCommitSleep(NDBT_Context* ctx, NDBT_Step* step){ for (int i = 2; i < 8; i++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); ndbout << i <<": Sleeping for " << sleepTime << " ms" << endl; NdbSleep_MilliSleep(sleepTime); // Dont care about result of these ops - hugoOps.pkReadRecord(pNdb, 1, true); + hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive); hugoOps.closeTransaction(pNdb); sleepTime = sleepTime *i; @@ -424,16 +424,16 @@ int runCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); @@ -467,7 +467,7 @@ int runCommit_TryCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction, TryCommit CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -475,11 +475,11 @@ int runCommit_TryCommit626(NDBT_Context* ctx, NDBT_Step* step){ // Several operations in one transaction // The insert is OK CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, TryCommit) == 626); }while(false); @@ -513,20 +513,23 @@ int runCommit_CommitAsMuchAsPossible626(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); - }while(false); + + CHECK(hugoOps.startTransaction(pNdb) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1) == 0); + CHECK(hugoOps.execute_Commit(pNdb) == 0); + CHECK(hugoOps.closeTransaction(pNdb) == 0); + } while(false); hugoOps.closeTransaction(pNdb); @@ -542,8 +545,14 @@ int runCommit_CommitAsMuchAsPossible630(NDBT_Context* ctx, NDBT_Step* step){ // Commit transaction, CommitAsMuchAsPossible CHECK(hugoOps.startTransaction(pNdb) == 0); CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0); + CHECK(hugoOps.pkDeleteRecord(pNdb, 2) == 0); CHECK(hugoOps.execute_Commit(pNdb, CommitAsMuchAsPossible) == 630); - }while(false); + CHECK(hugoOps.closeTransaction(pNdb) == 0); + + CHECK(hugoOps.startTransaction(pNdb) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2) == 0); + CHECK(hugoOps.execute_Commit(pNdb) == 0); + } while(false); hugoOps.closeTransaction(pNdb); @@ -558,13 +567,13 @@ int runNoCommit626(NDBT_Context* ctx, NDBT_Step* step){ do{ // No commit transaction, readTuple CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.closeTransaction(pNdb) == 0); // No commit transaction, readTupleExcluive CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); }while(false); @@ -598,7 +607,7 @@ int runNoCommitRollback626(NDBT_Context* ctx, NDBT_Step* step){ do{ // No commit transaction, rollback CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -606,10 +615,10 @@ int runNoCommitRollback626(NDBT_Context* ctx, NDBT_Step* step){ // No commit transaction, rollback // Multiple operations CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 2, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 3, true) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 4, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 2, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 3, 1, NdbOperation::LM_Exclusive) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 4, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); }while(false); @@ -647,7 +656,7 @@ int runNoCommitAndClose(NDBT_Context* ctx, NDBT_Step* step){ // Read CHECK(hugoOps.startTransaction(pNdb) == 0); for (i = 0; i < 10; i++) - CHECK(hugoOps.pkReadRecord(pNdb, i, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -701,7 +710,7 @@ int runCheckRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -709,13 +718,13 @@ int runCheckRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record is not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.compareRecordToCopy() == NDBT_OK); @@ -736,7 +745,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, false, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Update value 0 CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -747,7 +756,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check record is updated - CHECK(hugoOps.pkReadRecord(pNdb, 1, true, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(5) == NDBT_OK); // Updates value 5 CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -756,7 +765,7 @@ int runCheckRollbackUpdate(NDBT_Context* ctx, NDBT_Step* step){ // Check record is back to original value CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 1, true, numRecords) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 1, numRecords, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); // Updates value 0 @@ -775,7 +784,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read value and save it for later CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, false, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -785,7 +794,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ for(Uint32 i = 0; i<1; i++){ // Read record 5 - 10 CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); for(j = 0; j<10; j++){ @@ -794,7 +803,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.pkUpdateRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } @@ -806,7 +815,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ #if 0 // Check records are deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); #endif @@ -814,7 +823,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.pkInsertRecord(pNdb, 5, 10, updatesValue) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(updatesValue) == 0); } @@ -823,7 +832,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Check records are deleted - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 626); CHECK(hugoOps.execute_Rollback(pNdb) == 0); @@ -833,7 +842,7 @@ int runCheckRollbackDeleteMultiple(NDBT_Context* ctx, NDBT_Step* step){ // Check records are not deleted // after rollback CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.verifyUpdatesValue(0) == NDBT_OK); @@ -853,7 +862,7 @@ int runCheckImplicitRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read record 5 CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -872,7 +881,7 @@ int runCheckImplicitRollbackDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record is not deleted // Close transaction should have rollbacked CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 1, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); }while(false); @@ -889,7 +898,7 @@ int runCheckCommitDelete(NDBT_Context* ctx, NDBT_Step* step){ do{ // Read 10 records CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); // Update 10 records @@ -905,7 +914,7 @@ int runCheckCommitDelete(NDBT_Context* ctx, NDBT_Step* step){ // Check record's are deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 626); }while(false); @@ -930,7 +939,7 @@ int runRollbackNothing(NDBT_Context* ctx, NDBT_Step* step){ // Check records are not deleted CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, 5, true, 10) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, 5, 10, NdbOperation::LM_Exclusive) == 0); CHECK(hugoOps.execute_Commit(pNdb) == 0); CHECK(hugoOps.closeTransaction(pNdb) == 0); @@ -964,8 +973,8 @@ int runMassiveRollback(NDBT_Context* ctx, NDBT_Step* step){ for(int row = 0; row < records; row++){ int res; CHECK(hugoOps.startTransaction(pNdb) == 0); - for(int i = 0; i<OPS_TOTAL; i += OPS_PER_TRANS){ - for(int j = 0; j<OPS_PER_TRANS; j++){ + for(Uint32 i = 0; i<OPS_TOTAL; i += OPS_PER_TRANS){ + for(Uint32 j = 0; j<OPS_PER_TRANS; j++){ CHECK(hugoOps.pkUpdateRecord(pNdb, row, 1, i) == 0); } g_info << "Performed " << (i+OPS_PER_TRANS) << " updates on row: " << row @@ -1007,9 +1016,9 @@ runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ const Uint32 OPS_TOTAL = 4096; const Uint32 LOOPS = 10; - for(int loop = 0; loop<LOOPS; loop++){ + for(Uint32 loop = 0; loop<LOOPS; loop++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - for(int i = 0; i<OPS_TOTAL-1; i ++){ + for(Uint32 i = 0; i<OPS_TOTAL-1; i ++){ if((i & 1) == 0){ CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, loop) == 0); } else { @@ -1110,13 +1119,6 @@ TESTCASE("ReadWithLocksAndInserts", STEP(runInsertUntilStopped); FINALIZER(runClearTable); } -TESTCASE("ReadConsistency", - "Check that a read within a transaction returns the " \ - "same result no matter"){ - STEP(runInsertOne); - STEP(runReadOne); - FINALIZER(runClearTable2); -} TESTCASE("PkInsertTwice", "Verify that we can't insert an already inserted record." "Error should be returned" ){ @@ -1124,12 +1126,6 @@ TESTCASE("PkInsertTwice", STEP(runInsertTwice); FINALIZER(runClearTable); } -TESTCASE("Fill", - "Verify what happens when we fill the db" ){ - INITIALIZER(runFillTable); - INITIALIZER(runPkRead); - FINALIZER(runClearTable2); -} TESTCASE("NoCommitSleep", "Verify what happens when a NoCommit transaction is aborted by " "NDB because the application is sleeping" ){ @@ -1275,8 +1271,24 @@ TESTCASE("MassiveTransaction", INITIALIZER(runLoadTable2); FINALIZER(runClearTable2); } +TESTCASE("Fill", + "Verify what happens when we fill the db" ){ + INITIALIZER(runFillTable); + INITIALIZER(runPkRead); + FINALIZER(runClearTable2); +} NDBT_TESTSUITE_END(testBasic); +#if 0 +TESTCASE("ReadConsistency", + "Check that a read within a transaction returns the " \ + "same result no matter"){ + STEP(runInsertOne); + STEP(runReadOne); + FINALIZER(runClearTable2); +} +#endif + int main(int argc, const char** argv){ ndb_init(); return testBasic.execute(argc, argv); diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp index e18f4a8bd1a..41bb82f3e06 100644 --- a/ndb/test/ndbapi/testBlobs.cpp +++ b/ndb/test/ndbapi/testBlobs.cpp @@ -1030,7 +1030,7 @@ readScan(int style, bool idx) } else { CHK((g_ops = g_con->getNdbIndexScanOperation(g_opt.m_x2name, g_opt.m_tname)) != 0); } - CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Exclusive)) != 0); + CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0); CHK(g_ops->getValue("PK1", (char*)&tup.m_pk1) != 0); if (g_opt.m_pk2len != 0) CHK(g_ops->getValue("PK2", tup.m_pk2) != 0); diff --git a/ndb/test/ndbapi/testDataBuffers.cpp b/ndb/test/ndbapi/testDataBuffers.cpp index 94658d5c6b9..04602f51d5f 100644 --- a/ndb/test/ndbapi/testDataBuffers.cpp +++ b/ndb/test/ndbapi/testDataBuffers.cpp @@ -93,7 +93,7 @@ ndberror(char const* fmt, ...) va_list ap; char buf[200]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << buf << " --" << endl; if (ndb) @@ -115,7 +115,7 @@ chkerror(char const* fmt, ...) va_list ap; char buf[200]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << "*** check failed: " << buf << " ***" << endl; return -1; diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp index 7cba5ce4cc8..89232de2535 100644 --- a/ndb/test/ndbapi/testDict.cpp +++ b/ndb/test/ndbapi/testDict.cpp @@ -55,7 +55,7 @@ int runCreateInvalidTables(NDBT_Context* ctx, NDBT_Step* step){ char failTabName[256]; for (int i = 0; i < 10; i++){ - snprintf(failTabName, 256, "F%d", i); + BaseString::snprintf(failTabName, 256, "F%d", i); const NdbDictionary::Table* pFailTab = NDBT_Tables::getTable(failTabName); if (pFailTab != NULL){ @@ -425,7 +425,7 @@ int runCreateMaxTables(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = GETNDB(step); for (int i = 0; i < numTables && failures < 5; i++){ - snprintf(tabName, 256, "MAXTAB%d", i); + BaseString::snprintf(tabName, 256, "MAXTAB%d", i); if (pNdb->waitUntilReady(30) != 0){ // Db is not ready, return with failure @@ -491,7 +491,7 @@ int runDropMaxTables(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = GETNDB(step); for (int i = 0; i < numTables; i++){ - snprintf(tabName, 256, "MAXTAB%d", i); + BaseString::snprintf(tabName, 256, "MAXTAB%d", i); if (pNdb->waitUntilReady(30) != 0){ // Db is not ready, return with failure @@ -707,7 +707,7 @@ int runPkSizes(NDBT_Context* ctx, NDBT_Step* step){ int numRecords = ctx->getNumRecords(); for (int i = minPkSize; i < maxPkSize; i++){ - snprintf(tabName, 256, "TPK_%d", i); + BaseString::snprintf(tabName, 256, "TPK_%d", i); int records = numRecords; int max = ~0; diff --git a/ndb/test/ndbapi/testIndex.cpp b/ndb/test/ndbapi/testIndex.cpp index bef3b310c96..ed9e114fd92 100644 --- a/ndb/test/ndbapi/testIndex.cpp +++ b/ndb/test/ndbapi/testIndex.cpp @@ -150,7 +150,7 @@ int create_index(NDBT_Context* ctx, int indxNum, } // Create index - snprintf(idxName, 255, "IDC%d", indxNum); + BaseString::snprintf(idxName, 255, "IDC%d", indxNum); if (orderedIndex) ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index "<<idxName << " ("; else @@ -194,7 +194,7 @@ int drop_index(int indxNum, Ndb* pNdb, if (attr->indexCreated == false) return NDBT_OK; - snprintf(idxName, 255, "IDC%d", indxNum); + BaseString::snprintf(idxName, 255, "IDC%d", indxNum); // Drop index ndbout << "Dropping index "<<idxName<<"(" << pTab->getName() << ") "; @@ -284,7 +284,7 @@ int createRandomIndex_Drop(NDBT_Context* ctx, NDBT_Step* step){ Uint32 i = ctx->getProperty("createRandomIndex"); - snprintf(idxName, 255, "IDC%d", i); + BaseString::snprintf(idxName, 255, "IDC%d", i); // Drop index ndbout << "Dropping index " << idxName << " "; @@ -309,7 +309,7 @@ int createPkIndex(NDBT_Context* ctx, NDBT_Step* step){ bool logged = ctx->getProperty("LoggedIndexes", 1); // Create index - snprintf(pkIdxName, 255, "IDC_PK_%s", pTab->getName()); + BaseString::snprintf(pkIdxName, 255, "IDC_PK_%s", pTab->getName()); if (orderedIndex) ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index " << pkIdxName << " ("; @@ -381,27 +381,6 @@ runVerifyIndex(NDBT_Context* ctx, NDBT_Step* step){ } int -sync_down(NDBT_Context* ctx){ - Uint32 threads = ctx->getProperty("PauseThreads", (unsigned)0); - if(threads){ - ctx->decProperty("PauseThreads"); - } - return 0; -} - -int -sync_up_and_wait(NDBT_Context* ctx){ - Uint32 threads = ctx->getProperty("Threads", (unsigned)0); - ndbout_c("Setting PauseThreads to %d", threads); - ctx->setProperty("PauseThreads", threads); - ctx->getPropertyWait("PauseThreads", (unsigned)0); - if(threads){ - ndbout_c("wait completed"); - } - return 0; -} - -int runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ // Verify that data in index match // table data @@ -416,7 +395,7 @@ runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -425,7 +404,7 @@ runTransactions1(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -446,7 +425,7 @@ runTransactions2(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } #endif - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; #if 1 @@ -455,7 +434,7 @@ runTransactions2(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } #endif - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -476,7 +455,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ g_err << "Load table failed" << endl; return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -485,7 +464,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -494,7 +473,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -503,7 +482,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -512,7 +491,7 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; @@ -521,14 +500,14 @@ runTransactions3(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_FAILED; } - sync_down(ctx); + ctx->sync_down("PauseThreads"); if(ctx->isTestStopped()) break; int count = -1; if(utilTrans.selectCount(pNdb, 64, &count) != 0 || count != 0) return NDBT_FAILED; - sync_down(ctx); + ctx->sync_down("PauseThreads"); } return NDBT_OK; } @@ -540,6 +519,7 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ NdbRestarts restarts; int i = 0; int timeout = 240; + int sync_threads = ctx->getProperty("Threads", (unsigned)0); while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ if(restarts.executeRestart("RestartRandomNodeAbort", timeout) != 0){ @@ -547,7 +527,7 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ result = NDBT_FAILED; break; } - sync_up_and_wait(ctx); + ctx->sync_up_and_wait("PauseThreads", sync_threads); i++; } ctx->stopTest(); @@ -1088,7 +1068,7 @@ runUniqueNullTransactions(NDBT_Context* ctx, NDBT_Step* step){ const NdbDictionary::Table* pTab = ctx->getTab(); // Create index char nullIndex[255]; - snprintf(nullIndex, 255, "IDC_PK_%s_NULL", pTab->getName()); + BaseString::snprintf(nullIndex, 255, "IDC_PK_%s_NULL", pTab->getName()); if (orderedIndex) ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index " << pkIdxName << " ("; diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index 47987629fe3..74cb1f8bcd0 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -229,7 +229,7 @@ int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){ int i = 0; while (errors < maxErrors){ - if(hugoOps.pkReadRecord(pNdb,1, false, 1) != NDBT_OK){ + if(hugoOps.pkReadRecord(pNdb,1, 1) != NDBT_OK){ errors++; continue; } diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp index 6bfe59f8d3f..e844f227034 100644 --- a/ndb/test/ndbapi/testNodeRestart.cpp +++ b/ndb/test/ndbapi/testNodeRestart.cpp @@ -100,11 +100,16 @@ int runScanReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int runPkReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); + NdbOperation::LockMode lm = + (NdbOperation::LockMode)ctx->getProperty("ReadLockMode", + (Uint32)NdbOperation::LM_Read); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, 128) != 0){ + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + if (hugoTrans.pkReadRecords(GETNDB(step), rows, batch, lm) != 0){ return NDBT_FAILED; } i++; @@ -119,7 +124,9 @@ int runPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { g_info << i << ": "; - if (hugoTrans.pkUpdateRecords(GETNDB(step), records) != 0){ + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + if (hugoTrans.pkUpdateRecords(GETNDB(step), rows, batch) != 0){ return NDBT_FAILED; } i++; @@ -127,6 +134,60 @@ int runPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runPkReadPkUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + int records = ctx->getNumRecords(); + Ndb* pNdb = GETNDB(step); + int i = 0; + HugoOperations hugoOps(*ctx->getTab()); + while (ctx->isTestStopped() == false) { + g_info << i++ << ": "; + int rows = (rand()%records)+1; + int batch = (rand()%rows)+1; + int row = (records - rows) ? rand() % (records - rows) : 0; + + int j,k; + for(j = 0; j<rows; j += batch) + { + k = batch; + if(j+k > rows) + k = rows - j; + + if(hugoOps.startTransaction(pNdb) != 0) + goto err; + + if(hugoOps.pkReadRecord(pNdb, row+j, k, NdbOperation::LM_Exclusive) != 0) + goto err; + + if(hugoOps.execute_NoCommit(pNdb) != 0) + goto err; + + if(hugoOps.pkUpdateRecord(pNdb, row+j, k, rand()) != 0) + goto err; + + if(hugoOps.execute_Commit(pNdb) != 0) + goto err; + + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + } + + continue; +err: + NdbConnection* pCon = hugoOps.getTransaction(); + if(pCon == 0) + continue; + NdbError error = pCon->getNdbError(); + hugoOps.closeTransaction(pNdb); + if (error.status == NdbError::TemporaryError){ + NdbSleep_MilliSleep(50); + continue; + } + return NDBT_FAILED; + } + return NDBT_OK; +} + int runScanUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int records = ctx->getNumRecords(); @@ -158,6 +219,7 @@ int runScanReadVerify(NDBT_Context* ctx, NDBT_Step* step){ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; int loops = ctx->getNumLoops(); + int sync_threads = ctx->getProperty("SyncThreads", (unsigned)0); NdbRestarter restarter; int i = 0; int lastId = 0; @@ -174,11 +236,11 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ loops *= restarter.getNumDbNodes(); while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ - + int id = lastId % restarter.getNumDbNodes(); int nodeId = restarter.getDbNodeId(id); ndbout << "Restart node " << nodeId << endl; - if(restarter.restartOneDbNode(nodeId) != 0){ + if(restarter.restartOneDbNode(nodeId, false, false, true) != 0){ g_err << "Failed to restartNextDbNode" << endl; result = NDBT_FAILED; break; @@ -190,7 +252,7 @@ int runRestarter(NDBT_Context* ctx, NDBT_Step* step){ break; } - NdbSleep_SecSleep(1); + ctx->sync_up_and_wait("PauseThreads", sync_threads); lastId++; i++; @@ -234,6 +296,54 @@ int runRestarts(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runDirtyRead(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + int records = ctx->getNumRecords(); + NdbRestarter restarter; + HugoOperations hugoOps(*ctx->getTab()); + Ndb* pNdb = GETNDB(step); + + int i = 0; + while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){ + g_info << i << ": "; + + int id = i % restarter.getNumDbNodes(); + int nodeId = restarter.getDbNodeId(id); + ndbout << "Restart node " << nodeId << endl; + restarter.insertErrorInAllNodes(5041); + restarter.insertErrorInAllNodes(8048 + (i & 1)); + + for(int j = 0; j<records; j++){ + if(hugoOps.startTransaction(pNdb) != 0) + return NDBT_FAILED; + + if(hugoOps.pkReadRecord(pNdb, j, 1, NdbOperation::LM_CommittedRead) != 0) + goto err; + + int res; + if((res = hugoOps.execute_Commit(pNdb)) == 4119) + goto done; + + if(res != 0) + goto err; + + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + } +done: + if(hugoOps.closeTransaction(pNdb) != 0) + return NDBT_FAILED; + + i++; + restarter.waitClusterStarted(60) ; + } + return result; +err: + hugoOps.closeTransaction(pNdb); + return NDBT_FAILED; +} + NDBT_TESTSUITE(testNodeRestart); TESTCASE("NoLoad", "Test that one node at a time can be stopped and then restarted "\ @@ -246,6 +356,27 @@ TESTCASE("NoLoad", TESTCASE("PkRead", "Test that one node at a time can be stopped and then restarted "\ "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_Read); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("PkReadCommitted", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_CommittedRead); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedPkRead", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); INITIALIZER(runCheckAllNodesStarted); INITIALIZER(runLoadTable); STEP(runRestarter); @@ -255,14 +386,31 @@ TESTCASE("PkRead", TESTCASE("PkReadPkUpdate", "Test that one node at a time can be stopped and then restarted "\ "perform pk read and pk update while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", NdbOperation::LM_Read); INITIALIZER(runCheckAllNodesStarted); INITIALIZER(runLoadTable); STEP(runRestarter); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedPkReadPkUpdate", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read and pk update while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runPkReadUntilStopped); STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); FINALIZER(runClearTable); } TESTCASE("ReadUpdateScan", @@ -273,6 +421,21 @@ TESTCASE("ReadUpdateScan", STEP(runRestarter); STEP(runPkReadUntilStopped); STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); + STEP(runScanReadUntilStopped); + STEP(runScanUpdateUntilStopped); + FINALIZER(runClearTable); +} +TESTCASE("MixedReadUpdateScan", + "Test that one node at a time can be stopped and then restarted "\ + "perform pk read, pk update and scan reads while restarting. Do this loop number of times"){ + TC_PROPERTY("ReadLockMode", -1); + INITIALIZER(runCheckAllNodesStarted); + INITIALIZER(runLoadTable); + STEP(runRestarter); + STEP(runPkReadUntilStopped); + STEP(runPkUpdateUntilStopped); + STEP(runPkReadPkUpdateUntilStopped); STEP(runScanReadUntilStopped); STEP(runScanUpdateUntilStopped); FINALIZER(runClearTable); @@ -431,6 +594,12 @@ TESTCASE("StopOnError", FINALIZER(runScanReadVerify); FINALIZER(runClearTable); } +TESTCASE("CommittedRead", + "Test committed read"){ + INITIALIZER(runLoadTable); + STEP(runDirtyRead); + FINALIZER(runClearTable); +} NDBT_TESTSUITE_END(testNodeRestart); int main(int argc, const char** argv){ diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index f9eb3514926..1c611d2b8ff 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -40,18 +40,21 @@ struct Opt { bool m_core; const char* m_csname; CHARSET_INFO* m_cs; + int m_die; bool m_dups; NdbDictionary::Object::FragmentType m_fragtype; - unsigned m_idxloop; + unsigned m_subsubloop; const char* m_index; unsigned m_loop; - bool m_nologging; bool m_msglock; + bool m_nologging; + bool m_noverify; unsigned m_pctnull; unsigned m_rows; unsigned m_samples; - unsigned m_scanrd; - unsigned m_scanex; + unsigned m_scanbat; + unsigned m_scanpar; + unsigned m_scanstop; unsigned m_seed; unsigned m_subloop; const char* m_table; @@ -64,22 +67,25 @@ struct Opt { m_core(false), m_csname("latin1_bin"), m_cs(0), + m_die(0), m_dups(false), m_fragtype(NdbDictionary::Object::FragUndefined), - m_idxloop(4), + m_subsubloop(4), m_index(0), m_loop(1), - m_nologging(false), m_msglock(true), + m_nologging(false), + m_noverify(false), m_pctnull(10), m_rows(1000), m_samples(0), - m_scanrd(240), - m_scanex(240), + m_scanbat(0), + m_scanpar(0), + m_scanstop(0), m_seed(0), m_subloop(4), m_table(0), - m_threads(4), + m_threads(10), m_v(1) { } }; @@ -100,16 +106,18 @@ printhelp() << " -case abc only given test cases (letters a-z)" << endl << " -core core dump on error [" << d.m_core << "]" << endl << " -csname S charset (collation) of non-pk char column [" << d.m_csname << "]" << endl + << " -die nnn exit immediately on NDB error code nnn" << endl << " -dups allow duplicate tuples from index scan [" << d.m_dups << "]" << endl << " -fragtype T fragment type single/small/medium/large" << endl << " -index xyz only given index numbers (digits 1-9)" << endl << " -loop N loop count full suite 0=forever [" << d.m_loop << "]" << endl << " -nologging create tables in no-logging mode" << endl + << " -noverify skip index verifications" << endl << " -pctnull N pct NULL values in nullable column [" << d.m_pctnull << "]" << endl << " -rows N rows per thread [" << d.m_rows << "]" << endl << " -samples N samples for some timings (0=all) [" << d.m_samples << "]" << endl - << " -scanrd N scan read parallelism [" << d.m_scanrd << "]" << endl - << " -scanex N scan exclusive parallelism [" << d.m_scanex << "]" << endl + << " -scanbat N scan batch per fragment (ignored by ndb api) [" << d.m_scanbat << "]" << endl + << " -scanpar N scan parallelism [" << d.m_scanpar << "]" << endl << " -seed N srandom seed 0=loop number[" << d.m_seed << "]" << endl << " -subloop N subtest loop count [" << d.m_subloop << "]" << endl << " -table xyz only given table numbers (digits 1-9)" << endl @@ -208,10 +216,14 @@ struct Par : public Opt { Set& set() const { assert(m_set != 0); return *m_set; } Tmr* m_tmr; Tmr& tmr() const { assert(m_tmr != 0); return *m_tmr; } + unsigned m_lno; + unsigned m_slno; unsigned m_totrows; // value calculation unsigned m_range; unsigned m_pctrange; + // choice of key + bool m_randomkey; // do verify after read bool m_verify; // deadlock possible @@ -224,9 +236,12 @@ struct Par : public Opt { m_tab(0), m_set(0), m_tmr(0), + m_lno(0), + m_slno(0), m_totrows(m_threads * m_rows), m_range(m_rows), m_pctrange(0), + m_randomkey(false), m_verify(false), m_deadlock(false) { } @@ -688,13 +703,14 @@ struct Con { int setBound(int num, int type, const void* value); int execute(ExecType t); int execute(ExecType t, bool& deadlock); - int openScanRead(unsigned parallelism); - int openScanExclusive(unsigned parallelism); + int openScanRead(unsigned scanbat, unsigned scanpar); + int openScanExclusive(unsigned scanbat, unsigned scanpar); int executeScan(); int nextScanResult(bool fetchAllowed); int nextScanResult(bool fetchAllowed, bool& deadlock); int updateScanTuple(Con& con2); int deleteScanTuple(Con& con2); + void closeScan(); void closeTransaction(); void printerror(NdbOut& out); }; @@ -815,18 +831,20 @@ Con::execute(ExecType t, bool& deadlock) } int -Con::openScanRead(unsigned parallelism) +Con::openScanRead(unsigned scanbat, unsigned scanpar) { assert(m_tx != 0 && m_op != 0); - CHKCON((m_resultset = m_scanop->readTuples(parallelism)) != 0, *this); + NdbOperation::LockMode lm = NdbOperation::LM_Read; + CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this); return 0; } int -Con::openScanExclusive(unsigned parallelism) +Con::openScanExclusive(unsigned scanbat, unsigned scanpar) { assert(m_tx != 0 && m_op != 0); - CHKCON((m_resultset = m_scanop->readTuplesExclusive(parallelism)) != 0, *this); + NdbOperation::LockMode lm = NdbOperation::LM_Exclusive; + CHKCON((m_resultset = m_scanop->readTuples(lm, scanbat, scanpar)) != 0, *this); return 0; } @@ -880,11 +898,21 @@ Con::deleteScanTuple(Con& con2) } void +Con::closeScan() +{ + assert(m_resultset != 0); + m_resultset->close(); + m_scanop = 0, m_indexscanop = 0, m_resultset = 0; + +} + +void Con::closeTransaction() { assert(m_ndb != 0 && m_tx != 0); m_ndb->closeTransaction(m_tx); m_tx = 0, m_op = 0; + m_scanop = 0, m_indexscanop = 0, m_resultset = 0; } void @@ -893,27 +921,37 @@ Con::printerror(NdbOut& out) m_errtype = ErrOther; unsigned any = 0; int code; + int die = 0; if (m_ndb) { if ((code = m_ndb->getNdbError().code) != 0) { LL0(++any << " ndb: error " << m_ndb->getNdbError()); + die += (code == g_opt.m_die); } if (m_dic && (code = m_dic->getNdbError().code) != 0) { LL0(++any << " dic: error " << m_dic->getNdbError()); + die += (code == g_opt.m_die); } if (m_tx) { if ((code = m_tx->getNdbError().code) != 0) { LL0(++any << " con: error " << m_tx->getNdbError()); + die += (code == g_opt.m_die); if (code == 266 || code == 274 || code == 296 || code == 297 || code == 499) m_errtype = ErrDeadlock; } if (m_op && m_op->getNdbError().code != 0) { LL0(++any << " op : error " << m_op->getNdbError()); + die += (code == g_opt.m_die); } } } if (! any) { LL0("failed but no NDB error code"); } + if (die) { + if (g_opt.m_core) + abort(); + exit(1); + } } // dictionary operations @@ -1965,9 +2003,21 @@ BSet::calcpk(Par par, unsigned i) int BSet::setbnd(Par par) const { - for (unsigned j = 0; j < m_bvals; j++) { - const BVal& bval = *m_bval[j]; - CHK(bval.setbnd(par) == 0); + if (m_bvals != 0) { + unsigned p1 = urandom(m_bvals); + unsigned p2 = 10009; // prime + // random order + for (unsigned j = 0; j < m_bvals; j++) { + unsigned k = p1 + p2 * j; + const BVal& bval = *m_bval[k % m_bvals]; + CHK(bval.setbnd(par) == 0); + } + // duplicate + if (urandom(5) == 0) { + unsigned k = urandom(m_bvals); + const BVal& bval = *m_bval[k]; + CHK(bval.setbnd(par) == 0); + } } return 0; } @@ -2054,7 +2104,8 @@ pkinsert(Par par) CHK(con.startTransaction() == 0); Lst lst; for (unsigned j = 0; j < par.m_rows; j++) { - unsigned i = thrrow(par, j); + unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); + unsigned i = thrrow(par, j2); set.lock(); if (set.exist(i) || set.pending(i)) { set.unlock(); @@ -2107,7 +2158,8 @@ pkupdate(Par par) Lst lst; bool deadlock = false; for (unsigned j = 0; j < par.m_rows; j++) { - unsigned i = thrrow(par, j); + unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); + unsigned i = thrrow(par, j2); set.lock(); if (! set.exist(i) || set.pending(i)) { set.unlock(); @@ -2158,7 +2210,8 @@ pkdelete(Par par) Lst lst; bool deadlock = false; for (unsigned j = 0; j < par.m_rows; j++) { - unsigned i = thrrow(par, j); + unsigned j2 = ! par.m_randomkey ? j : urandom(par.m_rows); + unsigned i = thrrow(par, j2); set.lock(); if (! set.exist(i) || set.pending(i)) { set.unlock(); @@ -2268,7 +2321,7 @@ scanreadtable(Par par) Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(tab) == 0); - CHK(con.openScanRead(par.m_scanrd) == 0); + CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0); set2.getval(par); CHK(con.executeScan() == 0); while (1) { @@ -2296,7 +2349,7 @@ scanreadtablefast(Par par, unsigned countcheck) LL3("scanfast " << tab.m_name); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(tab) == 0); - CHK(con.openScanRead(par.m_scanrd) == 0); + CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0); // get 1st column NdbRecAttr* rec; CHK(con.getValue((Uint32)0, rec) == 0); @@ -2328,7 +2381,7 @@ scanreadindex(Par par, const ITab& itab, const BSet& bset) Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(itab, tab) == 0); - CHK(con.openScanRead(par.m_scanrd) == 0); + CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0); CHK(bset.setbnd(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); @@ -2359,7 +2412,7 @@ scanreadindexfast(Par par, const ITab& itab, const BSet& bset, unsigned countche LL4(bset); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(itab, tab) == 0); - CHK(con.openScanRead(par.m_scanrd) == 0); + CHK(con.openScanRead(par.m_scanbat, par.m_scanpar) == 0); CHK(bset.setbnd(par) == 0); // get 1st column NdbRecAttr* rec; @@ -2382,7 +2435,7 @@ static int scanreadindex(Par par, const ITab& itab) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < par.m_idxloop; i++) { + for (unsigned i = 0; i < par.m_subsubloop; i++) { BSet bset(tab, itab, par.m_rows); bset.calc(par); CHK(scanreadindex(par, itab, bset) == 0); @@ -2478,7 +2531,7 @@ scanupdatetable(Par par) Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(tab) == 0); - CHK(con.openScanExclusive(par.m_scanex) == 0); + CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0); set2.getval(par); CHK(con.executeScan() == 0); unsigned count = 0; @@ -2498,6 +2551,10 @@ scanupdatetable(Par par) LL1("scanupdatetable: stop on deadlock"); break; } + if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { + con.closeScan(); + break; + } do { unsigned i = (unsigned)-1; CHK(set2.getkey(par, &i) == 0); @@ -2557,7 +2614,7 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) Set set2(tab, set.m_rows); CHK(con.startTransaction() == 0); CHK(con.getNdbScanOperation(itab, tab) == 0); - CHK(con.openScanExclusive(par.m_scanex) == 0); + CHK(con.openScanExclusive(par.m_scanbat, par.m_scanpar) == 0); CHK(bset.setbnd(par) == 0); set2.getval(par); CHK(con.executeScan() == 0); @@ -2578,6 +2635,10 @@ scanupdateindex(Par par, const ITab& itab, const BSet& bset) LL1("scanupdateindex: stop on deadlock"); break; } + if (par.m_scanstop != 0 && urandom(par.m_scanstop) == 0) { + con.closeScan(); + break; + } do { unsigned i = (unsigned)-1; CHK(set2.getkey(par, &i) == 0); @@ -2629,7 +2690,7 @@ static int scanupdateindex(Par par, const ITab& itab) { const Tab& tab = par.tab(); - for (unsigned i = 0; i < par.m_idxloop; i++) { + for (unsigned i = 0; i < par.m_subsubloop; i++) { BSet bset(tab, itab, par.m_rows); bset.calc(par); CHK(scanupdateindex(par, itab, bset) == 0); @@ -2663,6 +2724,8 @@ scanupdateall(Par par) static int readverify(Par par) { + if (par.m_noverify) + return 0; par.m_verify = true; CHK(pkread(par) == 0); CHK(scanreadall(par) == 0); @@ -2670,6 +2733,55 @@ readverify(Par par) } static int +readverifyfull(Par par) +{ + if (par.m_noverify) + return 0; + par.m_verify = true; + if (par.m_no == 0) + CHK(scanreadtable(par) == 0); + else { + const Tab& tab = par.tab(); + unsigned i = par.m_no; + if (i <= tab.m_itabs && useindex(i)) { + const ITab& itab = tab.m_itab[i - 1]; + BSet bset(tab, itab, par.m_rows); + CHK(scanreadindex(par, itab, bset) == 0); + } + } + return 0; +} + +static int +pkops(Par par) +{ + par.m_randomkey = true; + for (unsigned i = 0; i < par.m_subsubloop; i++) { + unsigned sel = urandom(10); + if (par.m_slno % 2 == 0) { + // favor insert + if (sel < 8) { + CHK(pkinsert(par) == 0); + } else if (sel < 9) { + CHK(pkupdate(par) == 0); + } else { + CHK(pkdelete(par) == 0); + } + } else { + // favor delete + if (sel < 1) { + CHK(pkinsert(par) == 0); + } else if (sel < 2) { + CHK(pkupdate(par) == 0); + } else { + CHK(pkdelete(par) == 0); + } + } + } + return 0; +} + +static int pkupdatescanread(Par par) { par.m_dups = true; @@ -2691,6 +2803,7 @@ mixedoperations(Par par) { par.m_dups = true; par.m_deadlock = true; + par.m_scanstop = par.m_totrows; // randomly close scans unsigned sel = urandom(10); if (sel < 2) { CHK(pkdelete(par) == 0); @@ -2710,6 +2823,7 @@ pkupdateindexbuild(Par par) if (par.m_no == 0) { CHK(createindex(par) == 0); } else { + par.m_randomkey = true; CHK(pkupdate(par) == 0); } return 0; @@ -2913,6 +3027,8 @@ runstep(Par par, const char* fname, TFunc func, unsigned mode) thr.m_par.m_tab = par.m_tab; thr.m_par.m_set = par.m_set; thr.m_par.m_tmr = par.m_tmr; + thr.m_par.m_lno = par.m_lno; + thr.m_par.m_slno = par.m_slno; thr.m_func = func; thr.start(); } @@ -2936,8 +3052,8 @@ tbuild(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { - if (i % 2 == 0) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + if (par.m_slno % 2 == 0) { RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, pkinsert, MT); @@ -2946,9 +3062,10 @@ tbuild(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); } - RUNSTEP(par, readverify, MT); + RUNSTEP(par, pkupdate, MT); + RUNSTEP(par, readverifyfull, MT); RUNSTEP(par, pkdelete, MT); - RUNSTEP(par, readverify, MT); + RUNSTEP(par, readverifyfull, MT); RUNSTEP(par, dropindex, ST); } return 0; @@ -2960,11 +3077,27 @@ tpkops(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); + RUNSTEP(par, createindex, ST); + RUNSTEP(par, invalidateindex, MT); + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { + RUNSTEP(par, pkops, MT); + LL2("rows=" << par.set().count()); + RUNSTEP(par, readverifyfull, MT); + } + return 0; +} + +static int +tpkopsread(Par par) +{ + RUNSTEP(par, droptable, ST); + RUNSTEP(par, createtable, ST); + RUNSTEP(par, invalidatetable, MT); RUNSTEP(par, pkinsert, MT); RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverify, ST); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkupdatescanread, MT); RUNSTEP(par, readverify, ST); } @@ -2983,7 +3116,7 @@ tmixedops(Par par) RUNSTEP(par, createindex, ST); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverify, ST); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, mixedoperations, MT); RUNSTEP(par, readverify, ST); } @@ -2997,7 +3130,7 @@ tbusybuild(Par par) RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); RUNSTEP(par, pkinsert, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkupdateindexbuild, MT); RUNSTEP(par, invalidateindex, MT); RUNSTEP(par, readverify, ST); @@ -3013,7 +3146,7 @@ ttimebuild(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkinsert, MT); t1.on(); RUNSTEP(par, createindex, ST); @@ -3032,7 +3165,7 @@ ttimemaint(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkinsert, MT); t1.on(); RUNSTEP(par, pkupdate, MT); @@ -3057,7 +3190,7 @@ ttimescan(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkinsert, MT); RUNSTEP(par, createindex, ST); par.m_tmr = &t1; @@ -3079,7 +3212,7 @@ ttimepkread(Par par) RUNSTEP(par, droptable, ST); RUNSTEP(par, createtable, ST); RUNSTEP(par, invalidatetable, MT); - for (unsigned i = 0; i < par.m_subloop; i++) { + for (par.m_slno = 0; par.m_slno < par.m_subloop; par.m_slno++) { RUNSTEP(par, pkinsert, MT); RUNSTEP(par, createindex, ST); par.m_tmr = &t1; @@ -3115,9 +3248,10 @@ struct TCase { static const TCase tcaselist[] = { TCase("a", tbuild, "index build"), - TCase("b", tpkops, "pk operations and scan reads"), - TCase("c", tmixedops, "pk operations and scan operations"), - TCase("d", tbusybuild, "pk operations and index build"), + TCase("b", tpkops, "pk operations"), + TCase("c", tpkopsread, "pk operations and scan reads"), + TCase("d", tmixedops, "pk operations and scan operations"), + TCase("e", tbusybuild, "pk operations and index build"), TCase("t", ttimebuild, "time index build"), TCase("u", ttimemaint, "time index maintenance"), TCase("v", ttimescan, "time full scan table vs index on pk"), @@ -3175,10 +3309,10 @@ runtest(Par par) Thr& thr = *g_thrlist[n]; assert(thr.m_thread != 0); } - for (unsigned l = 0; par.m_loop == 0 || l < par.m_loop; l++) { - LL1("loop " << l); + for (par.m_lno = 0; par.m_loop == 0 || par.m_lno < par.m_loop; par.m_lno++) { + LL1("loop " << par.m_lno); if (par.m_seed == 0) - srandom(l); + srandom(par.m_lno); for (unsigned i = 0; i < tcasecount; i++) { const TCase& tcase = tcaselist[i]; if (par.m_case != 0 && strchr(par.m_case, tcase.m_name[0]) == 0) @@ -3252,6 +3386,12 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) continue; } } + if (strcmp(arg, "-die") == 0) { + if (++argv, --argc > 0) { + g_opt.m_die = atoi(argv[0]); + continue; + } + } if (strcmp(arg, "-dups") == 0) { g_opt.m_dups = true; continue; @@ -3292,6 +3432,10 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) g_opt.m_nologging = true; continue; } + if (strcmp(arg, "-noverify") == 0) { + g_opt.m_noverify = true; + continue; + } if (strcmp(arg, "-pctnull") == 0) { if (++argv, --argc > 0) { g_opt.m_pctnull = atoi(argv[0]); @@ -3310,15 +3454,15 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) continue; } } - if (strcmp(arg, "-scanrd") == 0) { + if (strcmp(arg, "-scanbat") == 0) { if (++argv, --argc > 0) { - g_opt.m_scanrd = atoi(argv[0]); + g_opt.m_scanbat = atoi(argv[0]); continue; } } - if (strcmp(arg, "-scanex") == 0) { + if (strcmp(arg, "-scanpar") == 0) { if (++argv, --argc > 0) { - g_opt.m_scanex = atoi(argv[0]); + g_opt.m_scanpar = atoi(argv[0]); continue; } } diff --git a/ndb/test/ndbapi/testOperations.cpp b/ndb/test/ndbapi/testOperations.cpp index ba41e1d1c40..f31906dd737 100644 --- a/ndb/test/ndbapi/testOperations.cpp +++ b/ndb/test/ndbapi/testOperations.cpp @@ -86,7 +86,7 @@ OperationTestCase matrix[] = { { "DeleteRead", true, "DELETE", 0, 0, "READ", 626, 0, 0, 0 }, { "DeleteReadEx", true, "DELETE", 0, 0, "READ-EX", 626, 0, 0, 0 }, { "DeleteSimpleRead", true, "DELETE", 0, 0, "S-READ", 626, 0, 0, 0 }, - { "DeleteDirtyRead", true, "DELETE", 0, 0, "D-READ", 626, 0, 0, 0 }, + { "DeleteDirtyRead", true, "DELETE", 0, 0, "D-READ", 626, 0, 626, 0 }, { "DeleteInsert", true, "DELETE", 0, 0, "INSERT", 0, 1, 0, 1 }, { "DeleteUpdate", true, "DELETE", 0, 0, "UPDATE", 626, 1, 0, 0 }, { "DeleteDelete", true, "DELETE", 0, 0, "DELETE", 626, 0, 0, 0 } @@ -110,13 +110,13 @@ runOp(HugoOperations & hugoOps, return NDBT_FAILED; }} if(strcmp(op, "READ") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, false, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0); } else if(strcmp(op, "READ-EX") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, true, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive), 0); } else if(strcmp(op, "S-READ") == 0){ - C2(hugoOps.pkSimpleReadRecord(pNdb, 1, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read), 0); } else if(strcmp(op, "D-READ") == 0){ - C2(hugoOps.pkDirtyReadRecord(pNdb, 1, 1), 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead), 0); } else if(strcmp(op, "INSERT") == 0){ C2(hugoOps.pkInsertRecord(pNdb, 1, 1, value), 0); } else if(strcmp(op, "UPDATE") == 0){ diff --git a/ndb/test/ndbapi/testReadPerf.cpp b/ndb/test/ndbapi/testReadPerf.cpp index 7cf3755d66f..8d0d78cbe8c 100644 --- a/ndb/test/ndbapi/testReadPerf.cpp +++ b/ndb/test/ndbapi/testReadPerf.cpp @@ -130,9 +130,9 @@ main(int argc, const char** argv){ for(int i = optind; i<argc; i++){ const char * T = argv[i]; g_info << "Testing " << T << endl; - snprintf(g_table, sizeof(g_table), T); - snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T); - snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T); + BaseString::snprintf(g_table, sizeof(g_table), T); + BaseString::snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T); + BaseString::snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T); if(create_table()) goto error; if(load_table()) diff --git a/ndb/test/ndbapi/testRestartGci.cpp b/ndb/test/ndbapi/testRestartGci.cpp index 4cdfca29e6f..e817245af55 100644 --- a/ndb/test/ndbapi/testRestartGci.cpp +++ b/ndb/test/ndbapi/testRestartGci.cpp @@ -63,7 +63,7 @@ int runInsertRememberGci(NDBT_Context* ctx, NDBT_Step* step){ result = NDBT_FAILED; break; } - CHECK(hugoOps.pkReadRecord(pNdb, i, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i) == 0); if (hugoOps.execute_Commit(pNdb) != 0){ ndbout << "Did not find record in DB " << i << endl; result = NDBT_FAILED; @@ -146,7 +146,7 @@ int runVerifyInserts(NDBT_Context* ctx, NDBT_Step* step){ // gci as in the vector for (unsigned i = 0; i < savedRecords.size(); i++){ CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, i, false) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, i) == 0); if (hugoOps.execute_Commit(pNdb) != 0){ // Record was not found in db' diff --git a/ndb/test/ndbapi/testScanInterpreter.cpp b/ndb/test/ndbapi/testScanInterpreter.cpp index 3a5ef22b613..5a7ca30cd2a 100644 --- a/ndb/test/ndbapi/testScanInterpreter.cpp +++ b/ndb/test/ndbapi/testScanInterpreter.cpp @@ -90,7 +90,7 @@ int runCreateResultTable(NDBT_Context* ctx, NDBT_Step* step){ const NdbDictionary::Table* pTab = ctx->getTab(); char newTabName[256]; - snprintf(newTabName, 256, "%s_RES", pTab->getName()); + BaseString::snprintf(newTabName, 256, "%s_RES", pTab->getName()); ctx->setProperty("ResultTabName", newTabName); NdbDictionary::Table resTab(* pTab); diff --git a/ndb/test/ndbapi/testScanPerf.cpp b/ndb/test/ndbapi/testScanPerf.cpp index 8c1a41047ca..c1334125978 100644 --- a/ndb/test/ndbapi/testScanPerf.cpp +++ b/ndb/test/ndbapi/testScanPerf.cpp @@ -110,8 +110,8 @@ main(int argc, const char** argv){ for(int i = optind; i<argc; i++){ const char * T = argv[i]; g_info << "Testing " << T << endl; - snprintf(g_tablename, sizeof(g_tablename), T); - snprintf(g_indexname, sizeof(g_indexname), "IDX_%s", T); + BaseString::snprintf(g_tablename, sizeof(g_tablename), T); + BaseString::snprintf(g_indexname, sizeof(g_indexname), "IDX_%s", T); if(create_table()) goto error; if(load_table()) diff --git a/ndb/test/ndbapi/testTimeout.cpp b/ndb/test/ndbapi/testTimeout.cpp index 5cabb86541d..e310e12df81 100644 --- a/ndb/test/ndbapi/testTimeout.cpp +++ b/ndb/test/ndbapi/testTimeout.cpp @@ -108,7 +108,7 @@ int runTimeoutTrans(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, stepNo, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, stepNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); int sleep = minSleep + myRandom48(maxSleep-minSleep); @@ -162,25 +162,25 @@ int runTimeoutTrans2(NDBT_Context* ctx, NDBT_Step* step){ case 0: break; case 1: - if(hugoOps.pkReadRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkReadRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 2: - if(hugoOps.pkUpdateRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkUpdateRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 3: - if(hugoOps.pkDeleteRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkDeleteRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 4: - if(hugoOps.pkInsertRecord(pNdb, stepNo+records+l, true) != 0){ + if(hugoOps.pkInsertRecord(pNdb, stepNo+records+l) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } @@ -204,25 +204,25 @@ int runTimeoutTrans2(NDBT_Context* ctx, NDBT_Step* step){ case 0: break; case 1: - if(hugoOps.pkReadRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkReadRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 2: - if(hugoOps.pkUpdateRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkUpdateRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 3: - if(hugoOps.pkDeleteRecord(pNdb, stepNo, true) != 0){ + if(hugoOps.pkDeleteRecord(pNdb, stepNo) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } break; case 4: - if(hugoOps.pkInsertRecord(pNdb, stepNo+2*records+l, true) != 0){ + if(hugoOps.pkInsertRecord(pNdb, stepNo+2*records+l) != 0){ g_err << stepNo << ": Fail" << __LINE__ << endl; result = NDBT_FAILED; break; } @@ -263,7 +263,7 @@ int runDontTimeoutTrans(NDBT_Context* ctx, NDBT_Step* step){ do{ // Commit transaction CHECK(hugoOps.startTransaction(pNdb) == 0); - CHECK(hugoOps.pkReadRecord(pNdb, stepNo, true) == 0); + CHECK(hugoOps.pkReadRecord(pNdb, stepNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); int sleep = myRandom48(maxSleep); @@ -299,7 +299,7 @@ int runBuddyTransNoTimeout(NDBT_Context* ctx, NDBT_Step* step){ // Start an insert trans CHECK(hugoOps.startTransaction(pNdb) == 0); int recordNo = records + (stepNo*loops) + l; - CHECK(hugoOps.pkInsertRecord(pNdb, recordNo, true) == 0); + CHECK(hugoOps.pkInsertRecord(pNdb, recordNo) == 0); CHECK(hugoOps.execute_NoCommit(pNdb) == 0); for (int i = 0; i < 3; i++){ diff --git a/ndb/test/ndbapi/testTransactions.cpp b/ndb/test/ndbapi/testTransactions.cpp index 2dca9e24fb4..46be808d8a5 100644 --- a/ndb/test/ndbapi/testTransactions.cpp +++ b/ndb/test/ndbapi/testTransactions.cpp @@ -190,13 +190,13 @@ runOp(HugoOperations & hugoOps, return NDBT_FAILED; } if(strcmp(op, "READ") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, false, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } else if(strcmp(op, "READ-EX") == 0){ - C2(hugoOps.pkReadRecord(pNdb, 1, true, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Exclusive) == 0); } else if(strcmp(op, "S-READ") == 0){ - C2(hugoOps.pkSimpleReadRecord(pNdb, 1, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_Read) == 0); } else if(strcmp(op, "D-READ") == 0){ - C2(hugoOps.pkDirtyReadRecord(pNdb, 1, 1) == 0); + C2(hugoOps.pkReadRecord(pNdb, 1, 1, NdbOperation::LM_CommittedRead) == 0); } else if(strcmp(op, "INSERT") == 0){ C2(hugoOps.pkInsertRecord(pNdb, 1, 1, value) == 0); } else if(strcmp(op, "UPDATE") == 0){ diff --git a/ndb/test/ndbapi/userInterface.cpp b/ndb/test/ndbapi/userInterface.cpp index fdbc229cc98..2f77c0f4857 100644 --- a/ndb/test/ndbapi/userInterface.cpp +++ b/ndb/test/ndbapi/userInterface.cpp @@ -103,7 +103,7 @@ void showTime() now = ::time((time_t*)NULL); tm_now = ::gmtime(&now); - ::snprintf(buf, 128, + BaseString::snprintf(buf, 128, "%d-%.2d-%.2d %.2d:%.2d:%.2d", tm_now->tm_year + 1900, tm_now->tm_mon, diff --git a/ndb/test/run-test/daily-devel-tests.txt b/ndb/test/run-test/daily-devel-tests.txt index f2abc961807..5c0b2821d85 100644 --- a/ndb/test/run-test/daily-devel-tests.txt +++ b/ndb/test/run-test/daily-devel-tests.txt @@ -52,26 +52,30 @@ args: -n SR4 T6 # max-time: 1500 cmd: testSystemRestart -args: -n SR_FULLDB T1 +args: -n SR_FULLDB T6 # # NODE RESTARTS # max-time: 2500 cmd: testNodeRestart -args: -n NoLoad T6 T8 T13 +args: -n NoLoad T6 max-time: 2500 cmd: testNodeRestart -args: -n PkRead T6 T8 T13 +args: -n MixedPkRead T6 T8 T13 max-time: 2500 cmd: testNodeRestart -args: -l 1 -n PkReadPkUpdate +args: -l 1 -n MixedPkReadPkUpdate max-time: 2500 cmd: testNodeRestart -args: -l 1 -n ReadUpdateScan +args: -l 1 -n MixedReadUpdateScan + +max-time: 2500 +cmd: testNodeRestart +args: -n CommittedRead T1 max-time: 2500 cmd: testNodeRestart @@ -186,10 +190,6 @@ max-time: 2500 cmd: testDict args: -n NF1 T1 T6 T13 -max-time: 2500 -cmd: test_event -args: -n BasicEventOperation T1 T6 - # max-time: 1500 cmd: testSystemRestart @@ -206,3 +206,9 @@ args: -l 1 -n SR8 T1 max-time: 1500 cmd: testSystemRestart args: -l 1 -n SR9 T1 + +# +max-time: 2500 +cmd: test_event +args: -n BasicEventOperation T1 T6 + diff --git a/ndb/test/src/HugoCalculator.cpp b/ndb/test/src/HugoCalculator.cpp index 147c8b104d8..62c35c54a7a 100644 --- a/ndb/test/src/HugoCalculator.cpp +++ b/ndb/test/src/HugoCalculator.cpp @@ -96,7 +96,7 @@ HugoCalculator::calcValue(int record, // of the string, then fill with other chars // The string length is set to the same size as the attribute len = attr->getLength(); - snprintf(buf, len, "%d", val); + BaseString::snprintf(buf, len, "%d", val); for(int i=strlen(buf); i < len; i++) buf[i] = a[((val^i)%25)]; } else{ diff --git a/ndb/test/src/HugoOperations.cpp b/ndb/test/src/HugoOperations.cpp index 7c05cb86a93..e8e2d992345 100644 --- a/ndb/test/src/HugoOperations.cpp +++ b/ndb/test/src/HugoOperations.cpp @@ -52,8 +52,8 @@ NdbConnection* HugoOperations::getTransaction(){ int HugoOperations::pkReadRecord(Ndb* pNdb, int recordNo, - bool exclusive, - int numRecords){ + int numRecords, + NdbOperation::LockMode lm){ int a; allocRows(numRecords); int check; @@ -64,94 +64,22 @@ int HugoOperations::pkReadRecord(Ndb* pNdb, return NDBT_FAILED; } - if (exclusive == true) - check = pOp->readTupleExclusive(); - else +rand_lock_mode: + switch(lm){ + case NdbOperation::LM_Read: check = pOp->readTuple(); - if( check == -1 ) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - // Define primary keys - for(a = 0; a<tab.getNoOfColumns(); a++){ - if (tab.getColumn(a)->getPrimaryKey() == true){ - if(equalForAttr(pOp, a, r+recordNo) != 0){ - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - - // Define attributes to read - for(a = 0; a<tab.getNoOfColumns(); a++){ - if((rows[r]->attributeStore(a) = - pOp->getValue(tab.getColumn(a)->getName())) == 0) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - return NDBT_OK; -} - -int HugoOperations::pkDirtyReadRecord(Ndb* pNdb, - int recordNo, - int numRecords){ - int a; - allocRows(numRecords); - int check; - for(int r=0; r < numRecords; r++){ - NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); - if (pOp == NULL) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - check = pOp->dirtyRead(); - - if( check == -1 ) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - - // Define primary keys - for(a = 0; a<tab.getNoOfColumns(); a++){ - if (tab.getColumn(a)->getPrimaryKey() == true){ - if(equalForAttr(pOp, a, r+recordNo) != 0){ - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - - // Define attributes to read - for(a = 0; a<tab.getNoOfColumns(); a++){ - if((rows[r]->attributeStore(a) = - pOp->getValue(tab.getColumn(a)->getName())) == 0) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; - } - } - } - return NDBT_OK; -} - -int HugoOperations::pkSimpleReadRecord(Ndb* pNdb, - int recordNo, - int numRecords){ - int a; - allocRows(numRecords); - int check; - for(int r=0; r < numRecords; r++){ - NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); - if (pOp == NULL) { - ERR(pTrans->getNdbError()); - return NDBT_FAILED; + break; + case NdbOperation::LM_Exclusive: + check = pOp->readTupleExclusive(); + break; + case NdbOperation::LM_CommittedRead: + check = pOp->dirtyRead(); + break; + default: + lm = (NdbOperation::LockMode)((rand() >> 16) & 3); + goto rand_lock_mode; } - check = pOp->simpleRead(); - if( check == -1 ) { ERR(pTrans->getNdbError()); return NDBT_FAILED; diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp index 994a45de3dc..456bfffbb77 100644 --- a/ndb/test/src/HugoTransactions.cpp +++ b/ndb/test/src/HugoTransactions.cpp @@ -1230,7 +1230,7 @@ int HugoTransactions::pkReadRecords(Ndb* pNdb, int records, int batchsize, - bool dirty){ + NdbOperation::LockMode lm){ int reads = 0; int r = 0; int retryAttempt = 0; @@ -1275,11 +1275,22 @@ HugoTransactions::pkReadRecords(Ndb* pNdb, return NDBT_FAILED; } - if (dirty == true){ - check = pOp->dirtyRead(); - } else { + rand_lock_mode: + switch(lm){ + case NdbOperation::LM_Read: check = pOp->readTuple(); + break; + case NdbOperation::LM_Exclusive: + check = pOp->readTupleExclusive(); + break; + case NdbOperation::LM_CommittedRead: + check = pOp->dirtyRead(); + break; + default: + lm = (NdbOperation::LockMode)((rand() >> 16) & 3); + goto rand_lock_mode; } + if( check == -1 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); diff --git a/ndb/test/src/NDBT_ResultRow.cpp b/ndb/test/src/NDBT_ResultRow.cpp index 7c419444760..f82963901b1 100644 --- a/ndb/test/src/NDBT_ResultRow.cpp +++ b/ndb/test/src/NDBT_ResultRow.cpp @@ -58,10 +58,14 @@ NDBT_ResultRow::attributeStore(int i){ return data[i]; } +const NdbRecAttr* +NDBT_ResultRow::attributeStore(int i) const { + return data[i]; +} const NdbRecAttr * -NDBT_ResultRow::attributeStore(const char* name){ +NDBT_ResultRow::attributeStore(const char* name) const { for(int i = 0; i<cols; i++){ if (strcmp(names[i], name) == 0) return data[i]; diff --git a/ndb/test/src/NDBT_Table.cpp b/ndb/test/src/NDBT_Table.cpp index d283cdf5912..8d398b75d81 100644 --- a/ndb/test/src/NDBT_Table.cpp +++ b/ndb/test/src/NDBT_Table.cpp @@ -24,7 +24,7 @@ operator <<(class NdbOut& ndbout, const NDBT_Table & tab) ndbout << "-- " << tab.getName() << " --" << endl; ndbout << "Version: " << tab.getObjectVersion() << endl; - ndbout << "Fragment type: " << tab.getFragmentType() << endl; + ndbout << "Fragment type: " << (unsigned) tab.getFragmentType() << endl; ndbout << "K Value: " << tab.getKValue()<< endl; ndbout << "Min load factor: " << tab.getMinLoadFactor()<< endl; ndbout << "Max load factor: " << tab.getMaxLoadFactor()<< endl; @@ -47,7 +47,7 @@ operator <<(class NdbOut& ndbout, const NDBT_Table & tab) ndbout << "Retrieved" << endl; break; default: - ndbout << "Unknown(" << tab.getObjectStatus() << ")" << endl; + ndbout << "Unknown(" << (unsigned) tab.getObjectStatus() << ")" << endl; } ndbout << "-- Attributes -- " << endl; @@ -81,7 +81,7 @@ class NdbOut& operator <<(class NdbOut&, const NdbDictionary::Index & idx) ndbout << "OrderedIndex"; break; default: - ndbout << "Type " << idx.getType(); + ndbout << "Type " << (unsigned) idx.getType(); break; } return ndbout; diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 4ff94bcf296..367223f8c98 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -484,7 +484,7 @@ void NDBT_TestCaseImpl1::startStepInThread(int stepNo, NDBT_Context* ctx){ NDBT_Step* pStep = steps[stepNo]; pStep->setContext(ctx); char buf[16]; - snprintf(buf, sizeof(buf), "step_%d", stepNo); + BaseString::snprintf(buf, sizeof(buf), "step_%d", stepNo); NdbThread* pThread = NdbThread_Create(runStep_C, (void**)pStep, 65535, @@ -704,7 +704,7 @@ void NDBT_TestCaseImpl1::printTestResult(){ res = "FAILED TO CREATE TABLE"; else if (tcr->getResult() == FAILED_TO_DISCOVER) res = "FAILED TO DISCOVER TABLE"; - snprintf(buf, 255," %-10s %-5s %-20s", tcr->getName(), res, tcr->getTimeStr()); + BaseString::snprintf(buf, 255," %-10s %-5s %-20s", tcr->getName(), res, tcr->getTimeStr()); ndbout << buf<<endl; } } @@ -1078,7 +1078,7 @@ const char* NDBT_TestSuite::getDate(){ tm_now = gmtime(&now); #endif - snprintf(theTime, 128, + BaseString::snprintf(theTime, 128, "%d-%.2d-%.2d %.2d:%.2d:%.2d", tm_now->tm_year + 1900, tm_now->tm_mon + 1, @@ -1150,6 +1150,20 @@ void NDBT_Step::print(){ } +void +NDBT_Context::sync_down(const char * key){ + Uint32 threads = getProperty(key, (unsigned)0); + if(threads){ + decProperty(key); + } +} + +void +NDBT_Context::sync_up_and_wait(const char * key, Uint32 value){ + setProperty(key, value); + getPropertyWait(key, (unsigned)0); +} + template class Vector<NDBT_TestCase*>; template class Vector<NDBT_TestCaseResult*>; template class Vector<NDBT_Step*>; diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index ad26dbeab16..1ce48d495a5 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -143,7 +143,7 @@ NdbBackup::execRestore(bool _restore_data, * Copy backup files to local dir */ - snprintf(buf, buf_len, + BaseString::snprintf(buf, buf_len, "scp %s:%s/BACKUP/BACKUP-%d/BACKUP-%d*.%d.* .", host, path, _backup_id, @@ -155,7 +155,7 @@ NdbBackup::execRestore(bool _restore_data, ndbout << "scp res: " << res << endl; - snprintf(buf, 255, "%sndb_restore -c \"host=%s\" -n %d -b %d %s %s .", + BaseString::snprintf(buf, 255, "%sndb_restore -c \"host=%s\" -n %d -b %d %s %s .", #if 1 "", #else diff --git a/ndb/test/src/NdbGrep.cpp b/ndb/test/src/NdbGrep.cpp index 8b7442b0e77..6c0c9cabfcb 100644 --- a/ndb/test/src/NdbGrep.cpp +++ b/ndb/test/src/NdbGrep.cpp @@ -60,10 +60,10 @@ NdbGrep::verify(NDBT_Context * ctx){ return -1; char cheat_table[255]; - snprintf(cheat_table, 255, "TEST_DB/def/%s",ctx->getTab()->getName()); + BaseString::snprintf(cheat_table, 255, "TEST_DB/def/%s",ctx->getTab()->getName()); char buf[255]; - snprintf(buf, 255, "testGrepVerify -c \"nodeid=%d;host=%s\" -t %s -r %d", + BaseString::snprintf(buf, 255, "testGrepVerify -c \"nodeid=%d;host=%s\" -t %s -r %d", 4, //cheat. Hardcoded nodeid.... ctx->getRemoteMgm(), cheat_table, diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index 506356dd140..c0e6effd244 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -383,11 +383,20 @@ UtilTransactions::clearTable3(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { + err = pTrans->getNdbError(); + if(err.status == NdbError::TemporaryError){ + ERR(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + par = 1; + goto restart; + } goto failed; } NdbResultSet * rs = pOp->readTuplesExclusive(par); if( rs == 0 ) { + err = pTrans->getNdbError(); goto failed; } @@ -647,8 +656,16 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { - ERR(pTrans->getNdbError()); + const NdbError err = pNdb->getNdbError(); pNdb->closeTransaction(pTrans); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); return NDBT_FAILED; } @@ -854,11 +871,12 @@ UtilTransactions::verifyIndex(Ndb* pNdb, ndbout << " Index " << indexName << " does not exist!" << endl; return NDBT_FAILED; } - + switch (pIndex->getType()){ case NdbDictionary::Index::UniqueHashIndex: + return verifyUniqueIndex(pNdb, pIndex, parallelism, transactional); case NdbDictionary::Index::OrderedIndex: - return verifyUniqueIndex(pNdb, indexName, parallelism, transactional); + return verifyOrderedIndex(pNdb, pIndex, parallelism, transactional); break; default: ndbout << "Unknown index type" << endl; @@ -870,7 +888,7 @@ UtilTransactions::verifyIndex(Ndb* pNdb, int UtilTransactions::verifyUniqueIndex(Ndb* pNdb, - const char* indexName, + const NdbDictionary::Index * pIndex, int parallelism, bool transactional){ @@ -882,7 +900,7 @@ UtilTransactions::verifyUniqueIndex(Ndb* pNdb, */ if (scanAndCompareUniqueIndex(pNdb, - indexName, + pIndex, parallelism, transactional) != NDBT_OK){ return NDBT_FAILED; @@ -896,7 +914,7 @@ UtilTransactions::verifyUniqueIndex(Ndb* pNdb, int UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb, - const char * indexName, + const NdbDictionary::Index* pIndex, int parallelism, bool transactional){ @@ -933,8 +951,15 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { - ERR(pTrans->getNdbError()); + const NdbError err = pNdb->getNdbError(); pNdb->closeTransaction(pTrans); + ERR(err); + + if (err.status == NdbError::TemporaryError){ + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } return NDBT_FAILED; } @@ -996,7 +1021,7 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb, if (readRowFromTableAndIndex(pNdb, pTrans, - indexName, + pIndex, row) != NDBT_OK){ pNdb->closeTransaction(pTrans); return NDBT_FAILED; @@ -1027,15 +1052,9 @@ UtilTransactions::scanAndCompareUniqueIndex(Ndb* pNdb, int UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb, NdbConnection* scanTrans, - const char * indexName, + const NdbDictionary::Index* pIndex, NDBT_ResultRow& row ){ - const NdbDictionary::Index* pIndex - = pNdb->getDictionary()->getIndex(indexName, tab.getName()); - if (pIndex == 0){ - ndbout << " Index " << indexName << " does not exist!" << endl; - return NDBT_FAILED; - } NdbDictionary::Index::Type indexType= pIndex->getType(); int retryAttempt = 0; @@ -1050,7 +1069,7 @@ UtilTransactions::readRowFromTableAndIndex(Ndb* pNdb, // Allocate place to store the result NDBT_ResultRow tabRow(tab); NDBT_ResultRow indexRow(tab); - + const char * indexName = pIndex->getName(); while (true){ if(retryAttempt) @@ -1281,3 +1300,239 @@ close_all: return return_code; } + +int +UtilTransactions::verifyOrderedIndex(Ndb* pNdb, + const NdbDictionary::Index* pIndex, + int parallelism, + bool transactional){ + + int retryAttempt = 0; + const int retryMax = 100; + int check; + NdbConnection *pTrans; + NdbScanOperation *pOp; + NdbIndexScanOperation * iop = 0; + NdbResultSet* cursor= 0; + + NDBT_ResultRow scanRow(tab); + NDBT_ResultRow pkRow(tab); + NDBT_ResultRow indexRow(tab); + const char * indexName = pIndex->getName(); + + int res; + parallelism = 1; + + while (true){ + + if (retryAttempt >= retryMax){ + g_info << "ERROR: has retried this operation " << retryAttempt + << " times, failing!" << endl; + return NDBT_FAILED; + } + + pTrans = pNdb->startTransaction(); + if (pTrans == NULL) { + const NdbError err = pNdb->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + return NDBT_FAILED; + } + + pOp = pTrans->getNdbScanOperation(tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + NdbResultSet* + rs = pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism); + + if( rs == 0 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + check = pOp->interpret_exit_ok(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if(get_values(pOp, scanRow)) + { + abort(); + } + + check = pTrans->execute(NoCommit); + if( check == -1 ) { + const NdbError err = pTrans->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + int eof; + int rows = 0; + while(check == 0 && (eof = rs->nextResult()) == 0){ + rows++; + + bool null_found= false; + for(int a = 0; a<(int)pIndex->getNoOfColumns(); a++){ + const NdbDictionary::Column * col = pIndex->getColumn(a); + if (scanRow.attributeStore(col->getName())->isNULL()) + { + null_found= true; + break; + } + } + + // Do pk lookup + NdbOperation * pk = pTrans->getNdbOperation(tab.getName()); + if(!pk || pk->readTuple()) + goto error; + if(equal(&tab, pk, scanRow) || get_values(pk, pkRow)) + goto error; + + if(!null_found) + { + if(!iop && (iop= pTrans->getNdbIndexScanOperation(indexName, + tab.getName()))) + { + cursor= iop->readTuples(NdbScanOperation::LM_CommittedRead, + parallelism); + iop->interpret_exit_ok(); + if(!cursor || get_values(iop, indexRow)) + goto error; + } + else if(!iop || iop->reset_bounds()) + { + goto error; + } + + if(equal(pIndex, iop, scanRow)) + goto error; + } + + check = pTrans->execute(NoCommit); + if(check) + goto error; + + if(scanRow.c_str() != pkRow.c_str()){ + g_err << "Error when comapring records" << endl; + g_err << " scanRow: \n" << scanRow.c_str().c_str() << endl; + g_err << " pkRow: \n" << pkRow.c_str().c_str() << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if(!null_found) + { + + if((res= cursor->nextResult()) != 0){ + g_err << "Failed to find row using index: " << res << endl; + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if(scanRow.c_str() != indexRow.c_str()){ + g_err << "Error when comapring records" << endl; + g_err << " scanRow: \n" << scanRow.c_str().c_str() << endl; + g_err << " indexRow: \n" << indexRow.c_str().c_str() << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if(cursor->nextResult() == 0){ + g_err << "Found extra row!!" << endl; + g_err << " indexRow: \n" << indexRow.c_str().c_str() << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + } + + if (eof == -1 || check == -1) { + error: + const NdbError err = pTrans->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + iop = 0; + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + retryAttempt++; + rows--; + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + + return NDBT_OK; + } + return NDBT_FAILED; +} + +int +UtilTransactions::get_values(NdbOperation* op, NDBT_ResultRow& dst) +{ + for (int a = 0; a < tab.getNoOfColumns(); a++){ + NdbRecAttr*& ref= dst.attributeStore(a); + if ((ref= op->getValue(a)) == 0) + { + return NDBT_FAILED; + } + } + return 0; +} + +int +UtilTransactions::equal(const NdbDictionary::Index* pIndex, + NdbOperation* op, const NDBT_ResultRow& src) +{ + for(Uint32 a = 0; a<pIndex->getNoOfColumns(); a++){ + const NdbDictionary::Column * col = pIndex->getColumn(a); + if(op->equal(col->getName(), + src.attributeStore(col->getName())->aRef()) != 0){ + return NDBT_FAILED; + } + } + return 0; +} + +int +UtilTransactions::equal(const NdbDictionary::Table* pTable, + NdbOperation* op, const NDBT_ResultRow& src) +{ + for(Uint32 a = 0; a<tab.getNoOfColumns(); a++){ + const NdbDictionary::Column* attr = tab.getColumn(a); + if (attr->getPrimaryKey() == true){ + if (op->equal(attr->getName(), src.attributeStore(a)->aRef()) != 0){ + return NDBT_FAILED; + } + } + } + return 0; +} diff --git a/ndb/test/tools/transproxy.cpp b/ndb/test/tools/transproxy.cpp index 90e216ec785..88267801172 100644 --- a/ndb/test/tools/transproxy.cpp +++ b/ndb/test/tools/transproxy.cpp @@ -32,7 +32,7 @@ fatal(char const* fmt, ...) va_list ap; char buf[200]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << "FATAL: " << buf << endl; sleep(1); @@ -45,7 +45,7 @@ debug(char const* fmt, ...) va_list ap; char buf[200]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << buf << endl; } diff --git a/ndb/tools/listTables.cpp b/ndb/tools/listTables.cpp index 4b24929ee4b..4fc5bcd7f21 100644 --- a/ndb/tools/listTables.cpp +++ b/ndb/tools/listTables.cpp @@ -38,7 +38,7 @@ fatal(char const* fmt, ...) va_list ap; char buf[500]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << buf; if (ndb) @@ -54,7 +54,7 @@ fatal_dict(char const* fmt, ...) va_list ap; char buf[500]; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + BaseString::vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << buf; if (dic) diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp index c27b46c9356..c01a3f9192e 100644 --- a/ndb/tools/waiter.cpp +++ b/ndb/tools/waiter.cpp @@ -15,8 +15,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <ndb_global.h> #include <mgmapi.h> -#include <string.h> #include <NdbMain.h> #include <NdbOut.hpp> #include <NdbSleep.h> @@ -68,7 +68,7 @@ int main(int argc, const char** argv){ return NDBT_ProgramExit(NDBT_FAILED); } - for (int i = 0; i<lcfg.ids.size();i++) + for (unsigned i = 0; i<lcfg.ids.size();i++) { MgmtSrvrId * m = &lcfg.ids[i]; @@ -292,8 +292,8 @@ waitClusterStatus(const char* _addr, if (ndbNode->node_status < _status) allInState = false; else - g_info << "node_status(" << ndbNode->node_status - <<") != _status("<<_status<<")"<<endl; + g_info << "node_status(" << (unsigned)ndbNode->node_status + << ") != _status("<< (unsigned)_status << ")" <<endl; } else if (ndbNode->start_phase < _startphase) allInState = false; } else { diff --git a/regex/regcomp.c b/regex/regcomp.c index 31899609e3c..5f0351c32aa 100644 --- a/regex/regcomp.c +++ b/regex/regcomp.c @@ -1183,6 +1183,7 @@ register cset *cs; return(n); } +#ifdef USE_ORIG_REGEX_CODE /* - mcadd - add a collating element to a cset == static void mcadd(register struct parse *p, register cset *cs, \ @@ -1209,6 +1210,7 @@ register char *cp; (void) strcpy(cs->multis + oldend - 1, cp); cs->multis[cs->smultis - 1] = '\0'; } +#endif #ifdef NOT_USED /* diff --git a/regex/regcomp.ih b/regex/regcomp.ih index 32f1f6e89eb..5deba89217a 100644 --- a/regex/regcomp.ih +++ b/regex/regcomp.ih @@ -27,7 +27,9 @@ static void freeset(register struct parse *p, register cset *cs); static int freezeset(register struct parse *p, register cset *cs); static int firstch(register struct parse *p, register cset *cs); static int nch(register struct parse *p, register cset *cs); +#ifdef USE_ORIG_REGEX_CODE static void mcadd(register struct parse *p, register cset *cs, register char *cp); +#endif #ifdef NOT_USED static void mcsub(register cset *cs, register char *cp); static int mcin(register cset *cs, register char *cp); diff --git a/scripts/Makefile.am b/scripts/Makefile.am index d4da77d0387..4158b5a34dc 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -139,6 +139,7 @@ SUFFIXES = .sh -e 's!@''IS_LINUX''@!@IS_LINUX@!' \ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ + -e "s!@MAKE@!$(MAKE)!" \ $< > $@-t @CHMOD@ +x $@-t @MV@ $@-t $@ diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 9af7913999f..281ef9bd469 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -267,8 +267,8 @@ fi # NDB Cluster if [ x$NDBCLUSTER = x1 ]; then - ( cd ndb ; make DESTDIR=$BASE/ndb-stage install ) - ( cd mysql-test/ndb ; make DESTDIR=$BASE/ndb-stage install ) + ( cd ndb ; @MAKE@ DESTDIR=$BASE/ndb-stage install ) + ( cd mysql-test/ndb ; @MAKE@ DESTDIR=$BASE/ndb-stage install ) $CP $BASE/ndb-stage@bindir@/* $BASE/bin/. $CP $BASE/ndb-stage@libexecdir@/* $BASE/bin/. $CP $BASE/ndb-stage@pkglibdir@/* $BASE/lib/. diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index b8494727975..2cfe91da115 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -8,7 +8,7 @@ use File::Path; use DBI; use Sys::Hostname; use File::Copy; -use File::Temp; +use File::Temp qw(tempfile); =head1 NAME @@ -39,7 +39,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.21"; +my $VERSION = "1.22"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -655,8 +655,8 @@ sub copy_index } elsif ($opt{method} =~ /^scp\b/) { - my ($fh, $tmp)=tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir); - die "Can\'t create/open file in $opt_tmpdir\n"; + my ($fh, $tmp)= tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir) or + die "Can\'t create/open file in $opt_tmpdir\n"; if (syswrite($fh,$buff) != length($buff)) { die "Error when writing data to $tmp: $!\n"; diff --git a/sql-common/client.c b/sql-common/client.c index 43e116eb0b6..9fca38f3857 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2249,7 +2249,7 @@ static void mysql_close_free(MYSQL *mysql) stmt_list pointer to mysql->stmts */ -void mysql_detach_stmt_list(LIST **stmt_list) +void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused))) { #ifdef MYSQL_CLIENT /* Reset connection handle in all prepared statements. */ diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 4b5daf53bea..93549f7340c 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -726,3 +726,75 @@ void set_zero_time(MYSQL_TIME *tm) tm->time_type= MYSQL_TIMESTAMP_NONE; } + +/* + Functions to convert time/date/datetime value to a string, + using default format. + This functions don't check that given TIME structure members are + in valid range. If they are not, return value won't reflect any + valid date either. Additionally, make_time doesn't take into + account time->day member: it's assumed that days have been converted + to hours already. + + RETURN + number of characters written to 'to' +*/ + +int my_time_to_str(const MYSQL_TIME *l_time, char *to) +{ + return my_sprintf(to, (to, "%s%02d:%02d:%02d", + (l_time->neg ? "-" : ""), + l_time->hour, + l_time->minute, + l_time->second)); +} + +int my_date_to_str(const MYSQL_TIME *l_time, char *to) +{ + return my_sprintf(to, (to, "%04d-%02d-%02d", + l_time->year, + l_time->month, + l_time->day)); +} + +int my_datetime_to_str(const MYSQL_TIME *l_time, char *to) +{ + return my_sprintf(to, (to, "%04d-%02d-%02d %02d:%02d:%02d", + l_time->year, + l_time->month, + l_time->day, + l_time->hour, + l_time->minute, + l_time->second)); +} + + +/* + Convert struct DATE/TIME/DATETIME value to string using built-in + MySQL time conversion formats. + + SYNOPSIS + my_TIME_to_string() + + NOTE + The string must have at least MAX_DATE_STRING_REP_LENGTH bytes reserved. +*/ + +int my_TIME_to_str(const MYSQL_TIME *l_time, char *to) +{ + switch (l_time->time_type) { + case MYSQL_TIMESTAMP_DATETIME: + return my_datetime_to_str(l_time, to); + case MYSQL_TIMESTAMP_DATE: + return my_date_to_str(l_time, to); + case MYSQL_TIMESTAMP_TIME: + return my_time_to_str(l_time, to); + case MYSQL_TIMESTAMP_NONE: + case MYSQL_TIMESTAMP_ERROR: + to[0]='\0'; + return 0; + default: + DBUG_ASSERT(0); + return 0; + } +} diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index c7d08772109..6fbfb3f9f9d 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -103,14 +103,15 @@ rows - This is an unsigned long long which is the number of rows in the data file. check point - Reserved for future use - dirty - Status of the file, whether or not its values are the latest. This flag - is what causes a repair to occur + dirty - Status of the file, whether or not its values are the latest. This + flag is what causes a repair to occur The data file: check - Just an int of 254 to make sure that the the file we are opening was never corrupted. version - The current version of the file format. data - The data is stored in a "row +blobs" format. +*/ /* Variables for archive share methods */ pthread_mutex_t archive_mutex; diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index 097abd48e05..cb0780ea74d 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -263,8 +263,8 @@ int ha_example::write_row(byte * buf) clause was used. Consecutive ordering is not guarenteed. Currently new_data will not have an updated auto_increament record, or and updated timestamp field. You can do these for example by doing these: - if (table->timestamp_on_update_now) - update_timestamp(new_row+table->timestamp_on_update_now-1); + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) + table->timestamp_field->set_time(); if (table->next_number_field && record == table->record[0]) update_auto_increment(); diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 06a19e478ae..0345a170c3c 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -428,8 +428,8 @@ int ha_tina::write_row(byte * buf) statistic_increment(ha_write_count,&LOCK_status); - if (table->timestamp_default_now) - update_timestamp(buf+table->timestamp_default_now-1); + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) + table->timestamp_field->set_time(); size= encode_quote(buf); @@ -464,8 +464,8 @@ int ha_tina::update_row(const byte * old_data, byte * new_data) statistic_increment(ha_update_count,&LOCK_status); - if (table->timestamp_default_now) - update_timestamp(new_data+table->timestamp_default_now-1); + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) + table->timestamp_field->set_time(); size= encode_quote(new_data); diff --git a/sql/field.cc b/sql/field.cc index 3dc1375dff3..aae507cd0ec 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -304,14 +304,11 @@ bool Field::field_cast_compatible(Field::field_cast_enum type) { DBUG_ASSERT(type != FIELD_CAST_STOP); Field::field_cast_enum *array= field_cast_array[field_cast_type()]; - uint i= 0; - Field::field_cast_enum tp; - do + while (*array != FIELD_CAST_STOP) { - tp= array[i++]; - if (tp == type) + if (*(array++) == type) return 1; - } while (tp != FIELD_CAST_STOP); + } return 0; } @@ -455,11 +452,9 @@ bool Field::get_time(TIME *ltime) void Field::store_time(TIME *ltime,timestamp_type type) { - char buff[MAX_DATE_REP_LENGTH]; - String tmp; - tmp.set(buff, sizeof(buff), &my_charset_bin); - TIME_to_string(ltime, &tmp); - store(buff, tmp.length(), &my_charset_bin); + char buff[MAX_DATE_STRING_REP_LENGTH]; + uint length= (uint) my_TIME_to_str(ltime, buff); + store(buff, length, &my_charset_bin); } @@ -4438,13 +4433,9 @@ char *Field_string::pack(char *to, const char *from, uint max_length) while (end > from && end[-1] == ' ') end--; length= (end-from); + *to++= (char) (uchar) length; if (field_length > 255) - { - int2store(to, length); - to+= 2; - } - else - *to++= (char) (uchar) length; + *to++= (char) (uchar) (length >> 8); memcpy(to, from, (int) length); return to+length; } @@ -4459,13 +4450,9 @@ char *Field_string::pack_key(char *to, const char *from, uint max_length) set_if_smaller(length, char_length); while (length && from[length-1] == ' ') length--; + *to++= (char) (uchar) length; if (field_length > 255) - { - int2store(to, length); - to+= 2; - } - else - *to++= (char) (uchar) length; + *to++= (char) (uchar) (length >> 8); memcpy(to, from, length); return to+length; } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index d748c005d02..8d9ecb95fc0 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -302,7 +302,7 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { - return(HA_ERR_CANNOT_ADD_FOREIGN); /* TODO: This is a bit + return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit misleading, a new MySQL error code should be introduced */ } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { @@ -429,6 +429,36 @@ innobase_mysql_print_thd( putc('\n', f); } +/********************************************************************** +Compares NUL-terminated UTF-8 strings case insensitively. + +NOTE that the exact prototype of this function has to be in +/innobase/dict/dict0dict.c! */ +extern "C" +int +innobase_strcasecmp( +/*================*/ + /* out: 0 if a=b, <0 if a<b, >1 if a>b */ + const char* a, /* in: first string to compare */ + const char* b) /* in: second string to compare */ +{ + return(my_strcasecmp(system_charset_info, a, b)); +} + +/********************************************************************** +Makes all characters in a NUL-terminated UTF-8 string lower case. + +NOTE that the exact prototype of this function has to be in +/innobase/dict/dict0dict.c! */ +extern "C" +void +innobase_casedn_str( +/*================*/ + char* a) /* in/out: string to put in lower case */ +{ + my_casedn_str(system_charset_info, a); +} + /************************************************************************* Creates a temporary file. */ extern "C" @@ -687,14 +717,7 @@ innobase_query_caching_of_table_permitted( separator between db and table */ norm_name[full_name_len] = '\0'; #ifdef __WIN__ - /* Put to lower case */ - - char* ptr = norm_name; - - while (*ptr != '\0') { - *ptr = tolower(*ptr); - ptr++; - } + innobase_casedn_str(norm_name); #endif /* The call of row_search_.. will start a new transaction if it is not yet started */ @@ -855,7 +878,7 @@ innobase_init(void) Note that when using the embedded server, the datadirectory is not necessarily the current directory of this program. */ - if (mysql_embedded) { + if (mysqld_embedded) { default_path = mysql_real_data_home; fil_path_to_mysql_datadir = mysql_real_data_home; } else { @@ -993,7 +1016,7 @@ innobase_init(void) srv_max_n_open_files = (ulint) innobase_open_files; srv_innodb_status = (ibool) innobase_create_status_file; - srv_print_verbose_log = mysql_embedded ? 0 : 1; + srv_print_verbose_log = mysqld_embedded ? 0 : 1; /* Store the default charset-collation number of this MySQL installation */ @@ -1539,14 +1562,7 @@ normalize_table_name( norm_name[name_ptr - db_ptr - 1] = '/'; #ifdef __WIN__ - /* Put to lower case */ - - ptr = norm_name; - - while (*ptr != '\0') { - *ptr = tolower(*ptr); - ptr++; - } + innobase_casedn_str(norm_name); #endif } @@ -2445,9 +2461,10 @@ ha_innobase::write_row( /* If the insert did not succeed we restore the value of the auto-inc counter we used; note that this behavior was introduced only in version 4.0.4. - NOTE that a REPLACE command handles a duplicate key error + NOTE that a REPLACE command and LOAD DATA INFILE REPLACE + handles a duplicate key error itself, and we must not decrement the autoinc counter - if we are performing a REPLACE statement. + if we are performing a those statements. NOTE 2: if there was an error, for example a deadlock, which caused InnoDB to roll back the whole transaction already in the call of row_insert_for_mysql(), we may no @@ -2459,7 +2476,9 @@ ha_innobase::write_row( if (error == DB_DUPLICATE_KEY && (user_thd->lex->sql_command == SQLCOM_REPLACE || user_thd->lex->sql_command - == SQLCOM_REPLACE_SELECT)) { + == SQLCOM_REPLACE_SELECT + || (user_thd->lex->sql_command == SQLCOM_LOAD + && user_thd->lex->duplicates == DUP_REPLACE))) { skip_auto_inc_decr= TRUE; } @@ -3559,9 +3578,9 @@ create_index( field = form->field[j]; - if (0 == ut_cmp_in_lower_case( - (char*)field->field_name, - (char*)key_part->field->field_name)) { + if (0 == innobase_strcasecmp( + field->field_name, + key_part->field->field_name)) { /* Found the corresponding column */ break; @@ -4003,7 +4022,7 @@ innobase_drop_database( namebuf[len] = '/'; namebuf[len + 1] = '\0'; #ifdef __WIN__ - my_casedn_str(system_charset_info, namebuf); + innobase_casedn_str(namebuf); #endif trx = trx_allocate_for_mysql(); trx->mysql_thd = current_thd; @@ -4318,6 +4337,8 @@ ha_innobase::info( ha_rows rec_per_key; ulong j; ulong i; + char path[FN_REFLEN]; + os_file_stat_t stat_info; DBUG_ENTER("info"); @@ -4355,6 +4376,26 @@ ha_innobase::info( prebuilt->trx->op_info = (char*) "returning various info to MySQL"; + + if (ib_table->space != 0) { + my_snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, ib_table->name, + ".ibd"); + unpack_filename(path,path); + } else { + my_snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, ib_table->name, + reg_ext); + + unpack_filename(path,path); + } + + /* Note that we do not know the access time of the table, + nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ + + if (os_file_get_status(path,&stat_info)) { + create_time = stat_info.ctime; + } } if (flag & HA_STATUS_VARIABLE) { @@ -4942,7 +4983,8 @@ ha_innobase::external_lock( } if (prebuilt->select_lock_type != LOCK_NONE) { - if (thd->in_lock_tables) { + if (thd->in_lock_tables && + thd->variables.innodb_table_locks) { ulint error; error = row_lock_table_for_mysql(prebuilt); @@ -5468,4 +5510,30 @@ innobase_get_at_most_n_mbchars( } } +extern "C" { +/********************************************************************** +This function returns true if SQL-query in the current thread +is either REPLACE or LOAD DATA INFILE REPLACE. +NOTE that /mysql/innobase/row/row0ins.c must contain the +prototype for this function ! */ + +ibool +innobase_query_is_replace(void) +/*===========================*/ +{ + THD* thd; + + thd = (THD *)innobase_current_thd(); + + if ( thd->lex->sql_command == SQLCOM_REPLACE || + thd->lex->sql_command == SQLCOM_REPLACE_SELECT || + ( thd->lex->sql_command == SQLCOM_LOAD && + thd->lex->duplicates == DUP_REPLACE )) { + return true; + } else { + return false; + } +} +} + #endif /* HAVE_INNOBASE_DB */ diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 0b993ebe793..6504dd321a0 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -537,6 +537,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) { + int error; if (!file) return HA_ADMIN_INTERNAL_ERROR; MI_CHECK param; @@ -546,7 +547,14 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE | T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX); param.sort_buffer_length= check_opt->sort_buffer_size; - return repair(thd,param,1); + if ((error= repair(thd,param,1)) && param.retry_repair) + { + sql_print_warning("Warning: Optimize table got errno %d, retrying", + my_errno); + param.testflag&= ~T_REP_BY_SORT; + error= repair(thd,param,1); + } + return error; } @@ -913,7 +921,13 @@ int ha_myisam::enable_indexes(uint mode) param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; param.tmpdir=&mysql_tmpdir_list; - error=repair(thd,param,0) != HA_ADMIN_OK; + if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) + { + sql_print_warning("Warning: Enabling keys got errno %d, retrying", + my_errno); + param.testflag&= ~(T_REP_BY_SORT | T_QUICK); + error= (repair(thd,param,0) != HA_ADMIN_OK); + } info(HA_STATUS_CONST); thd->proc_info=save_proc_info; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3441ee1e339..145fd23ff43 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -65,7 +65,7 @@ typedef NdbDictionary::Table NDBTAB; typedef NdbDictionary::Index NDBINDEX; typedef NdbDictionary::Dictionary NDBDICT; -bool ndbcluster_inited= false; +bool ndbcluster_inited= FALSE; static Ndb* g_ndb= NULL; static Ndb_cluster_connection* g_ndb_cluster_connection= NULL; @@ -90,6 +90,12 @@ static int ndb_get_table_statistics(Ndb*, const char *, /* + Dummy buffer to read zero pack_length fields + which are mapped to 1 char +*/ +static byte dummy_buf[1]; + +/* Error handling functions */ @@ -134,8 +140,13 @@ static int ndb_to_mysql_error(const NdbError *err) uint i; for (i=0 ; err_map[i].ndb_err != err->code ; i++) { - if (err_map[i].my_err == -1) + if (err_map[i].my_err == -1){ + // Push the NDB error message as warning + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_GET_ERRMSG, ER(ER_GET_ERRMSG), + err->code, err->message, "NDB"); return err->code; + } } return err_map[i].my_err; } @@ -146,8 +157,10 @@ inline int execute_no_commit(ha_ndbcluster *h, NdbConnection *trans) { int m_batch_execute= 0; - if (false && m_batch_execute) +#ifdef NOT_USED + if (m_batch_execute) return 0; +#endif return trans->execute(NoCommit,AbortOnError,1); } @@ -155,8 +168,10 @@ inline int execute_commit(ha_ndbcluster *h, NdbConnection *trans) { int m_batch_execute= 0; - if (false && m_batch_execute) +#ifdef NOT_USED + if (m_batch_execute) return 0; +#endif return trans->execute(Commit,AbortOnError,1); } @@ -164,8 +179,10 @@ inline int execute_no_commit_ie(ha_ndbcluster *h, NdbConnection *trans) { int m_batch_execute= 0; - if (false && m_batch_execute) +#ifdef NOT_USED + if (m_batch_execute) return 0; +#endif return trans->execute(NoCommit,IgnoreError,1); } @@ -326,7 +343,7 @@ bool ha_ndbcluster::get_error_message(int error, Ndb *ndb= ((Thd_ndb*)current_thd->transaction.thd_ndb)->ndb; if (!ndb) - DBUG_RETURN(false); + DBUG_RETURN(FALSE); const NdbError err= ndb->getNdbError(error); bool temporary= err.status==NdbError::TemporaryError; @@ -367,12 +384,12 @@ static inline bool ndb_supported_type(enum_field_types type) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: - return true; + return TRUE; case MYSQL_TYPE_NULL: case MYSQL_TYPE_GEOMETRY: break; } - return false; + return FALSE; } @@ -432,6 +449,13 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, if (ndb_supported_type(field->type())) { + // ndb currently does not support size 0 + const byte *empty_field= ""; + if (pack_len == 0) + { + pack_len= 1; + field_ptr= empty_field; + } if (! (field->flags & BLOB_FLAG)) { if (field->is_null()) @@ -466,7 +490,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); if (set_blob_value) - *set_blob_value= true; + *set_blob_value= TRUE; // No callback needed to write value DBUG_RETURN(ndb_blob->setValue(blob_ptr, blob_len) != 0); } @@ -575,7 +599,11 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_ASSERT(field->ptr != NULL); if (! (field->flags & BLOB_FLAG)) { - byte *field_buf= buf + (field->ptr - table->record[0]); + byte *field_buf; + if (field->pack_length() != 0) + field_buf= buf + (field->ptr - table->record[0]); + else + field_buf= dummy_buf; m_value[fieldnr].rec= ndb_op->getValue(fieldnr, field_buf); DBUG_RETURN(m_value[fieldnr].rec == NULL); @@ -609,24 +637,24 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, bool ha_ndbcluster::uses_blob_value(bool all_fields) { if (table->blob_fields == 0) - return false; + return FALSE; if (all_fields) - return true; + return TRUE; { uint no_fields= table->fields; int i; - THD *thd= current_thd; + THD *thd= table->in_use; // They always put blobs at the end.. for (i= no_fields - 1; i >= 0; i--) { Field *field= table->field[i]; if (thd->query_id == field->query_id) { - return true; + return TRUE; } } } - return false; + return FALSE; } @@ -645,7 +673,7 @@ int ha_ndbcluster::get_metadata(const char *path) NDBDICT *dict= m_ndb->getDictionary(); const NDBTAB *tab; int error; - bool invalidating_ndb_table= false; + bool invalidating_ndb_table= FALSE; DBUG_ENTER("get_metadata"); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); @@ -676,7 +704,7 @@ int ha_ndbcluster::get_metadata(const char *path) { DBUG_PRINT("info", ("Invalidating table")); dict->invalidateTable(m_tabname); - invalidating_ndb_table= true; + invalidating_ndb_table= TRUE; } else { @@ -687,12 +715,12 @@ int ha_ndbcluster::get_metadata(const char *path) DBUG_DUMP("pack_data", (char*)pack_data, pack_length); DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); error= 3; - invalidating_ndb_table= false; + invalidating_ndb_table= FALSE; } } else { - invalidating_ndb_table= false; + invalidating_ndb_table= FALSE; } my_free((char*)data, MYF(0)); my_free((char*)pack_data, MYF(0)); @@ -755,7 +783,7 @@ int ha_ndbcluster::build_index_list(TABLE *tab, enum ILBP phase) error= create_ordered_index(index_name, key_info); break; default: - DBUG_ASSERT(false); + DBUG_ASSERT(FALSE); break; } if (error) @@ -824,13 +852,10 @@ void ha_ndbcluster::release_metadata() int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type) { - if (type == TL_WRITE_ALLOW_WRITE) + if (type >= TL_WRITE_ALLOW_WRITE) return NdbOperation::LM_Exclusive; else if (uses_blob_value(retrieve_all_fields)) - /* - TODO use a new scan mode to read + lock + keyinfo - */ - return NdbOperation::LM_Exclusive; + return NdbOperation::LM_Read; else return NdbOperation::LM_CommittedRead; } @@ -1161,7 +1186,7 @@ inline int ha_ndbcluster::next_result(byte *buf) If this an update or delete, call nextResult with false to process any records already cached in NdbApi */ - bool contact_ndb= m_lock.type != TL_WRITE_ALLOW_WRITE; + bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE; do { DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb)); /* @@ -1172,7 +1197,7 @@ inline int ha_ndbcluster::next_result(byte *buf) if (execute_no_commit(this,trans) != 0) DBUG_RETURN(ndb_err(trans)); ops_pending= 0; - blobs_pending= false; + blobs_pending= FALSE; } check= cursor->nextResult(contact_ndb); if (check == 0) @@ -1225,114 +1250,204 @@ inline int ha_ndbcluster::next_result(byte *buf) DBUG_RETURN(HA_ERR_END_OF_FILE); } - /* - Set bounds for a ordered index scan, use key_range + Set bounds for ordered index scan. */ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, - const key_range *key, - int bound) + const key_range *keys[2]) { - uint key_len, key_store_len, tot_len, key_tot_len; - byte *key_ptr; - KEY* key_info= table->key_info + active_index; - KEY_PART_INFO* key_part= key_info->key_part; - KEY_PART_INFO* end= key_part+key_info->key_parts; - Field* field; - bool key_nullable, key_null; + const KEY *const key_info= table->key_info + active_index; + const uint key_parts= key_info->key_parts; + uint key_tot_len[2]; + uint tot_len; + int i, j; DBUG_ENTER("set_bounds"); - DBUG_PRINT("enter", ("bound: %d", bound)); - DBUG_PRINT("enter", ("key_parts: %d", key_info->key_parts)); - DBUG_PRINT("enter", ("key->length: %d", key->length)); - DBUG_PRINT("enter", ("key->flag: %d", key->flag)); + DBUG_PRINT("info", ("key_parts=%d", key_parts)); - // Set bounds using key data + for (j= 0; j <= 1; j++) + { + const key_range *key= keys[j]; + if (key != NULL) + { + // for key->flag see ha_rkey_function + DBUG_PRINT("info", ("key %d length=%d flag=%d", + j, key->length, key->flag)); + key_tot_len[j]= key->length; + } + else + { + DBUG_PRINT("info", ("key %d not present", j)); + key_tot_len[j]= 0; + } + } tot_len= 0; - key_ptr= (byte *) key->key; - key_tot_len= key->length; - for (; key_part != end; key_part++) + + for (i= 0; i < key_parts; i++) { - field= key_part->field; - key_len= key_part->length; - key_store_len= key_part->store_length; - key_nullable= (bool) key_part->null_bit; - key_null= (field->maybe_null() && *key_ptr); - tot_len+= key_store_len; - - const char* bounds[]= {"LE", "LT", "GE", "GT", "EQ"}; - DBUG_ASSERT(bound >= 0 && bound <= 4); - DBUG_PRINT("info", ("Set Bound%s on %s %s %s", - bounds[bound], - field->field_name, - key_nullable ? "NULLABLE" : "", - key_null ? "NULL":"")); - DBUG_PRINT("info", ("Total length %d", tot_len)); - - DBUG_DUMP("key", (char*) key_ptr, key_store_len); - - if (op->setBound(field->field_name, - bound, - key_null ? 0 : (key_nullable ? key_ptr + 1 : key_ptr), - key_null ? 0 : key_len) != 0) - ERR_RETURN(op->getNdbError()); - - key_ptr+= key_store_len; + KEY_PART_INFO *key_part= &key_info->key_part[i]; + Field *field= key_part->field; + uint part_len= key_part->length; + uint part_store_len= key_part->store_length; + bool part_nullable= (bool) key_part->null_bit; + // Info about each key part + struct part_st { + bool part_last; + const key_range *key; + const byte *part_ptr; + bool part_null; + int bound_type; + const char* bound_ptr; + }; + struct part_st part[2]; + + for (j= 0; j <= 1; j++) + { + struct part_st &p = part[j]; + p.key= NULL; + p.bound_type= -1; + if (tot_len < key_tot_len[j]) + { + p.part_last= (tot_len + part_store_len >= key_tot_len[j]); + p.key= keys[j]; + p.part_ptr= &p.key->key[tot_len]; + p.part_null= (field->maybe_null() && *p.part_ptr); + p.bound_ptr= (const char *) + p.part_null ? 0 : part_nullable ? p.part_ptr + 1 : p.part_ptr; + + if (j == 0) + { + switch (p.key->flag) + { + case HA_READ_KEY_EXACT: + p.bound_type= NdbIndexScanOperation::BoundEQ; + break; + case HA_READ_KEY_OR_NEXT: + p.bound_type= NdbIndexScanOperation::BoundLE; + break; + case HA_READ_AFTER_KEY: + if (! p.part_last) + p.bound_type= NdbIndexScanOperation::BoundLE; + else + p.bound_type= NdbIndexScanOperation::BoundLT; + break; + default: + break; + } + } + if (j == 1) { + switch (p.key->flag) + { + case HA_READ_BEFORE_KEY: + if (! p.part_last) + p.bound_type= NdbIndexScanOperation::BoundGE; + else + p.bound_type= NdbIndexScanOperation::BoundGT; + break; + case HA_READ_AFTER_KEY: // weird + p.bound_type= NdbIndexScanOperation::BoundGE; + break; + default: + break; + } + } - if (tot_len >= key_tot_len) - break; + if (p.bound_type == -1) + { + DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag)); + DBUG_ASSERT(false); + // Stop setting bounds but continue with what we have + DBUG_RETURN(0); + } + } + } - /* - Only one bound which is not EQ can be set - so if this bound was not EQ, bail out and make - a best effort attempt - */ - if (bound != NdbIndexScanOperation::BoundEQ) - break; - } + // Seen with e.g. b = 1 and c > 1 + if (part[0].bound_type == NdbIndexScanOperation::BoundLE && + part[1].bound_type == NdbIndexScanOperation::BoundGE && + memcmp(part[0].part_ptr, part[1].part_ptr, part_store_len) == 0) + { + DBUG_PRINT("info", ("replace LE/GE pair by EQ")); + part[0].bound_type= NdbIndexScanOperation::BoundEQ; + part[1].bound_type= -1; + } + // Not seen but was in previous version + if (part[0].bound_type == NdbIndexScanOperation::BoundEQ && + part[1].bound_type == NdbIndexScanOperation::BoundGE && + memcmp(part[0].part_ptr, part[1].part_ptr, part_store_len) == 0) + { + DBUG_PRINT("info", ("remove GE from EQ/GE pair")); + part[1].bound_type= -1; + } + for (j= 0; j <= 1; j++) + { + struct part_st &p = part[j]; + // Set bound if not done with this key + if (p.key != NULL) + { + DBUG_PRINT("info", ("key %d:%d offset=%d length=%d last=%d bound=%d", + j, i, tot_len, part_len, p.part_last, p.bound_type)); + DBUG_DUMP("info", (const char*)p.part_ptr, part_store_len); + + // Set bound if not cancelled via type -1 + if (p.bound_type != -1) + if (op->setBound(field->field_name, p.bound_type, p.bound_ptr)) + ERR_RETURN(op->getNdbError()); + } + } + + tot_len+= part_store_len; + } DBUG_RETURN(0); } -#ifndef DBUG_OFF - -const char* key_flag_strs[] = -{ "HA_READ_KEY_EXACT", - "HA_READ_KEY_OR_NEXT", - "HA_READ_KEY_OR_PREV", - "HA_READ_AFTER_KEY", - "HA_READ_BEFORE_KEY", - "HA_READ_PREFIX", - "HA_READ_PREFIX_LAST", - "HA_READ_PREFIX_LAST_OR_PREV", - "HA_READ_MBR_CONTAIN", - "HA_READ_MBR_INTERSECT", - "HA_READ_MBR_WITHIN", - "HA_READ_MBR_DISJOINT", - "HA_READ_MBR_EQUAL" -}; +inline +int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op) +{ + uint i; + THD *thd= current_thd; + NdbConnection *trans= m_active_trans; -const int no_of_key_flags = sizeof(key_flag_strs)/sizeof(char*); + DBUG_ENTER("define_read_attrs"); -void print_key(const key_range* key, const char* info) -{ - if (key) - { - const char* str= key->flag < no_of_key_flags ? - key_flag_strs[key->flag] : "Unknown flag"; - - DBUG_LOCK_FILE; - fprintf(DBUG_FILE,"%s: %s, length=%d, key=", info, str, key->length); - uint i; - for (i=0; i<key->length-1; i++) - fprintf(DBUG_FILE,"%0d ", key->key[i]); - fprintf(DBUG_FILE, "\n"); - DBUG_UNLOCK_FILE; + // Define attributes to read + for (i= 0; i < table->fields; i++) + { + Field *field= table->field[i]; + if ((thd->query_id == field->query_id) || + (field->flags & PRI_KEY_FLAG) || + retrieve_all_fields) + { + if (get_ndb_value(op, field, i, buf)) + ERR_RETURN(op->getNdbError()); + } + else + { + m_value[i].ptr= NULL; + } } - return; -} + + if (table->primary_key == MAX_KEY) + { + DBUG_PRINT("info", ("Getting hidden key")); + // Scanning table with no primary key + int hidden_no= table->fields; +#ifndef DBUG_OFF + const NDBTAB *tab= (const NDBTAB *) m_table; + if (!tab->getColumn(hidden_no)) + DBUG_RETURN(1); #endif + if (get_ndb_value(op, NULL, hidden_no, NULL)) + ERR_RETURN(op->getNdbError()); + } + + if (execute_no_commit(this,trans) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_PRINT("exit", ("Scan started successfully")); + DBUG_RETURN(next_result(buf)); +} /* Start ordered index scan in NDB @@ -1342,6 +1457,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, const key_range *end_key, bool sorted, byte* buf) { + bool restart; NdbConnection *trans= m_active_trans; NdbResultSet *cursor; NdbIndexScanOperation *op; @@ -1350,44 +1466,51 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_PRINT("enter", ("index: %u, sorted: %d", active_index, sorted)); DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname)); - DBUG_EXECUTE("enter", print_key(start_key, "start_key");); - DBUG_EXECUTE("enter", print_key(end_key, "end_key");); + // Check that sorted seems to be initialised + DBUG_ASSERT(sorted == 0 || sorted == 1); + if (m_active_cursor == 0) + { + restart= false; + NdbOperation::LockMode lm= + (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *) + m_index[active_index].index, + (const NDBTAB *) m_table)) || + !(cursor= op->readTuples(lm, 0, parallelism, sorted))) + ERR_RETURN(trans->getNdbError()); + m_active_cursor= cursor; + } else { + restart= true; + op= (NdbIndexScanOperation*)m_active_cursor->getOperation(); + + DBUG_ASSERT(op->getSorted() == sorted); + DBUG_ASSERT(op->getLockMode() == + (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); + if(op->reset_bounds()) + DBUG_RETURN(ndb_err(m_active_trans)); + } - NdbOperation::LockMode lm= - (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); - if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *) - m_index[active_index].index, - (const NDBTAB *) m_table)) || - !(cursor= op->readTuples(lm, 0, parallelism, sorted))) - ERR_RETURN(trans->getNdbError()); - m_active_cursor= cursor; - - if (start_key && - set_bounds(op, start_key, - (start_key->flag == HA_READ_KEY_EXACT) ? - NdbIndexScanOperation::BoundEQ : - (start_key->flag == HA_READ_AFTER_KEY) ? - NdbIndexScanOperation::BoundLT : - NdbIndexScanOperation::BoundLE)) - DBUG_RETURN(1); + { + const key_range *keys[2]= { start_key, end_key }; + int ret= set_bounds(op, keys); + if (ret) + DBUG_RETURN(ret); + } - if (end_key) + if (!restart) { - if (start_key && start_key->flag == HA_READ_KEY_EXACT) - { - DBUG_PRINT("info", ("start_key is HA_READ_KEY_EXACT ignoring end_key")); - } - else if (set_bounds(op, end_key, - (end_key->flag == HA_READ_AFTER_KEY) ? - NdbIndexScanOperation::BoundGE : - NdbIndexScanOperation::BoundGT)) - DBUG_RETURN(1); + DBUG_RETURN(define_read_attrs(buf, op)); + } + else + { + if (execute_no_commit(this,trans) != 0) + DBUG_RETURN(ndb_err(trans)); + + DBUG_RETURN(next_result(buf)); } - DBUG_RETURN(define_read_attrs(buf, op)); } - /* Start a filtered scan in NDB. @@ -1496,53 +1619,6 @@ int ha_ndbcluster::full_table_scan(byte *buf) DBUG_RETURN(define_read_attrs(buf, op)); } -inline -int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op) -{ - uint i; - THD *thd= current_thd; - NdbConnection *trans= m_active_trans; - - DBUG_ENTER("define_read_attrs"); - - // Define attributes to read - for (i= 0; i < table->fields; i++) - { - Field *field= table->field[i]; - if ((thd->query_id == field->query_id) || - (field->flags & PRI_KEY_FLAG) || - retrieve_all_fields) - { - if (get_ndb_value(op, field, i, buf)) - ERR_RETURN(op->getNdbError()); - } - else - { - m_value[i].ptr= NULL; - } - } - - if (table->primary_key == MAX_KEY) - { - DBUG_PRINT("info", ("Getting hidden key")); - // Scanning table with no primary key - int hidden_no= table->fields; -#ifndef DBUG_OFF - const NDBTAB *tab= (const NDBTAB *) m_table; - if (!tab->getColumn(hidden_no)) - DBUG_RETURN(1); -#endif - if (get_ndb_value(op, NULL, hidden_no, NULL)) - ERR_RETURN(op->getNdbError()); - } - - if (execute_no_commit(this,trans) != 0) - DBUG_RETURN(ndb_err(trans)); - DBUG_PRINT("exit", ("Scan started successfully")); - DBUG_RETURN(next_result(buf)); -} - - /* Insert one record into NDB */ @@ -1585,7 +1661,7 @@ int ha_ndbcluster::write_row(byte *record) if (has_auto_increment) { - skip_auto_increment= false; + skip_auto_increment= FALSE; update_auto_increment(); skip_auto_increment= !auto_increment_column_changed; } @@ -1595,14 +1671,14 @@ int ha_ndbcluster::write_row(byte *record) } // Set non-key attribute(s) - bool set_blob_value= false; + bool set_blob_value= FALSE; for (i= 0; i < table->fields; i++) { Field *field= table->field[i]; if (!(field->flags & PRI_KEY_FLAG) && set_ndb_value(op, field, i, &set_blob_value)) { - skip_auto_increment= true; + skip_auto_increment= TRUE; ERR_RETURN(op->getNdbError()); } } @@ -1616,7 +1692,7 @@ int ha_ndbcluster::write_row(byte *record) */ rows_inserted++; no_uncommitted_rows_update(1); - bulk_insert_not_flushed= true; + bulk_insert_not_flushed= TRUE; if ((rows_to_insert == 1) || ((rows_inserted % bulk_insert_rows) == 0) || set_blob_value) @@ -1627,12 +1703,12 @@ int ha_ndbcluster::write_row(byte *record) "rows_inserted:%d, bulk_insert_rows: %d", (int)rows_inserted, (int)bulk_insert_rows)); - bulk_insert_not_flushed= false; + bulk_insert_not_flushed= FALSE; if (thd->transaction.on) { if (execute_no_commit(this,trans) != 0) { - skip_auto_increment= true; + skip_auto_increment= TRUE; no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } @@ -1641,7 +1717,7 @@ int ha_ndbcluster::write_row(byte *record) { if (execute_commit(this,trans) != 0) { - skip_auto_increment= true; + skip_auto_increment= TRUE; no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } @@ -1655,11 +1731,11 @@ int ha_ndbcluster::write_row(byte *record) DBUG_PRINT("info", ("Trying to set next auto increment value to %lu", (ulong) next_val)); - if (m_ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, true)) + if (m_ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE)) DBUG_PRINT("info", ("Setting next auto increment value to %u", next_val)); } - skip_auto_increment= true; + skip_auto_increment= TRUE; DBUG_RETURN(0); } @@ -1763,8 +1839,8 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) if (!(op= cursor->updateTuple())) ERR_RETURN(trans->getNdbError()); ops_pending++; - if (uses_blob_value(false)) - blobs_pending= true; + if (uses_blob_value(FALSE)) + blobs_pending= TRUE; } else { @@ -1920,7 +1996,7 @@ void ha_ndbcluster::unpack_record(byte* buf) else { NdbBlob* ndb_blob= (*value).blob; - bool isNull= true; + bool isNull= TRUE; int ret= ndb_blob->getNull(isNull); DBUG_ASSERT(ret == 0); if (isNull) @@ -1988,7 +2064,7 @@ void ha_ndbcluster::print_results() else { ndb_blob= value.blob; - bool isNull= true; + bool isNull= TRUE; ndb_blob->getNull(isNull); if (isNull) { fprintf(DBUG_FILE, "NULL\n"); @@ -2165,19 +2241,16 @@ int ha_ndbcluster::index_read(byte *buf, break; default: case UNDEFINED_INDEX: - DBUG_ASSERT(false); - return 1; + DBUG_ASSERT(FALSE); + DBUG_RETURN(1); break; } - if (m_active_cursor) - close_scan(); - key_range start_key; start_key.key = key; start_key.length = key_len; start_key.flag = find_flag; - error= ordered_index_scan(&start_key, 0, true, buf); + error= ordered_index_scan(&start_key, 0, TRUE, buf); DBUG_RETURN(error == HA_ERR_END_OF_FILE ? HA_ERR_KEY_NOT_FOUND : error); } @@ -2219,7 +2292,7 @@ int ha_ndbcluster::index_first(byte *buf) // Start the ordered index scan and fetch the first row // Only HA_READ_ORDER indexes get called by index_first - DBUG_RETURN(ordered_index_scan(0, 0, true, buf)); + DBUG_RETURN(ordered_index_scan(0, 0, TRUE, buf)); } @@ -2228,9 +2301,9 @@ int ha_ndbcluster::index_last(byte *buf) DBUG_ENTER("index_last"); statistic_increment(ha_read_last_count,&LOCK_status); int res; - if((res= ordered_index_scan(0, 0, true, buf)) == 0){ + if((res= ordered_index_scan(0, 0, TRUE, buf)) == 0){ NdbResultSet *cursor= m_active_cursor; - while((res= cursor->nextResult(true)) == 0); + while((res= cursor->nextResult(TRUE)) == 0); if(res == 1){ unpack_record(buf); table->status= 0; @@ -2241,20 +2314,6 @@ int ha_ndbcluster::index_last(byte *buf) } -int ha_ndbcluster::read_range_first(const key_range *start_key, - const key_range *end_key, - bool eq_range, bool sorted) -{ - byte* buf= table->record[0]; - DBUG_ENTER("ha_ndbcluster::read_range_first"); - - DBUG_RETURN(read_range_first_to_buf(start_key, - end_key, - eq_range, - sorted, - buf)); -} - inline int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, const key_range *end_key, @@ -2266,9 +2325,6 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, DBUG_ENTER("ha_ndbcluster::read_range_first_to_buf"); DBUG_PRINT("info", ("eq_range: %d, sorted: %d", eq_range, sorted)); - if (m_active_cursor) - close_scan(); - switch (get_index_type(active_index)){ case PRIMARY_KEY_ORDERED_INDEX: case PRIMARY_KEY_INDEX: @@ -2296,15 +2352,26 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, break; } - // Start the ordered index scan and fetch the first row - error= ordered_index_scan(start_key, end_key, sorted, - buf); - + error= ordered_index_scan(start_key, end_key, sorted, buf); DBUG_RETURN(error); } +int ha_ndbcluster::read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted) +{ + byte* buf= table->record[0]; + DBUG_ENTER("ha_ndbcluster::read_range_first"); + + DBUG_RETURN(read_range_first_to_buf(start_key, + end_key, + eq_range, + sorted, + buf)); +} + int ha_ndbcluster::read_range_next() { DBUG_ENTER("ha_ndbcluster::read_range_next"); @@ -2584,8 +2651,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) case HA_EXTRA_NO_IGNORE_DUP_KEY: DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY")); DBUG_PRINT("info", ("Turning OFF use of write instead of insert")); - m_use_write= false; - m_ignore_dup_key_not_supported= false; + m_use_write= FALSE; + m_ignore_dup_key_not_supported= FALSE; break; case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those where field->query_id is the same as @@ -2671,7 +2738,7 @@ int ha_ndbcluster::end_bulk_insert() DBUG_PRINT("info", ("Sending inserts to NDB, "\ "rows_inserted:%d, bulk_insert_rows: %d", rows_inserted, bulk_insert_rows)); - bulk_insert_not_flushed= false; + bulk_insert_not_flushed= FALSE; if (execute_no_commit(this,trans) != 0) { no_uncommitted_rows_execute_failure(); my_errno= error= ndb_err(trans); @@ -2731,6 +2798,9 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, /* If we are not doing a LOCK TABLE, then allow multiple writers */ + /* Since NDB does not currently have table locks + this is treated as a ordinary lock */ + if ((lock_type >= TL_WRITE_ALLOW_WRITE && lock_type <= TL_WRITE) && !thd->in_lock_tables) lock_type= TL_WRITE_ALLOW_WRITE; @@ -3110,7 +3180,10 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Char); col.setCharset(cs); } - col.setLength(field->pack_length()); + if (field->pack_length() == 0) + col.setLength(1); // currently ndb does not support size 0 + else + col.setLength(field->pack_length()); break; case MYSQL_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) @@ -3210,7 +3283,7 @@ static int create_ndb_column(NDBCOL &col, col.setAutoIncrementInitialValue(value); } else - col.setAutoIncrement(false); + col.setAutoIncrement(FALSE); return 0; } @@ -3280,7 +3353,7 @@ int ha_ndbcluster::create(const char *name, col.setName("$PK"); col.setType(NdbDictionary::Column::Bigunsigned); col.setLength(1); - col.setNullable(false); + col.setNullable(FALSE); col.setPrimaryKey(TRUE); col.setAutoIncrement(TRUE); tab.addColumn(col); @@ -3315,7 +3388,7 @@ int ha_ndbcluster::create_ordered_index(const char *name, KEY *key_info) { DBUG_ENTER("create_ordered_index"); - DBUG_RETURN(create_index(name, key_info, false)); + DBUG_RETURN(create_index(name, key_info, FALSE)); } int ha_ndbcluster::create_unique_index(const char *name, @@ -3323,7 +3396,7 @@ int ha_ndbcluster::create_unique_index(const char *name, { DBUG_ENTER("create_unique_index"); - DBUG_RETURN(create_index(name, key_info, true)); + DBUG_RETURN(create_index(name, key_info, TRUE)); } @@ -3349,7 +3422,7 @@ int ha_ndbcluster::create_index(const char *name, { ndb_index.setType(NdbDictionary::Index::OrderedIndex); // TODO Only temporary ordered indexes supported - ndb_index.setLogging(false); + ndb_index.setLogging(FALSE); } ndb_index.setTable(m_tabname); @@ -3512,15 +3585,15 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): HA_AUTO_PART_KEY | HA_NO_PREFIX_CHAR_KEYS), m_share(0), - m_use_write(false), - m_ignore_dup_key_not_supported(false), + m_use_write(FALSE), + m_ignore_dup_key_not_supported(FALSE), retrieve_all_fields(FALSE), rows_to_insert(1), rows_inserted(0), bulk_insert_rows(1024), - bulk_insert_not_flushed(false), + bulk_insert_not_flushed(FALSE), ops_pending(0), - skip_auto_increment(true), + skip_auto_increment(TRUE), blobs_pending(0), blobs_buffer(0), blobs_buffer_size(0), @@ -3929,11 +4002,11 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, TABLE_LIST table_list; bzero((char*) &table_list,sizeof(table_list)); table_list.db= (char*) db; - table_list.real_name=(char*)file_name; + table_list.alias=table_list.real_name=(char*)file_name; (void)mysql_rm_table_part2(thd, &table_list, - /* if_exists */ true, - /* drop_temporary */ false, - /* dont_log_query*/ true); + /* if_exists */ TRUE, + /* drop_temporary */ FALSE, + /* dont_log_query*/ TRUE); } } @@ -3942,7 +4015,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, while ((file_name=it2++)) { DBUG_PRINT("info", ("Table %s need discovery", name)); - if (ha_create_table_from_engine(thd, db, file_name, true) == 0) + if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0) files->push_back(thd->strdup(file_name)); } @@ -4009,7 +4082,7 @@ bool ndbcluster_init() if (ndb_discover_tables() != 0) DBUG_RETURN(TRUE); #endif - DBUG_RETURN(false); + DBUG_RETURN(FALSE); } @@ -4367,7 +4440,7 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, Uint64 sum_rows= 0; Uint64 sum_commits= 0; - while((check= rs->nextResult(true)) == 0) + while((check= rs->nextResult(TRUE)) == 0) { sum_rows+= rows; sum_commits+= commits; diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 36452033516..8224d1c4167 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -139,12 +139,12 @@ class ha_ndbcluster: public handler bool low_byte_first() const { #ifdef WORDS_BIGENDIAN - return false; + return FALSE; #else - return true; + return TRUE; #endif } - bool has_transactions() { return true; } + bool has_transactions() { return TRUE; } const char* index_type(uint key_number) { switch (get_index_type(key_number)) { @@ -214,8 +214,7 @@ class ha_ndbcluster: public handler int set_primary_key(NdbOperation *op, const byte *key); int set_primary_key(NdbOperation *op); int set_primary_key_from_old_data(NdbOperation *op, const byte *old_data); - int set_bounds(NdbIndexScanOperation *ndb_op, const key_range *key, - int bound); + int set_bounds(NdbIndexScanOperation *ndb_op, const key_range *keys[2]); int key_cmp(uint keynr, const byte * old_row, const byte * new_row); void print_results(); diff --git a/sql/handler.cc b/sql/handler.cc index e59358d44bf..cecf5689464 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1105,6 +1105,11 @@ void handler::print_error(int error, myf errflag) break; case HA_ERR_NO_SUCH_TABLE: { + /* + We have to use path to find database name instead of using + table->table_cache_key because if the table didn't exist, then + table_cache_key was not set up + */ char *db; char buff[FN_REFLEN]; uint length=dirname_part(buff,table->path); @@ -1276,23 +1281,26 @@ int ha_create_table_from_engine(THD* thd, const char *name, bool create_if_found) { - int error= 0; - const void* frmblob = NULL; - uint frmlen = 0; + int error; + const void *frmblob; + uint frmlen; char path[FN_REFLEN]; HA_CREATE_INFO create_info; TABLE table; DBUG_ENTER("ha_create_table_from_engine"); - DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); - DBUG_PRINT("enter", ("create_if_found: %d", create_if_found)); + DBUG_PRINT("enter", ("name '%s'.'%s' create_if_found: %d", + db, name, create_if_found)); bzero((char*) &create_info,sizeof(create_info)); if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) DBUG_RETURN(error); + /* + Table exists in handler + frmblob and frmlen are set + */ - // Table exists in handler - if (create_if_found) + if (create_if_found) { (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); // Save the frm file @@ -1309,9 +1317,7 @@ int ha_create_table_from_engine(THD* thd, !(table.file->table_flags() & HA_FILE_BASED)) { /* Ensure that handler gets name in lower case */ - strmov(path, name); my_casedn_str(files_charset_info, path); - name= path; } error=table.file->create(path,&table,&create_info); @@ -1319,8 +1325,7 @@ int ha_create_table_from_engine(THD* thd, } err_end: - if (frmblob) - my_free((char*) frmblob,MYF(0)); + my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(error); } @@ -1429,10 +1434,14 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, /* Try to discover one table from handler(s) + + RETURN + 0 ok. In this case *frmblob and *frmlen are set + 1 error. frmblob and frmlen may not be set */ -int ha_discover(THD* thd, const char* db, const char* name, - const void** frmblob, uint* frmlen) +int ha_discover(THD *thd, const char *db, const char *name, + const void **frmblob, uint *frmlen) { int error= 1; // Table does not exist in any handler DBUG_ENTER("ha_discover"); @@ -1470,6 +1479,8 @@ ha_find_files(THD *thd,const char *db,const char *path, } +#ifdef NOT_YET_USED + /* Ask handler if the table exists in engine @@ -1491,6 +1502,7 @@ int ha_table_exists(THD* thd, const char* db, const char* name) DBUG_RETURN(error); } +#endif /* diff --git a/sql/item.cc b/sql/item.cc index 0366ea29485..b4c416e7741 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -348,17 +348,45 @@ Item_field::Item_field(Field *f) :Item_ident(NullS, f->table_name, f->field_name) { set_field(f); - collation.set(DERIVATION_IMPLICIT); - fixed= 1; + /* + field_name and talbe_name should not point to garbage + if this item is to be reused + */ + orig_table_name= orig_field_name= ""; } Item_field::Item_field(THD *thd, Field *f) - :Item_ident(NullS, thd->strdup(f->table_name), - thd->strdup(f->field_name)) + :Item_ident(f->table->table_cache_key, f->table_name, f->field_name) { + /* + We always need to provide Item_field with a fully qualified field + name to avoid ambiguity when executing prepared statements like + SELECT * from d1.t1, d2.t1; (assuming d1.t1 and d2.t1 have columns + with same names). + This is because prepared statements never deal with wildcards in + select list ('*') and always fix fields using fully specified path + (i.e. db.table.column). + No check for OOM: if db_name is NULL, we'll just get + "Field not found" error. + We need to copy db_name, table_name and field_name because they must + be allocated in the statement memory, not in table memory (the table + structure can go away and pop up again between subsequent executions + of a prepared statement). + */ + if (thd->current_arena->is_stmt_prepare()) + { + if (db_name) + orig_db_name= thd->strdup(db_name); + orig_table_name= thd->strdup(table_name); + orig_field_name= thd->strdup(field_name); + /* + We don't restore 'name' in cleanup because it's not changed + during execution. Still we need it to point to persistent + memory if this item is to be reused. + */ + name= (char*) orig_field_name; + } set_field(f); - collation.set(DERIVATION_IMPLICIT); - fixed= 1; } // Constructor need to process subselect with temporary tables (see Item) @@ -381,6 +409,21 @@ void Item_field::set_field(Field *field_par) db_name=field_par->table->table_cache_key; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); collation.set(field_par->charset(), DERIVATION_IMPLICIT); + fixed= 1; +} + + +/* + Reset this item to point to a field from the new temporary table. + This is used when we create a new temporary table for each execution + of prepared statement. +*/ + +void Item_field::reset_field(Field *f) +{ + set_field(f); + /* 'name' is pointing at field->field_name of old field */ + name= (char*) f->field_name; } const char *Item_ident::full_name() const @@ -988,9 +1031,10 @@ String *Item_param::val_str(String* str) return str; case TIME_VALUE: { - if (str->reserve(MAX_DATE_REP_LENGTH)) + if (str->reserve(MAX_DATE_STRING_REP_LENGTH)) break; - TIME_to_string(&value.time, str); + str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr())); + str->set_charset(&my_charset_bin); return str; } case NULL_VALUE: @@ -1020,24 +1064,19 @@ const String *Item_param::query_val_str(String* str) const case TIME_VALUE: { char *buf, *ptr; - String tmp; str->length(0); /* TODO: in case of error we need to notify replication that binary log contains wrong statement */ - if (str->reserve(MAX_DATE_REP_LENGTH+3)) + if (str->reserve(MAX_DATE_STRING_REP_LENGTH+3)) break; /* Create date string inplace */ buf= str->c_ptr_quick(); ptr= buf; *ptr++= '\''; - tmp.set(ptr, MAX_DATE_REP_LENGTH, &my_charset_bin); - tmp.length(0); - TIME_to_string(&value.time, &tmp); - - ptr+= tmp.length(); + ptr+= (uint) my_TIME_to_str(&value.time, ptr); *ptr++= '\''; str->length((uint32) (ptr - buf)); break; @@ -1196,7 +1235,7 @@ bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate) static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, Item_ident *item) { - // store pointer on SELECT_LEX from wich item is dependent + // store pointer on SELECT_LEX from which item is dependent item->depended_from= last; current->mark_as_dependent(last); if (thd->lex->describe & DESCRIBE_EXTENDED) @@ -1378,8 +1417,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) field->query_id=thd->query_id; table->used_fields++; table->used_keys.intersect(field->part_of_key); + fixed= 1; } - fixed= 1; return 0; } @@ -1872,10 +1911,11 @@ bool Item_field::send(Protocol *protocol, String *buffer) return protocol->store(result_field); } + /* This is used for HAVING clause Find field in select list having the same name - */ +*/ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { @@ -1904,8 +1944,9 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) REPORT_ALL_ERRORS ), ¬_used)) == (Item **)not_found_item) { - upward_lookup= 1; Field *tmp= (Field*) not_found_field; + SELECT_LEX *last= 0; + upward_lookup= 1; /* We can't find table field in select list of current select, consequently we have to find it in outer subselect(s). @@ -1915,7 +1956,6 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) mention of table name, but if we join tables in one list it will cause error ER_NON_UNIQ_ERROR in find_item_in_list. */ - SELECT_LEX *last=0; for ( ; sl ; sl= (prev_unit= sl->master_unit())->outer_select()) { last= sl; @@ -1967,9 +2007,9 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) if (!ref) return 1; - else if (!tmp) + if (!tmp) return -1; - else if (ref == (Item **)not_found_item && tmp == not_found_field) + if (ref == (Item **)not_found_item && tmp == not_found_field) { if (upward_lookup) { @@ -1984,31 +2024,33 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) *(thd->lex->current_select->get_item_list()), &counter, REPORT_ALL_ERRORS, ¬_used); } - ref= 0; + ref= 0; // Safety return 1; } - else if (tmp != not_found_field) + if (tmp != not_found_field) { - ref= 0; // To prevent "delete *ref;" on ~Item_ref() of this item - Item_field* fld= new Item_field(tmp); - if (!fld) + Item_field* fld; + /* + Set ref to 0 as we are replacing this item with the found item + and this will ensure we get an error if this item would be + used elsewhere + */ + ref= 0; // Safety + if (!(fld= new Item_field(tmp))) return 1; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last, thd->lex->current_select, fld); return 0; } - else + if (!(*ref)->fixed) { - if (!(*ref)->fixed) - { - my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, - "forward reference in item list"); - return -1; - } - mark_as_dependent(thd, last, thd->lex->current_select, - this); - ref= last->ref_pointer_array + counter; + my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, + "forward reference in item list"); + return -1; } + mark_as_dependent(thd, last, thd->lex->current_select, + this); + ref= last->ref_pointer_array + counter; } else if (!ref) return 1; @@ -2121,7 +2163,6 @@ bool Item_default_value::fix_fields(THD *thd, def_field->move_field(def_field->table->default_values - def_field->table->record[0]); set_field(def_field); - fixed= 1; return 0; } @@ -2179,7 +2220,6 @@ bool Item_insert_value::fix_fields(THD *thd, set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name, tmp_field->table, &my_charset_bin)); } - fixed= 1; return 0; } @@ -2523,12 +2563,13 @@ bool Item_type_holder::join_types(THD *thd, Item *item) uint32 new_length= real_length(item); bool use_new_field= 0, use_expression_type= 0; Item_result new_result_type= type_convertor[item_type][item->result_type()]; + bool item_is_a_field= item->type() == Item::FIELD_ITEM; /* Check if both items point to fields: in this case we can adjust column types of result table in the union smartly. */ - if (field_example && item->type() == Item::FIELD_ITEM) + if (field_example && item_is_a_field) { Field *field= ((Item_field *)item)->field; /* Can 'field_example' field store data of the column? */ @@ -2545,23 +2586,25 @@ bool Item_type_holder::join_types(THD *thd, Item *item) !is_attr_compatible(this, item)); } } - else if (field_example || item->type() == Item::FIELD_ITEM) + else if (field_example || item_is_a_field) { /* Expression types can't be mixed with field types, we have to use expression types. */ + use_new_field= 1; // make next if test easier use_expression_type= 1; } /* Check whether size/type of the result item should be changed */ - if (use_new_field || use_expression_type || + if (use_new_field || (new_result_type != item_type) || (new_length > max_length) || (!maybe_null && item->maybe_null) || - (item_type == STRING_RESULT && - !my_charset_same(collation.collation, item->collation.collation))) + (item_type == STRING_RESULT && + collation.collation != item->collation.collation)) { - if (use_expression_type || item->type() != Item::FIELD_ITEM) + const char *old_cs,*old_derivation; + if (use_expression_type || !item_is_a_field) field_example= 0; else { @@ -2572,8 +2615,8 @@ bool Item_type_holder::join_types(THD *thd, Item *item) field_example= ((Item_field*) item)->field; } - const char *old_cs= collation.collation->name, - *old_derivation= collation.derivation_name(); + old_cs= collation.collation->name; + old_derivation= collation.derivation_name(); if (item_type == STRING_RESULT && collation.aggregate(item->collation)) { my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), @@ -2593,12 +2636,12 @@ bool Item_type_holder::join_types(THD *thd, Item *item) return 0; } + uint32 Item_type_holder::real_length(Item *item) { if (item->type() == Item::FIELD_ITEM) - { return ((Item_field *)item)->max_disp_length(); - } + switch (item->result_type()) { case STRING_RESULT: diff --git a/sql/item.h b/sql/item.h index 68fa013647c..116dc86390c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -310,6 +310,7 @@ public: class st_select_lex; class Item_ident :public Item { +protected: /* We have to store initial values of db_name, table_name and field_name to be able to restore them during cleanup() because they can be @@ -356,13 +357,21 @@ public: :Item_ident(db_par,table_name_par,field_name_par), field(0), result_field(0) { collation.set(DERIVATION_IMPLICIT); } - // Constructor need to process subselect with temporary tables (see Item) + /* + Constructor needed to process subselect with temporary tables (see Item) + */ Item_field(THD *thd, Item_field *item); /* - Constructor used inside setup_wild(), ensures that field and table - names will live as long as Item_field (important in prep. stmt.) + Constructor used inside setup_wild(), ensures that field, table, + and database names will live as long as Item_field (this is important + in prepared statements). */ Item_field(THD *thd, Field *field); + /* + If this constructor is used, fix_fields() won't work, because + db_name, table_name and column_name are unknown. It's necessary to call + reset_field() before fix_fields() for all fields created this way. + */ Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; @@ -373,6 +382,7 @@ public: longlong val_int_result(); String *str_result(String* tmp); bool send(Protocol *protocol, String *str_arg); + void reset_field(Field *f); bool fix_fields(THD *, struct st_table_list *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 248b56fe064..f6730c84979 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -859,6 +859,10 @@ void Item_func_between::fix_length_and_dec() Field *field=((Item_field*) args[0])->field; if (field->can_be_compared_as_longlong()) { + /* + The following can't be recoded with || as convert_constant_item + changes the argument + */ if (convert_constant_item(thd, field,&args[1])) cmp_type=INT_RESULT; // Works for all types. if (convert_constant_item(thd, field,&args[2])) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index dcc32441e88..69528099aa1 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -845,7 +845,7 @@ public: char escape; Item_func_like(Item *a,Item *b, Item *escape_arg) - :Item_bool_func2(a,b), canDoTurboBM(false), pattern(0), pattern_len(0), + :Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), bmGs(0), bmBc(0), escape_item(escape_arg) {} longlong val_int(); enum Functype functype() const { return LIKE_FUNC; } diff --git a/sql/item_func.cc b/sql/item_func.cc index f20d69bf2ad..17cf8642ce5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -651,11 +651,11 @@ void Item_func_int_div::fix_length_and_dec() double Item_func_mod::val() { DBUG_ASSERT(fixed == 1); - double value= floor(args[0]->val()+0.5); - double val2=floor(args[1]->val()+0.5); - if ((null_value=val2 == 0.0 || args[0]->null_value || args[1]->null_value)) + double x= args[0]->val(); + double y= args[1]->val(); + if ((null_value= (y == 0.0) || args[0]->null_value || args[1]->null_value)) return 0.0; /* purecov: inspected */ - return fmod(value,val2); + return fmod(x, y); } longlong Item_func_mod::val_int() @@ -670,10 +670,7 @@ longlong Item_func_mod::val_int() void Item_func_mod::fix_length_and_dec() { - max_length=args[1]->max_length; - decimals=0; - maybe_null=1; - find_num_type(); + Item_num_op::fix_length_and_dec(); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 301836fa839..d78a3ac88a4 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2709,41 +2709,40 @@ longlong Item_func_crc32::val_int() String *Item_func_compress::val_str(String *str) { + int err= Z_OK, code; + ulong new_size; + String *res; + Byte *body; + char *tmp, *last_char; DBUG_ASSERT(fixed == 1); - String *res= args[0]->val_str(str); - if (!res) + + if (!(res= args[0]->val_str(str))) { null_value= 1; return 0; } if (res->is_empty()) return res; - int err= Z_OK; - int code; - /* - citation from zlib.h (comment for compress function): + Citation from zlib.h (comment for compress function): Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least 0.1% larger than - sourceLen plus 12 bytes. - - Proportion 120/100 founded by Sinisa with help of procedure - compress(compress(compress(...))) - I.e. zlib give number 'at least'.. + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. + We assume here that the buffer can't grow more than .25 %. */ - ulong new_size= res->length() + res->length() / 5 + 12; + new_size= res->length() + res->length() / 5 + 12; - // Will check new_size overflow: new_size <= res->length() - if (((uint32) new_size <= res->length()) || + // Check new_size overflow: new_size <= res->length() + if (((uint32) (new_size+5) <= res->length()) || buffer.realloc((uint32) new_size + 4 + 1)) { null_value= 1; return 0; } - Byte *body= ((Byte*)buffer.ptr()) + 4; + body= ((Byte*)buffer.ptr()) + 4; // As far as we have checked res->is_empty() we can use ptr() if ((err= compress(body, &new_size, @@ -2755,11 +2754,11 @@ String *Item_func_compress::val_str(String *str) return 0; } - char *tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects + tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects int4store(tmp, res->length() & 0x3FFFFFFF); - /* This is for the stupid char fields which trim ' ': */ - char *last_char= ((char*)body)+new_size-1; + /* This is to ensure that things works for CHAR fields, which trim ' ': */ + last_char= ((char*)body)+new_size-1; if (*last_char == ' ') { *++last_char= '.'; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 863b041044e..48c1f2c5443 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1292,14 +1292,13 @@ String *Item_func_curtime::val_str(String *str) void Item_func_curtime::fix_length_and_dec() { TIME ltime; - String tmp((char*) buff,sizeof(buff), &my_charset_bin); decimals=0; collation.set(&my_charset_bin); store_now_in_TIME(<ime); value= TIME_to_ulonglong_time(<ime); - make_time((DATE_TIME_FORMAT *) 0, <ime, &tmp); - max_length= buff_length= tmp.length(); + buff_length= (uint) my_time_to_str(<ime, buff); + max_length= buff_length; } @@ -1341,16 +1340,14 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - decimals=0; collation.set(&my_charset_bin); store_now_in_TIME(<ime); value= (longlong) TIME_to_ulonglong_datetime(<ime); - make_datetime((DATE_TIME_FORMAT *) 0, <ime, &tmp); - max_length= buff_length= tmp.length(); + buff_length= (uint) my_datetime_to_str(<ime, buff); + max_length= buff_length; } diff --git a/sql/lock.cc b/sql/lock.cc index 215059b8a46..646babea6a1 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -792,9 +792,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, { if (thd->global_read_lock) // This thread had the read locks { - my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); + if (is_not_commit) + my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); (void) pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(1); + /* + We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does. + This allowance is needed to not break existing versions of innobackup + which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT. + */ + DBUG_RETURN(is_not_commit); } old_message=thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for release of readlock"); diff --git a/sql/log_event.h b/sql/log_event.h index 28d1f44df92..8070c334d8b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -571,7 +571,7 @@ public: { fname= afname; fname_len= alen; - local_fname= true; + local_fname= TRUE; } /* fname doesn't point to memory inside Log_event::temp_buf */ int check_fname_outside_temp_buf() diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1a0879c6347..391199942e0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -284,14 +284,6 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define WEEK_MONDAY_FIRST 1 #define WEEK_YEAR 2 #define WEEK_FIRST_WEEKDAY 4 -/* - Required buffer length for make_date, make_time, make_datetime - and TIME_to_string functions. Note, that the caller is still - responsible to check that given TIME structure has values - in valid ranges, otherwise size of the buffer could be not - enough. -*/ -#define MAX_DATE_REP_LENGTH 30 enum enum_parsing_place { @@ -374,7 +366,7 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); int insert_select_precheck(THD *thd, TABLE_LIST *tables); int update_precheck(THD *thd, TABLE_LIST *tables); int delete_precheck(THD *thd, TABLE_LIST *tables); -int insert_precheck(THD *thd, TABLE_LIST *tables, bool update); +int insert_precheck(THD *thd, TABLE_LIST *tables); int create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); Item *negate_expression(THD *thd, Item *expr); @@ -897,7 +889,7 @@ extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern uint delay_key_write_options, lower_case_table_names; extern bool opt_endinfo, using_udf_functions, locked_in_memory; -extern bool opt_using_transactions, mysql_embedded; +extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; extern bool opt_disable_networking, opt_skip_show_db; @@ -1046,7 +1038,6 @@ void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time, String *str); void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time, String *str); -void TIME_to_string(const TIME *time, String *str); ulonglong TIME_to_ulonglong_datetime(const TIME *time); ulonglong TIME_to_ulonglong_date(const TIME *time); ulonglong TIME_to_ulonglong_time(const TIME *time); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d7d0f637ec2..384f76029f9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -449,9 +449,9 @@ pthread_cond_t eventShutdown; #endif #ifndef EMBEDDED_LIBRARY -bool mysql_embedded=0; +bool mysqld_embedded=0; #else -bool mysql_embedded=1; +bool mysqld_embedded=1; #endif #ifndef DBUG_OFF @@ -4012,6 +4012,7 @@ enum options_mysqld OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_STATUS_FILE, OPT_INNODB_MAX_DIRTY_PAGES_PCT, + OPT_INNODB_TABLE_LOCKS, OPT_INNODB_OPEN_FILES, OPT_INNODB_AUTOEXTEND_INCREMENT, OPT_BDB_CACHE_SIZE, @@ -4250,6 +4251,11 @@ Disable with --skip-innodb (will save memory).", "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file", (gptr*) &innobase_create_status_file, (gptr*) &innobase_create_status_file, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"innodb_table_locks", OPT_INNODB_TABLE_LOCKS, + "If Innodb should enforce LOCK TABLE", + (gptr*) &global_system_variables.innodb_table_locks, + (gptr*) &global_system_variables.innodb_table_locks, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \ Disable with --skip-isam.", @@ -4812,7 +4818,7 @@ replicating a LOAD DATA INFILE command.", (gptr*) &dflt_key_cache_var.param_buff_size, (gptr*) 0, 0, (GET_ULL | GET_ASK_ADDR), - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9c5b0235767..541acc69ec7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -393,7 +393,7 @@ SQL_SELECT::~SQL_SELECT() #undef index // Fix for Unixware 7 QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc) - :dont_free(0),error(0),index(key_nr),max_used_key_length(0), + :dont_free(0),sorted(0),error(0),index(key_nr),max_used_key_length(0), used_key_parts(0), head(table), it(ranges),range(0) { if (!no_alloc) diff --git a/sql/protocol.cc b/sql/protocol.cc index c2d9117b062..060dc14be10 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -880,10 +880,9 @@ bool Protocol_simple::store_date(TIME *tm) field_types[field_pos] == MYSQL_TYPE_DATE); field_pos++; #endif - char buff[40]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - make_date((DATE_TIME_FORMAT *) 0, tm, &tmp); - return net_store_data((char*) tmp.ptr(), tmp.length()); + char buff[MAX_DATE_STRING_REP_LENGTH]; + int length= my_date_to_str(tm, buff); + return net_store_data(buff, (uint) length); } diff --git a/sql/set_var.cc b/sql/set_var.cc index d661470576b..b5e479b9985 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -351,6 +351,8 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); +sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", + &SV::innodb_table_locks); sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", &srv_auto_extend_increment); sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag", @@ -605,6 +607,7 @@ sys_var *sys_variables[]= &sys_os, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, + &sys_innodb_table_locks, &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, #endif @@ -700,6 +703,7 @@ struct show_var_st init_vars[]= { {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, + {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG }, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fc252c1f5ac..b7eecac4e48 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2398,7 +2398,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, table_list->db, table_list->real_name, rights, column_priv, revoke_grant)) - { // Crashend table ?? + { + /* Should only happen if table is crashed */ result= -1; /* purecov: deadcode */ } else if (tables[2].table) @@ -3636,12 +3637,17 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list) if (!strcmp(lex_user->user.str,user) && !my_strcasecmp(system_charset_info, lex_user->host.str, host)) { - if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1)) - result= -1; - else + if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1)) + { + /* + Don't increment counter as replace_db_table deleted the + current element in acl_db's and shifted the higher elements down + */ continue; + } + result= -1; // Something went wrong } - ++counter; + counter++; } /* Remove column access */ @@ -3664,26 +3670,27 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list) ~0, 0, 1)) { result= -1; + continue; } else { - if (grant_table->cols) - { - List<LEX_COLUMN> columns; - if (replace_column_table(grant_table,tables[3].table, *lex_user, - columns, - grant_table->db, - grant_table->tname, - ~0, 1)) - result= -1; - else - continue; - } - else - continue; + if (!grant_table->cols) + continue; + List<LEX_COLUMN> columns; + if (replace_column_table(grant_table,tables[3].table, *lex_user, + columns, + grant_table->db, + grant_table->tname, + ~0, 1)) + result= -1; + /* + Safer to do continue here as replace_table_table changed + column_priv_hash and we want to test the current element + */ + continue; } } - ++counter; + counter++; } } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 31b2ab9ea89..cd7b643e146 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -818,6 +818,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->query_id=thd->query_id; table->clear_query_id=1; thd->tmp_table_used= 1; + DBUG_PRINT("info",("Using temporary table")); goto reset; } } @@ -832,6 +833,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->query_id != thd->query_id) { table->query_id=thd->query_id; + DBUG_PRINT("info",("Using locked table")); goto reset; } } @@ -1368,7 +1370,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, */ if (discover_retry_count++ != 0) goto err; - if (ha_create_table_from_engine(thd, db, name, true) != 0) + if (ha_create_table_from_engine(thd, db, name, TRUE) != 0) goto err; thd->clear_error(); // Clear error message @@ -2653,8 +2655,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) strlen(t1_field_name), 0, 0, ¬_used_field_index))) { - Item_func_eq *tmp=new Item_func_eq(new Item_field(*t1_field), - new Item_field(t2_field)); + Item_func_eq *tmp=new Item_func_eq(new Item_field(thd, *t1_field), + new Item_field(thd, t2_field)); if (!tmp) goto err; /* Mark field used for table cache */ @@ -2846,8 +2848,15 @@ void flush_tables() /* -** Mark all entries with the table as deleted to force an reopen of the table -** Returns true if the table is in use by another thread + Mark all entries with the table as deleted to force an reopen of the table + + The table will be closed (not stored in cache) by the current thread when + close_thread_tables() is called. + + RETURN + 0 This thread now have exclusive access to this table and no other thread + can access the table until close_thread_tables() is called. + 1 Table is in use by another thread */ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, diff --git a/sql/sql_class.h b/sql/sql_class.h index aea31f7db54..e73b35966a9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -396,6 +396,9 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; my_bool query_cache_wlock_invalidate; +#ifdef HAVE_INNOBASE_DB + my_bool innodb_table_locks; +#endif /* HAVE_INNOBASE_DB */ my_bool old_passwords; /* Only charset part of these variables is sensible */ @@ -461,6 +464,8 @@ public: inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } + inline bool is_stmt_execute() const + { return state == PREPARED || state == EXECUTED; } inline bool is_conventional_execution() const { return state == CONVENTIONAL_EXECUTION; } inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); } @@ -1109,6 +1114,13 @@ public: unit= u; return 0; } + /* + Because of peculiarities of prepared statements protocol + we need to know number of columns in the result set (if + there is a result set) apart from sending columns metadata. + */ + virtual uint field_count(List<Item> &fields) const + { return fields.elements; } virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_data(List<Item> &items)=0; virtual bool initialize_tables (JOIN *join=0) { return 0; } @@ -1123,6 +1135,20 @@ public: }; +/* + Base class for select_result descendands which intercept and + transform result set rows. As the rows are not sent to the client, + sending of result set metadata should be suppressed as well. +*/ + +class select_result_interceptor: public select_result +{ +public: + uint field_count(List<Item> &fields) const { return 0; } + bool send_fields(List<Item> &fields, uint flag) { return FALSE; } +}; + + class select_send :public select_result { public: select_send() {} @@ -1132,7 +1158,7 @@ public: }; -class select_to_file :public select_result { +class select_to_file :public select_result_interceptor { protected: sql_exchange *exchange; File file; @@ -1144,7 +1170,6 @@ public: select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); - bool send_fields(List<Item> &list, uint flag) { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); void cleanup(); @@ -1171,7 +1196,7 @@ public: }; -class select_insert :public select_result { +class select_insert :public select_result_interceptor { public: TABLE *table; List<Item> *fields; @@ -1187,8 +1212,6 @@ class select_insert :public select_result { } ~select_insert(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flag) - { return 0; } bool send_data(List<Item> &items); void send_error(uint errcode,const char *err); bool send_eof(); @@ -1271,7 +1294,7 @@ public: } }; -class select_union :public select_result { +class select_union :public select_result_interceptor { public: TABLE *table; COPY_INFO info; @@ -1280,8 +1303,6 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flag) - { return 0; } bool send_data(List<Item> &items); bool send_eof(); bool flush(); @@ -1289,13 +1310,12 @@ class select_union :public select_result { }; /* Base subselect interface class */ -class select_subselect :public select_result +class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: select_subselect(Item_subselect *item); - bool send_fields(List<Item> &list, uint flag) { return 0; }; bool send_data(List<Item> &items)=0; bool send_eof() { return 0; }; }; @@ -1432,7 +1452,7 @@ public: }; -class multi_delete :public select_result +class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; @@ -1445,8 +1465,6 @@ public: multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, - uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); @@ -1455,7 +1473,7 @@ public: }; -class multi_update :public select_result +class multi_update :public select_result_interceptor { TABLE_LIST *all_tables, *update_tables, *table_being_updated; THD *thd; @@ -1474,7 +1492,6 @@ public: List<Item> *values, enum_duplicates handle_duplicates); ~multi_update(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); @@ -1483,7 +1500,7 @@ public: }; -class select_dumpvar :public select_result { +class select_dumpvar :public select_result_interceptor { ha_rows row_count; public: List<LEX_STRING> var_list; @@ -1491,7 +1508,6 @@ public: select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;} ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flag) {return 0;} bool send_data(List<Item> &items); bool send_eof(); void cleanup(); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index eabe66d33bf..ffaaafc26e6 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -746,7 +746,7 @@ int mysqld_help(THD *thd, const char *mask) select,&subcategories_list); delete select; String *cat= categories_list.head(); - if (send_header_2(protocol, true) || + if (send_header_2(protocol, TRUE) || send_variant_2_list(mem_root,protocol,&topics_list, "N",cat) || send_variant_2_list(mem_root,protocol,&subcategories_list,"Y",cat)) goto end; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 856742d13bc..679ffb2140e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -477,7 +477,6 @@ inline static uint int_token(const char *str,uint length) int yylex(void *arg, void *yythd) { reg1 uchar c; - bool space_ignored; int tokval, result_state; uint length; enum my_lex_states state; @@ -560,6 +559,7 @@ int yylex(void *arg, void *yythd) /* Fall through */ case MY_LEX_IDENT_OR_BIN: // TODO: Add binary string handling case MY_LEX_IDENT: + uchar *start; #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { @@ -596,12 +596,16 @@ int yylex(void *arg, void *yythd) result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT; } length= (uint) (lex->ptr - lex->tok_start)-1; - space_ignored= FALSE; + start= lex->ptr; if (lex->ignore_space) { - for (; state_map[c] == MY_LEX_SKIP ; space_ignored= TRUE, c= yyGet()); + /* + If we find a space then this can't be an identifier. We notice this + below by checking start != lex->ptr. + */ + for (; state_map[c] == MY_LEX_SKIP ; c= yyGet()); } - if (! space_ignored && c == '.' && ident_map[yyPeek()]) + if (start == lex->ptr && c == '.' && ident_map[yyPeek()]) lex->next_state=MY_LEX_IDENT_SEP; else { // '(' must follow directly if function diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e7a013e19ea..8279e32c8de 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -501,12 +501,17 @@ void free_max_user_conn(void) /* Mark all commands that somehow changes a table This is used to check number of updates / hour + + sql_command is actually set to SQLCOM_END sometimes + so we need the +1 to include it in the array. */ -char uc_update_queries[SQLCOM_END]; +char uc_update_queries[SQLCOM_END+1]; void init_update_queries(void) { + bzero((gptr) &uc_update_queries, sizeof(uc_update_queries)); + uc_update_queries[SQLCOM_CREATE_TABLE]=1; uc_update_queries[SQLCOM_CREATE_INDEX]=1; uc_update_queries[SQLCOM_ALTER_TABLE]=1; @@ -531,6 +536,7 @@ void init_update_queries(void) bool is_update_query(enum enum_sql_command command) { + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); return uc_update_queries[command]; } @@ -894,7 +900,7 @@ static int check_connection(THD *thd) x_free(thd->user); if (!(thd->user= my_strdup(user, MYF(0)))) return (ER_OUT_OF_RESOURCES); - return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true); + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); } @@ -2682,12 +2688,11 @@ unsent_create_error: case SQLCOM_REPLACE: case SQLCOM_INSERT: { - my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0); - if ((res= insert_precheck(thd, tables, update))) + if ((res= insert_precheck(thd, tables))) break; res = mysql_insert(thd,tables,lex->field_list,lex->many_values, select_lex->item_list, lex->value_list, - (update ? DUP_UPDATE : lex->duplicates)); + lex->duplicates); if (thd->net.report_error) res= -1; break; @@ -4767,7 +4772,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, acl_reload(thd); grant_reload(thd); if (mqh_used) - reset_mqh(thd,(LEX_USER *) NULL,true); + reset_mqh(thd,(LEX_USER *) NULL,TRUE); } #endif if (options & REFRESH_LOG) @@ -5366,13 +5371,14 @@ int delete_precheck(THD *thd, TABLE_LIST *tables) -1 error (message is not sent to user) */ -int insert_precheck(THD *thd, TABLE_LIST *tables, bool update) +int insert_precheck(THD *thd, TABLE_LIST *tables) { LEX *lex= thd->lex; DBUG_ENTER("insert_precheck"); - ulong privilege= (lex->duplicates == DUP_REPLACE ? - INSERT_ACL | DELETE_ACL : INSERT_ACL | update); + ulong privilege= INSERT_ACL | + (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) | + (lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0); if (check_one_table_access(thd, privilege, tables)) DBUG_RETURN(1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 27d98fdfeba..12f526c5566 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -895,10 +895,9 @@ static int mysql_test_insert(Prepared_statement *stmt, int res= -1; TABLE_LIST *insert_table_list= (TABLE_LIST*) lex->select_lex.table_list.first; - my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0); DBUG_ENTER("mysql_test_insert"); - if ((res= insert_precheck(thd, table_list, update))) + if ((res= insert_precheck(thd, table_list))) DBUG_RETURN(res); /* @@ -1065,6 +1064,12 @@ static int mysql_test_select(Prepared_statement *stmt, DBUG_RETURN(1); #endif + if (!lex->result && !(lex->result= new (&stmt->mem_root) select_send)) + { + send_error(thd); + goto err; + } + if (open_and_lock_tables(thd, tables)) { send_error(thd); @@ -1088,8 +1093,13 @@ static int mysql_test_select(Prepared_statement *stmt, } else { - if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) || - thd->protocol_simple.send_fields(&lex->select_lex.item_list, 0) + List<Item> &fields= lex->select_lex.item_list; + /* + We can use lex->result as it should've been + prepared in unit->prepare call above. + */ + if (send_prep_stmt(stmt, lex->result->field_count(fields)) || + lex->result->send_fields(fields, 0) #ifndef EMBEDDED_LIBRARY || net_flush(&thd->net) #endif @@ -1388,8 +1398,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) res= mysql_test_insert(stmt, tables, lex->field_list, lex->many_values, select_lex->item_list, lex->value_list, - (lex->value_list.elements ? - DUP_UPDATE : lex->duplicates)); + lex->duplicates); break; case SQLCOM_UPDATE: @@ -1781,7 +1790,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) goto set_params_data_err; #endif thd->protocol= &thd->protocol_prep; // Switch to binary protocol - execute_stmt(thd, stmt, &expanded_query, true); + execute_stmt(thd, stmt, &expanded_query, TRUE); thd->protocol= &thd->protocol_simple; // Use normal protocol DBUG_VOID_RETURN; @@ -1834,7 +1843,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); send_error(thd); } - execute_stmt(thd, stmt, &expanded_query, false); + execute_stmt(thd, stmt, &expanded_query, FALSE); DBUG_VOID_RETURN; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 638ed229a70..df74a946b5c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6911,10 +6911,23 @@ part_of_refkey(TABLE *table,Field *field) /***************************************************************************** Test if one can use the key to resolve ORDER BY - Returns: 1 if key is ok. - 0 if key can't be used - -1 if reverse key can be used - used_key_parts is set to key parts used if length != 0 + + SYNOPSIS + test_if_order_by_key() + order Sort order + table Table to sort + idx Index to check + used_key_parts Return value for used key parts. + + + NOTES + used_key_parts is set to correct key parts used if return value != 0 + (On other cases, used_key_part may be changed) + + RETURN + 1 key is ok. + 0 Key can't be used + -1 Reverse key can be used *****************************************************************************/ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, @@ -6943,16 +6956,17 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, DBUG_RETURN(0); /* set flag to 1 if we can use read-next on key, else to -1 */ - flag= ((order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT)) ? 1 : -1); + flag= ((order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT)) ? + 1 : -1); if (reverse && flag != reverse) DBUG_RETURN(0); reverse=flag; // Remember if reverse key_part++; } - uint tmp= (uint) (key_part - table->key_info[idx].key_part); - if (reverse == -1 && !(table->file->index_flags(idx,tmp-1, 1) & HA_READ_PREV)) - DBUG_RETURN(0); - *used_key_parts= tmp; + *used_key_parts= (uint) (key_part - table->key_info[idx].key_part); + if (reverse == -1 && !(table->file->index_flags(idx, *used_key_parts-1, 1) & + HA_READ_PREV)) + reverse= 0; // Index can't be used DBUG_RETURN(reverse); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c5cd2860e03..e030db2caf7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1136,7 +1136,7 @@ static const char *require_quotes(const char *name, uint name_length) for ( ; name < end ; name++) { uchar chr= (uchar) *name; - length= my_mbcharlen(system_charset_info, (uchar) chr); + length= my_mbcharlen(system_charset_info, chr); if (length == 1 && !system_charset_info->ident_map[chr]) return name; } @@ -1148,25 +1148,29 @@ void append_identifier(THD *thd, String *packet, const char *name, uint length) { const char *name_end; + char quote_char; int q= get_quote_char_for_identifier(thd, name, length); - if (q == EOF) { + if (q == EOF) + { packet->append(name, length, system_charset_info); return; } - char quote_char= q; - - /* The identifier must be quoted as it includes a quote character */ + /* + The identifier must be quoted as it includes a quote character or + it's a keyword + */ packet->reserve(length*2 + 2); + quote_char= (char) q; packet->append("e_char, 1, system_charset_info); for (name_end= name+length ; name < name_end ; name+= length) { - char chr= *name; - length= my_mbcharlen(system_charset_info, (uchar) chr); - if (length == 1 && chr == quote_char) + uchar chr= (uchar) *name; + length= my_mbcharlen(system_charset_info, chr); + if (length == 1 && chr == (uchar) quote_char) packet->append("e_char, 1, system_charset_info); packet->append(name, length, packet->charset()); } @@ -1174,8 +1178,25 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) } -/* Get the quote character for displaying an identifier. - If no quote character is needed, return EOF. */ +/* + Get the quote character for displaying an identifier. + + SYNOPSIS + get_quote_char_for_identifier() + thd Thread handler + name name to quote + length length of name + + IMPLEMENTATION + If name is a keyword or includes a special character, then force + quoting. + Otherwise identifier is quoted only if the option OPTION_QUOTE_SHOW_CREATE + is set. + + RETURN + EOF No quote character is needed + # Quote character +*/ int get_quote_char_for_identifier(THD *thd, const char *name, uint length) { @@ -1183,10 +1204,9 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length) !require_quotes(name, length) && !(thd->options & OPTION_QUOTE_SHOW_CREATE)) return EOF; - else if (thd->variables.sql_mode & MODE_ANSI_QUOTES) + if (thd->variables.sql_mode & MODE_ANSI_QUOTES) return '"'; - else - return '`'; + return '`'; } @@ -1195,10 +1215,9 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length) static void append_directory(THD *thd, String *packet, const char *dir_type, const char *filename) { - uint length; if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) { - length= dirname_length(filename); + uint length= dirname_length(filename); packet->append(' '); packet->append(dir_type); packet->append(" DIRECTORY='", 12); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 1ec0faafa8f..1044dc4e58e 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -537,7 +537,8 @@ uint32 String::numchars() int String::charpos(int i,uint32 offset) { - if (i<0) return i; + if (i <= 0) + return i; return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 65e23c7ba1d..d2de24b0d2a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -223,7 +223,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, (void) unpack_filename(path,path); } if (drop_temporary || - (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,true))) + (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,TRUE))) { if (if_exists) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index b46cfc05538..44004e1238d 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -264,9 +264,27 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - // it is not single select if (first_select->next_select()) { + /* This is not a single select */ + + /* + Check that it was possible to aggregate + all collations together for UNION. + */ + List_iterator_fast<Item> tp(types); + Item_arena *arena= thd->current_arena; + Item *type; + while ((type= tp++)) + { + if (type->result_type() == STRING_RESULT && + type->collation.derivation == DERIVATION_NONE) + { + my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION"); + goto err; + } + } + union_result->tmp_table_param.field_count= types.elements; if (!(table= create_tmp_table(thd_arg, &union_result->tmp_table_param, types, @@ -287,7 +305,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, thd_arg->lex->current_select= lex_select_save; if (!item_list.elements) { - Item_arena *arena= thd->current_arena, backup; + /* + We're in statement prepare or in execution + of a conventional statement. + */ + Item_arena backup; if (arena->is_stmt_prepare()) thd->set_n_backup_item_arena(arena, &backup); Field **field; @@ -327,6 +349,20 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, fake_select_lex->table_list.empty(); } } + else if (arena->is_stmt_execute()) + { + /* + We're in execution of a prepared statement: reset field items + to point at fields from the created temporary table. + */ + List_iterator_fast<Item> it(item_list); + for (Field **field= table->field; *field; field++) + { + Item_field *item_field= (Item_field*) it++; + DBUG_ASSERT(item_field); + item_field->reset_field(*field); + } + } } else first_select->braces= 0; // remove our changes diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c1513dd55e2..426f6d4d057 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -843,14 +843,14 @@ prepare_src: THD *thd=YYTHD; LEX *lex= thd->lex; lex->prepared_stmt_code= $1; - lex->prepared_stmt_code_is_varref= false; + lex->prepared_stmt_code_is_varref= FALSE; } | '@' ident_or_text { THD *thd=YYTHD; LEX *lex= thd->lex; lex->prepared_stmt_code= $2; - lex->prepared_stmt_code_is_varref= true; + lex->prepared_stmt_code_is_varref= TRUE; }; execute: @@ -4136,14 +4136,18 @@ expr_or_default: opt_insert_update: /* empty */ | ON DUPLICATE_SYM - { /* for simplisity, let's forget about - INSERT ... SELECT ... UPDATE - for a moment */ - if (Lex->sql_command != SQLCOM_INSERT) + { + LEX *lex= Lex; + /* + For simplicity, let's forget about INSERT ... SELECT ... UPDATE + for a moment. + */ + if (lex->sql_command != SQLCOM_INSERT) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + lex->duplicates= DUP_UPDATE; } KEY_SYM UPDATE_SYM update_list ; diff --git a/sql/table.h b/sql/table.h index f25b172a0d9..2eb854f553d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -164,6 +164,7 @@ struct st_table { MEM_ROOT mem_root; GRANT_INFO grant; + /* A pair "database_name\0table_name\0", widely used as simply a db name */ char *table_cache_key; char *table_name,*real_name,*path; uint key_length; /* Length of key */ diff --git a/sql/time.cc b/sql/time.cc index 4421b6aa00f..e76b169b336 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -747,13 +747,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), const TIME *l_time, String *str) { - long length= my_sprintf((char*) str->ptr(), - ((char*) str->ptr(), - "%s%02d:%02d:%02d", - (l_time->neg ? "-" : ""), - l_time->hour, - l_time->minute, - l_time->second)); + uint length= (uint) my_time_to_str(l_time, (char*) str->ptr()); str->length(length); str->set_charset(&my_charset_bin); } @@ -762,12 +756,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)), void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)), const TIME *l_time, String *str) { - long length= my_sprintf((char*) str->ptr(), - ((char*) str->ptr(), - "%04d-%02d-%02d", - l_time->year, - l_time->month, - l_time->day)); + uint length= (uint) my_date_to_str(l_time, (char*) str->ptr()); str->length(length); str->set_charset(&my_charset_bin); } @@ -776,15 +765,7 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)), void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)), const TIME *l_time, String *str) { - long length= my_sprintf((char*) str->ptr(), - ((char*) str->ptr(), - "%04d-%02d-%02d %02d:%02d:%02d", - l_time->year, - l_time->month, - l_time->day, - l_time->hour, - l_time->minute, - l_time->second)); + uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr()); str->length(length); str->set_charset(&my_charset_bin); } @@ -894,38 +875,4 @@ ulonglong TIME_to_ulonglong(const TIME *time) return 0; } - -/* - Convert struct DATE/TIME/DATETIME value to string using built-in - MySQL time conversion formats. - - SYNOPSIS - TIME_to_string() - - NOTE - The string must have at least MAX_DATE_REP_LENGTH bytes reserved. -*/ - -void TIME_to_string(const TIME *time, String *str) -{ - switch (time->time_type) { - case MYSQL_TIMESTAMP_DATETIME: - make_datetime((DATE_TIME_FORMAT*) 0, time, str); - break; - case MYSQL_TIMESTAMP_DATE: - make_date((DATE_TIME_FORMAT*) 0, time, str); - break; - case MYSQL_TIMESTAMP_TIME: - make_time((DATE_TIME_FORMAT*) 0, time, str); - break; - case MYSQL_TIMESTAMP_NONE: - case MYSQL_TIMESTAMP_ERROR: - str->length(0); - str->set_charset(&my_charset_bin); - break; - default: - DBUG_ASSERT(0); - } -} - #endif diff --git a/strings/CHARSET_INFO.txt b/strings/CHARSET_INFO.txt new file mode 100644 index 00000000000..f7a10f95880 --- /dev/null +++ b/strings/CHARSET_INFO.txt @@ -0,0 +1,230 @@ + +CHARSET_INFO +============ +A structure containing data for charset+collation pair implementation. + +Virtual functions which use this data are collected +into separate structures MY_CHARSET_HANDLER and +MY_COLLATION_HANDLER. + + +typedef struct charset_info_st +{ + uint number; + uint primary_number; + uint binary_number; + uint state; + + const char *csname; + const char *name; + const char *comment; + + uchar *ctype; + uchar *to_lower; + uchar *to_upper; + uchar *sort_order; + + uint16 *tab_to_uni; + MY_UNI_IDX *tab_from_uni; + + uchar state_map[256]; + uchar ident_map[256]; + + uint strxfrm_multiply; + uint mbminlen; + uint mbmaxlen; + char max_sort_char; /* For LIKE optimization */ + + MY_CHARSET_HANDLER *cset; + MY_COLLATION_HANDLER *coll; + +} CHARSET_INFO; + + +CHARSET_INFO fields description: +=============================== + + +Numbers (identifiers) +--------------------- + +number - an ID uniquely identifying this charset+collation pair. + +primary_number - ID of a charset+collation pair, which consists +of the same character set and the default collation of this +character set. Not really used now. Intended to optimize some +parts of the code where we need to find the default collation +using its non-default counterpart for the given character set. + +binary_numner - ID of a charset+collation pair, which consists +of the same character set and the binary collation of this +character set. Not really used now. + +Names +----- + + csname - name of the character set for this charset+collation pair. + name - name of the collation for this charset+collation pair. + comment - a text comment, dysplayed in "Description" column of + SHOW CHARACTER SET output. + +Conversion tables +----------------- + + ctype - pointer to array[257] of "type of characters" + bit mask for each chatacter, e.g. if a + character is a digit or a letter or a separator, etc. + + Monty 2004-10-21: + If you look at the macros, we use ctype[(char)+1]. + ctype[0] is traditionally in most ctype libraries + reserved for EOF (-1). The idea is that you can use + the result from fgetc() directly with ctype[]. As + we have to be compatible with external ctype[] versions, + it's better to do it the same way as they do... + + to_lower - pointer to array[256] used in LCASE() + to_upper - pointer to array[256] used in UCASE() + sort_order - pointer to array[256] used for strings comparison + + + +Unicode conversion data +----------------------- +For 8bit character sets: + +tab_to_uni : array[256] of charset->Unicode translation +tab_from_uni: a structure for Unicode->charset translation + +Non-8 bit charsets have their own structures per charset +hidden in correspondent ctype-xxx.c file and don't use +tab_to_uni and tab_from_uni tables. + + +Parser maps +----------- +state_map[] +ident_map[] + + These maps are to quickly identify if a character is +an identificator part, a digit, a special character, +or a part of other SQL language lexical item. + +Probably can be combined with ctype array in the future. +But for some reasons these two arrays are used in the parser, +while a separate ctype[] array is used in the other part of the +code, like fulltext, etc. + + +Misc fields +----------- + + strxfrm_multiply - how many times a sort key (i.e. a string + which can be passed into memcmp() for comparison) + can be longer than the original string. + Usually it is 1. For some complex + collations it can be bigger. For example + in latin1_german2_ci, a sort key is up to + twice longer than the original string. + e.g. Letter 'A' with two dots above is + substituted with 'AE'. + mbminlen - mininum multibyte sequence length. + Now always 1 except ucs2. For ucs2 + it is 2. + mbmaxlen - maximum multibyte sequence length. + 1 for 8bit charsets. Can be also 2 or 3. + + + +MY_CHARSET_HANDLER +================== + +MY_CHARSET_HANDLER is a collection of character-set +related routines. Defined in m_ctype.h. Have the +following set of functions: + +Multibyte routines +------------------ +ismbchar() - detects if the given string is a multibyte sequence +mbcharlen() - returns length of multibyte sequence starting with + the given character +numchars() - returns number of characters in the given string, e.g. + in SQL function CHAR_LENGTH(). +charpos() - calculates the offset of the given position in the string. + Used in SQL functions LEFT(), RIGHT(), SUBSTRING(), + INSERT() + +well_formed_length() + - finds the length of correctly formed multybyte beginning. + Used in INSERTs to cut a beginning of the given string + which is + a) "well formed" according to the given character set. + b) can fit into the given data type + Terminates the string in the good position, taking in account + multibyte character boundaries. + +lengthsp() - returns the length of the given string without traling spaces. + + +Unicode conversion routines +--------------------------- +mb_wc - converts the left multibyte sequence into it Unicode code. +mc_mb - converts the given Unicode code into multibyte sequence. + + +Case and sort convertion +------------------------ +caseup_str - converts the given 0-terminated string into the upper case +casedn_str - converts the given 0-terminated string into the lower case +caseup - converts the given string into the lower case using length +casedn - converts the given string into the lower case using length + +Number-to-string conversion routines +------------------------------------ +snprintf() +long10_to_str() +longlong10_to_str() + +The names are pretty self-descripting. + +String padding routines +----------------------- +fill() - writes the given Unicode value into the given string + with the given length. Used to pad the string, usually + with space character, according to the given charset. + +String-to-numner conversion routines +------------------------------------ +strntol() +strntoul() +strntoll() +strntoull() +strntod() + +These functions are almost for the same thing with their +STDLIB counterparts, but also: + - accept length instead of 0-terminator + - and are character set dependant + +Simple scanner routines +----------------------- +scan() - to skip leading spaces in the given string. + Used when a string value is inserted into a numeric field. + + + +MY_COLLATION_HANDLER +==================== +strnncoll() - compares two strings according to the given collation +strnncollsp() - like the above but ignores trailing spaces +strnxfrm() - makes a sort key suitable for memcmp() corresponding + to the given string +like_range() - creates a LIKE range, for optimizer +wildcmp() - wildcard comparison, for LIKE +strcasecmp() - 0-terminated string comparison +instr() - finds the first substring appearence in the string +hash_sort() - calculates hash value taking in account + the collation rules, e.g. case-insensitivity, + accent sensitivity, etc. + +
\ No newline at end of file diff --git a/strings/Makefile.am b/strings/Makefile.am index be51e48ef8d..d17a4f598a6 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -57,7 +57,7 @@ EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \ t_ctype.h libmystrings_a_LIBADD= -conf_to_src_SOURCES = conf_to_src.c xml.c ctype.c +conf_to_src_SOURCES = conf_to_src.c xml.c ctype.c bcmp.c conf_to_src_LDADD= #force static linking of conf_to_src - essential when linking against #custom installation of libc diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index a41449d5e50..e7527b418f5 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -123,8 +123,7 @@ int my_strcasecmp_mb(CHARSET_INFO * cs,const char *s, const char *t) ** 1 if matched with wildcard */ -#define INC_PTR(cs,A,B) A+=((use_mb_flag && \ - my_ismbchar(cs,A,B)) ? my_ismbchar(cs,A,B) : 1) +#define INC_PTR(cs,A,B) A+=(my_ismbchar(cs,A,B) ? my_ismbchar(cs,A,B) : 1) #define likeconv(s,A) (uchar) (s)->sort_order[(uchar) (A)] @@ -135,8 +134,6 @@ int my_wildcmp_mb(CHARSET_INFO *cs, { int result= -1; /* Not found, using wildcards */ - bool use_mb_flag=use_mb(cs); - while (wildstr != wildend) { while (*wildstr != w_many && *wildstr != w_one) @@ -144,8 +141,7 @@ int my_wildcmp_mb(CHARSET_INFO *cs, int l; if (*wildstr == escape && wildstr+1 != wildend) wildstr++; - if (use_mb_flag && - (l = my_ismbchar(cs, wildstr, wildend))) + if ((l = my_ismbchar(cs, wildstr, wildend))) { if (str+l > str_end || memcmp(str, wildstr, l) != 0) return 1; @@ -200,41 +196,30 @@ int my_wildcmp_mb(CHARSET_INFO *cs, cmp= *++wildstr; mb=wildstr; - LINT_INIT(mblen); - if (use_mb_flag) - mblen = my_ismbchar(cs, wildstr, wildend); + mblen= my_ismbchar(cs, wildstr, wildend); INC_PTR(cs,wildstr,wildend); /* This is compared trough cmp */ cmp=likeconv(cs,cmp); do { - if (use_mb_flag) - { - for (;;) + for (;;) + { + if (str >= str_end) + return -1; + if (mblen) { - if (str >= str_end) - return -1; - if (mblen) - { - if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0) - { - str += mblen; - break; - } - } - else if (!my_ismbchar(cs, str, str_end) && - likeconv(cs,*str) == cmp) + if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0) { - str++; + str += mblen; break; } - INC_PTR(cs,str, str_end); } - } - else - { - while (str != str_end && likeconv(cs,*str) != cmp) + else if (!my_ismbchar(cs, str, str_end) && + likeconv(cs,*str) == cmp) + { str++; - if (str++ == str_end) return (-1); + break; + } + INC_PTR(cs,str, str_end); } { int tmp=my_wildcmp_mb(cs,str,str_end,wildstr,wildend,escape,w_one, @@ -555,8 +540,6 @@ static int my_wildcmp_mb_bin(CHARSET_INFO *cs, { int result= -1; /* Not found, using wildcards */ - bool use_mb_flag=use_mb(cs); - while (wildstr != wildend) { while (*wildstr != w_many && *wildstr != w_one) @@ -564,8 +547,7 @@ static int my_wildcmp_mb_bin(CHARSET_INFO *cs, int l; if (*wildstr == escape && wildstr+1 != wildend) wildstr++; - if (use_mb_flag && - (l = my_ismbchar(cs, wildstr, wildend))) + if ((l = my_ismbchar(cs, wildstr, wildend))) { if (str+l > str_end || memcmp(str, wildstr, l) != 0) return 1; @@ -620,39 +602,28 @@ static int my_wildcmp_mb_bin(CHARSET_INFO *cs, cmp= *++wildstr; mb=wildstr; - LINT_INIT(mblen); - if (use_mb_flag) - mblen = my_ismbchar(cs, wildstr, wildend); + mblen= my_ismbchar(cs, wildstr, wildend); INC_PTR(cs,wildstr,wildend); /* This is compared trough cmp */ do { - if (use_mb_flag) - { - for (;;) + for (;;) + { + if (str >= str_end) + return -1; + if (mblen) { - if (str >= str_end) - return -1; - if (mblen) - { - if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0) - { - str += mblen; - break; - } - } - else if (!my_ismbchar(cs, str, str_end) && *str == cmp) + if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0) { - str++; + str += mblen; break; } - INC_PTR(cs,str, str_end); } - } - else - { - while (str != str_end && *str != cmp) + else if (!my_ismbchar(cs, str, str_end) && *str == cmp) + { str++; - if (str++ == str_end) return (-1); + break; + } + INC_PTR(cs,str, str_end); } { int tmp=my_wildcmp_mb_bin(cs,str,str_end,wildstr,wildend,escape,w_one,w_many); diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 55ff8ac28fe..4176ff2e538 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4563,6 +4563,40 @@ uint my_numcells_sjis(CHARSET_INFO *cs __attribute__((unused)), return clen; } +/* + Returns a well formed length of a SJIS string. + CP932 additional characters are also accepted. +*/ +static +uint my_well_formed_len_sjis(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, uint pos) +{ + const char *b0= b; + while (pos && b < e) + { + /* + Cast to int8 for extra safety. + "char" can be unsigned by default + on some platforms. + */ + if (((int8)b[0]) >= 0) + { + /* Single byte character */ + b+= 1; + } + else if (issjishead((uchar)*b) && (e-b)>1 && issjistail((uchar)b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + break; + } + } + return b - b0; +} static MY_COLLATION_HANDLER my_collation_ci_handler = @@ -4586,7 +4620,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_sjis, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_sjis, my_lengthsp_8bit, my_numcells_sjis, my_mb_wc_sjis, /* mb_wc */ diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 446fc821337..91af7af0c54 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -7052,6 +7052,28 @@ static int my_strnncoll_uca(CHARSET_INFO *cs, NOTES: Works exactly the same with my_strnncoll_uca(), but ignores trailing spaces. + + In the while() comparison these situations are possible: + 1. (s_res>0) and (t_res>0) and (s_res == t_res) + Weights are the same so far, continue comparison + 2. (s_res>0) and (t_res>0) and (s_res!=t_res) + A difference has been found, return. + 3. (s_res>0) and (t_res<0) + We have reached the end of the second string, or found + an illegal multibyte sequence in the second string. + Compare the first string to an infinite array of + space characters until difference is found, or until + the end of the first string. + 4. (s_res<0) and (t_res>0) + We have reached the end of the first string, or found + an illegal multibyte sequence in the first string. + Compare the second string to an infinite array of + space characters until difference is found or until + the end of the second steing. + 5. (s_res<0) and (t_res<0) + Both scanners returned -1. It means we have riched + the end-of-string of illegal-sequence in both strings + at the same time. Return 0, strings are equal. RETURN Difference between two strings, according to the collation: @@ -7070,9 +7092,6 @@ static int my_strnncollsp_uca(CHARSET_INFO *cs, int s_res; int t_res; - slen= cs->cset->lengthsp(cs, (char*) s, slen); - tlen= cs->cset->lengthsp(cs, (char*) t, tlen); - scanner_handler->init(&sscanner, cs, s, slen); scanner_handler->init(&tscanner, cs, t, tlen); @@ -7081,6 +7100,36 @@ static int my_strnncollsp_uca(CHARSET_INFO *cs, s_res= scanner_handler->next(&sscanner); t_res= scanner_handler->next(&tscanner); } while ( s_res == t_res && s_res >0); + + if (s_res > 0 && t_res < 0) + { + /* Calculate weight for SPACE character */ + t_res= cs->sort_order_big[0][0x20 * cs->sort_order[0]]; + + /* compare the first string to spaces */ + do + { + if (s_res != t_res) + return (s_res - t_res); + s_res= scanner_handler->next(&sscanner); + } while (s_res > 0); + return 0; + } + + if (s_res < 0 && t_res > 0) + { + /* Calculate weight for SPACE character */ + s_res= cs->sort_order_big[0][0x20 * cs->sort_order[0]]; + + /* compare the second string to spaces */ + do + { + if (s_res != t_res) + return (s_res - t_res); + t_res= scanner_handler->next(&tscanner); + } while (t_res > 0); + return 0; + } return ( s_res - t_res ); } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 3247e1d7424..851c2044f47 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1231,172 +1231,14 @@ uint my_lengthsp_ucs2(CHARSET_INFO *cs __attribute__((unused)), } -/* -** Compare string against string with wildcard -** 0 if matched -** -1 if not matched with wildcard -** 1 if matched with wildcard -*/ - -static -int my_wildcmp_ucs2(CHARSET_INFO *cs, - const char *str,const char *str_end, - const char *wildstr,const char *wildend, - int escape, int w_one, int w_many, - MY_UNICASE_INFO **weights) -{ - int result= -1; /* Not found, using wildcards */ - my_wc_t s_wc, w_wc; - int scan, plane; - - while (wildstr != wildend) - { - - while (1) - { - scan= my_ucs2_uni(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend); - if (scan <= 0) - return 1; - - if (w_wc == (my_wc_t)escape) - { - wildstr+= scan; - scan= my_ucs2_uni(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend); - if (scan <= 0) - return 1; - } - - if (w_wc == (my_wc_t)w_many) - { - result= 1; /* Found an anchor char */ - break; - } - - wildstr+= scan; - scan= my_ucs2_uni(cs, &s_wc, (const uchar*)str, (const uchar*)str_end); - if (scan <=0) - return 1; - str+= scan; - - if (w_wc == (my_wc_t)w_one) - { - result= 1; /* Found an anchor char */ - } - else - { - if (weights) - { - plane=(s_wc>>8) & 0xFF; - s_wc = weights[plane] ? weights[plane][s_wc & 0xFF].sort : s_wc; - plane=(w_wc>>8) & 0xFF; - w_wc = weights[plane] ? weights[plane][w_wc & 0xFF].sort : w_wc; - } - if (s_wc != w_wc) - return 1; /* No match */ - } - if (wildstr == wildend) - return (str != str_end); /* Match if both are at end */ - } - - - if (w_wc == (my_wc_t)w_many) - { /* Found w_many */ - - /* Remove any '%' and '_' from the wild search string */ - for ( ; wildstr != wildend ; ) - { - scan= my_ucs2_uni(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend); - if (scan <= 0) - return 1; - - if (w_wc == (my_wc_t)w_many) - { - wildstr+= scan; - continue; - } - - if (w_wc == (my_wc_t)w_one) - { - wildstr+= scan; - scan= my_ucs2_uni(cs, &s_wc, (const uchar*)str, - (const uchar*)str_end); - if (scan <=0) - return 1; - str+= scan; - continue; - } - break; /* Not a wild character */ - } - - if (wildstr == wildend) - return 0; /* Ok if w_many is last */ - - if (str == str_end) - return -1; - - scan= my_ucs2_uni(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend); - if (scan <= 0) - return 1; - - if (w_wc == (my_wc_t)escape) - { - wildstr+= scan; - scan= my_ucs2_uni(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend); - if (scan <= 0) - return 1; - } - - while (1) - { - /* Skip until the first character from wildstr is found */ - while (str != str_end) - { - scan= my_ucs2_uni(cs,&s_wc, (const uchar*)str, - (const uchar*)str_end); - if (scan <= 0) - return 1; - if (weights) - { - plane=(s_wc>>8) & 0xFF; - s_wc = weights[plane] ? weights[plane][s_wc & 0xFF].sort : s_wc; - plane=(w_wc>>8) & 0xFF; - w_wc = weights[plane] ? weights[plane][w_wc & 0xFF].sort : w_wc; - } - - if (s_wc == w_wc) - break; - str+= scan; - } - if (str == str_end) - return -1; - - result= my_wildcmp_ucs2(cs,str,str_end,wildstr,wildend,escape, - w_one,w_many,weights); - - if (result <= 0) - return result; - - str+= scan; - } - } - } - return (str != str_end ? 1 : 0); -} - - static int my_wildcmp_ucs2_ci(CHARSET_INFO *cs, const char *str,const char *str_end, const char *wildstr,const char *wildend, int escape, int w_one, int w_many) { - return my_wildcmp_ucs2(cs,str,str_end,wildstr,wildend, - escape,w_one,w_many,uni_plane); + return my_wildcmp_unicode(cs,str,str_end,wildstr,wildend, + escape,w_one,w_many,uni_plane); } @@ -1406,8 +1248,8 @@ int my_wildcmp_ucs2_bin(CHARSET_INFO *cs, const char *wildstr,const char *wildend, int escape, int w_one, int w_many) { - return my_wildcmp_ucs2(cs,str,str_end,wildstr,wildend, - escape,w_one,w_many,NULL); + return my_wildcmp_unicode(cs,str,str_end,wildstr,wildend, + escape,w_one,w_many,NULL); } diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index fd6610b72b1..3ca6c5d279f 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1518,6 +1518,161 @@ MY_UNICASE_INFO *uni_plane[256]={ }; + +/* +** Compare string against string with wildcard +** This function is used in UTF8 and UCS2 +** +** 0 if matched +** -1 if not matched with wildcard +** 1 if matched with wildcard +*/ + +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights) +{ + int result= -1; /* Not found, using wildcards */ + my_wc_t s_wc, w_wc; + int scan, plane; + int (*mb_wc)(struct charset_info_st *cs, my_wc_t *wc, + const unsigned char *s,const unsigned char *e); + mb_wc= cs->cset->mb_wc; + + while (wildstr != wildend) + { + while (1) + { + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <= 0) + return 1; + + if (w_wc == (my_wc_t)escape) + { + wildstr+= scan; + if ((scan= mb_wc(cs,&w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <= 0) + return 1; + } + + if (w_wc == (my_wc_t)w_many) + { + result= 1; /* Found an anchor char */ + break; + } + + wildstr+= scan; + if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, + (const uchar*)str_end)) <=0) + return 1; + str+= scan; + + if (w_wc == (my_wc_t)w_one) + { + result= 1; /* Found an anchor char */ + } + else + { + if (weights) + { + plane=(s_wc>>8) & 0xFF; + s_wc = weights[plane] ? weights[plane][s_wc & 0xFF].sort : s_wc; + plane=(w_wc>>8) & 0xFF; + w_wc = weights[plane] ? weights[plane][w_wc & 0xFF].sort : w_wc; + } + if (s_wc != w_wc) + return 1; /* No match */ + } + if (wildstr == wildend) + return (str != str_end); /* Match if both are at end */ + } + + + if (w_wc == (my_wc_t)w_many) + { /* Found w_many */ + + /* Remove any '%' and '_' from the wild search string */ + for ( ; wildstr != wildend ; ) + { + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <= 0) + return 1; + + if (w_wc == (my_wc_t)w_many) + { + wildstr+= scan; + continue; + } + + if (w_wc == (my_wc_t)w_one) + { + wildstr+= scan; + if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, + (const uchar*)str_end)) <=0) + return 1; + str+= scan; + continue; + } + break; /* Not a wild character */ + } + + if (wildstr == wildend) + return 0; /* Ok if w_many is last */ + + if (str == str_end) + return -1; + + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <=0) + return 1; + + if (w_wc == (my_wc_t)escape) + { + wildstr+= scan; + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <=0) + return 1; + } + + while (1) + { + /* Skip until the first character from wildstr is found */ + while (str != str_end) + { + if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, + (const uchar*)str_end)) <=0) + return 1; + if (weights) + { + plane=(s_wc>>8) & 0xFF; + s_wc = weights[plane] ? weights[plane][s_wc & 0xFF].sort : s_wc; + plane=(w_wc>>8) & 0xFF; + w_wc = weights[plane] ? weights[plane][w_wc & 0xFF].sort : w_wc; + } + + if (s_wc == w_wc) + break; + str+= scan; + } + if (str == str_end) + return -1; + + result= my_wildcmp_unicode(cs, str, str_end, wildstr, wildend, + escape, w_one, w_many, + weights); + + if (result <= 0) + return result; + + str+= scan; + } + } + } + return (str != str_end ? 1 : 0); +} + #endif @@ -1948,50 +2103,120 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs, } -static int my_strncasecmp_utf8(CHARSET_INFO *cs, - const char *s, const char *t, uint len) -{ - int s_res,t_res; - my_wc_t s_wc,t_wc; - const char *se=s+len; - const char *te=t+len; +/* + Compare 0-terminated UTF8 strings. - while ( s < se && t < te ) - { - int plane; + SYNOPSIS + my_strcasecmp_utf8() + cs character set handler + s First 0-terminated string to compare + t Second 0-terminated string to compare - s_res=my_utf8_uni(cs,&s_wc, (const uchar*)s, (const uchar*)se); - t_res=my_utf8_uni(cs,&t_wc, (const uchar*)t, (const uchar*)te); + IMPLEMENTATION - if ( s_res <= 0 || t_res <= 0 ) + RETURN + - negative number if s < t + - positive number if s > t + - 0 is the strings are equal +*/ + +static +int my_strcasecmp_utf8(CHARSET_INFO *cs, const char *s, const char *t) +{ + while (s[0] && t[0]) + { + my_wc_t s_wc,t_wc; + + /* + Cast to int8 for extra safety. + char can be unsigned by default + on some platforms. + */ + if (((int8)s[0]) >= 0) { - /* Incorrect string, compare byte by byte value */ - return bincmp(s, se, t, te); + /* + s[0] is between 0 and 127. + It represents a single byte character. + Convert it into weight according to collation. + */ + s_wc= plane00[(uchar) s[0]].tolower; + s++; } - - plane=(s_wc>>8) & 0xFF; - s_wc = uni_plane[plane] ? uni_plane[plane][s_wc & 0xFF].tolower : s_wc; - - plane=(t_wc>>8) & 0xFF; - t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].tolower : t_wc; - + else + { + int plane, res; + + /* + Scan a multibyte character. + + In the future it is worth to write a special version of my_utf8_uni() + for 0-terminated strings which will not take in account length. Now + we call the regular version of my_utf8_uni() with s+3 in the + last argument. s+3 is enough to scan any multibyte sequence. + + Calling the regular version of my_utf8_uni is safe for 0-terminated + strings: we will never lose the end of the string: + If we have 0 character in the middle of a multibyte sequence, + then my_utf8_uni will always return a negative number, so the + loop with finish. + */ + + res= my_utf8_uni(cs,&s_wc, (const uchar*)s, (const uchar*) s + 3); + + /* + In the case of wrong multibyte sequence we will + call strcmp() for byte-to-byte comparison. + */ + if (res <= 0) + return strcmp(s, t); + s+= res; + + /* Convert Unicode code into weight according to collation */ + plane=(s_wc>>8) & 0xFF; + s_wc = uni_plane[plane] ? uni_plane[plane][s_wc & 0xFF].tolower : s_wc; + } + + + /* Do the same for the second string */ + + if (t[0] >= 0) + { + /* Convert single byte character into weight */ + t_wc= plane00[(uchar) t[0]].tolower; + t++; + } + else + { + int plane; + int res=my_utf8_uni(cs,&t_wc, (const uchar*)t, (const uchar*) t + 3); + if (res <= 0) + return strcmp(s, t); + t+= res; + + /* Convert code into weight */ + plane=(t_wc>>8) & 0xFF; + t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].tolower : t_wc; + } + + /* Now we have two weights, let's compare them */ if ( s_wc != t_wc ) return ((int) s_wc) - ((int) t_wc); - - s+=s_res; - t+=t_res; } - return ( (se-s) - (te-t) ); + return ((int)(uchar)s[0]) - ((int) (uchar) t[0]); } -static int my_strcasecmp_utf8(CHARSET_INFO *cs, const char *s, const char *t) + +static +int my_wildcmp_utf8(CHARSET_INFO *cs, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many) { - uint s_len=strlen(s); - uint t_len=strlen(t); - uint len = (s_len > t_len) ? s_len : t_len; - return my_strncasecmp_utf8(cs, s, t, len); + return my_wildcmp_unicode(cs,str,str_end,wildstr,wildend, + escape,w_one,w_many,uni_plane); } + static int my_strnxfrm_utf8(CHARSET_INFO *cs, uchar *dst, uint dstlen, const uchar *src, uint srclen) @@ -2060,7 +2285,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = my_strnncollsp_utf8, my_strnxfrm_utf8, my_like_range_mb, - my_wildcmp_mb, + my_wildcmp_utf8, my_strcasecmp_utf8, my_instr_mb, my_hash_sort_utf8 diff --git a/strings/xml.c b/strings/xml.c index 7d7839e1603..6ba52ea41a8 100644 --- a/strings/xml.c +++ b/strings/xml.c @@ -81,10 +81,11 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) a->beg=p->cur; a->end=p->cur; - if (!memcmp(p->cur,"<!--",4)) + if (!bcmp(p->cur,"<!--",4)) { - for( ; (p->cur < p->end) && memcmp(p->cur, "-->", 3); p->cur++); - if(!memcmp(p->cur, "-->", 3)) + for( ; (p->cur < p->end) && bcmp(p->cur, "-->", 3); p->cur++) + {} + if (!bcmp(p->cur, "-->", 3)) p->cur+=3; a->end=p->cur; lex=MY_XML_COMMENT; diff --git a/tests/client_test.c b/tests/client_test.c index 0b30cc3386d..130e0bc3b4f 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -26,14 +26,6 @@ #include <mysql.h> #include <my_getopt.h> #include <m_string.h> -#ifdef HAVE_SYS_PARAM_H -/* Include to get MAXPATHLEN */ -#include <sys/param.h> -#endif - -#ifndef MAXPATHLEN -#define MAXPATHLEN 256 -#endif #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ @@ -3439,7 +3431,7 @@ static void test_fetch_date() MYSQL_STMT *stmt; uint i; int rc, year; - char date[25], time[25], ts[25], ts_4[15], ts_6[20], dt[20]; + char date[25], time[25], ts[25], ts_4[25], ts_6[20], dt[20]; ulong d_length, t_length, ts_length, ts4_length, ts6_length, dt_length, y_length; MYSQL_BIND bind[8]; @@ -3549,8 +3541,8 @@ static void test_fetch_date() DIE_UNLESS(strcmp(dt, "2010-07-10 00:00:00") == 0); DIE_UNLESS(dt_length == 19); - DIE_UNLESS(ts_4[0] == '\0'); - DIE_UNLESS(ts4_length == 0); + DIE_UNLESS(strcmp(ts_4, "0000-00-00 00:00:00") == 0); + DIE_UNLESS(ts4_length == strlen("0000-00-00 00:00:00")); DIE_UNLESS(strcmp(ts_6, "1999-12-29 00:00:00") == 0); DIE_UNLESS(ts6_length == 19); @@ -6652,8 +6644,8 @@ static void test_frm_bug() MYSQL_RES *result; MYSQL_ROW row; FILE *test_file; - char data_dir[MAXPATHLEN]; - char test_frm[MAXPATHLEN]; + char data_dir[FN_REFLEN]; + char test_frm[FN_REFLEN]; int rc; myheader("test_frm_bug"); @@ -6674,7 +6666,7 @@ static void test_frm_bug() bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= data_dir; - bind[0].buffer_length= MAXPATHLEN; + bind[0].buffer_length= FN_REFLEN; bind[0].is_null= 0; bind[0].length= 0; bind[1]= bind[0]; @@ -10541,6 +10533,163 @@ static void test_bug5315() } +static void test_bug6049() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *stmt_text; + char buffer[30]; + ulong length; + int rc; + + myheader("test_bug6049"); + + stmt_text= "SELECT MAKETIME(-25, 12, 12)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = &buffer; + bind[0].buffer_length = sizeof(buffer); + bind[0].length = &length; + + mysql_stmt_bind_result(stmt, bind); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + printf("Result from query: %s\n", row[0]); + printf("Result from prepared statement: %s\n", (char*) buffer); + + DIE_UNLESS(strcmp(row[0], (char*) buffer) == 0); + + mysql_free_result(res); + mysql_stmt_close(stmt); +} + + +static void test_bug6058() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + const char *stmt_text; + char buffer[30]; + ulong length; + int rc; + + myheader("test_bug6058"); + + stmt_text= "SELECT CAST('0000-00-00' AS DATE)"; + + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = &buffer; + bind[0].buffer_length = sizeof(buffer); + bind[0].length = &length; + + mysql_stmt_bind_result(stmt, bind); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + + printf("Result from query: %s\n", row[0]); + printf("Result from prepared statement: %s\n", buffer); + + DIE_UNLESS(strcmp(row[0], buffer) == 0); + + mysql_free_result(res); + mysql_stmt_close(stmt); +} + + +static void test_bug6059() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + + myheader("test_bug6059"); + + stmt_text= "SELECT 'foo' INTO OUTFILE 'x.3'"; + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + DIE_UNLESS(mysql_stmt_field_count(stmt) == 0); + mysql_stmt_close(stmt); +} + + +static void test_bug6046() +{ + MYSQL_STMT *stmt; + const char *stmt_text; + int rc; + short b= 1; + MYSQL_BIND bind[1]; + + myheader("test_bug6046"); + + stmt_text= "DROP TABLE IF EXISTS t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "CREATE TABLE a1 (a int, b int)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + stmt_text= "INSERT INTO a1 VALUES (1,1),(2,2),(3,1),(4,2)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + stmt_text= "SELECT a1.a FROM a1 NATURAL JOIN a1 as X1 " + "WHERE a1.b > ? ORDER BY a1.a"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + b= 1; + bzero(bind, sizeof(bind)); + bind[0].buffer= &b; + bind[0].buffer_type= MYSQL_TYPE_SHORT; + + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_store_result(stmt); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + mysql_stmt_close(stmt); +} + + + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -10851,6 +11000,10 @@ int main(int argc, char **argv) test_bug5194(); /* bulk inserts in prepared mode */ test_bug5315(); /* check that mysql_change_user closes all prepared statements */ + test_bug6049(); /* check support for negative TIME values */ + test_bug6058(); /* check support for 0000-00-00 dates */ + test_bug6059(); /* correct metadata for SELECT ... INTO OUTFILE */ + test_bug6046(); /* NATURAL JOIN transformation works in PS */ /* XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. |