diff options
author | unknown <cmiller@zippy.cornsilk.net> | 2007-11-09 14:55:32 -0500 |
---|---|---|
committer | unknown <cmiller@zippy.cornsilk.net> | 2007-11-09 14:55:32 -0500 |
commit | f0e24c795fbceb3d7ad060934e1e399ec939a3f8 (patch) | |
tree | 80d51cbfd49ff9e193edbb78843eb3e2ebbae2c9 | |
parent | 69aee07373c19b5e5615c9a99574c000d0b3c95c (diff) | |
parent | 10397af9c519b8238599a1ff9fed0d3e871c50e7 (diff) | |
download | mariadb-git-f0e24c795fbceb3d7ad060934e1e399ec939a3f8.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.1-community
into zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.1-forcollapseandmerge
sql/ha_ndbcluster.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/log_event.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/set_var.cc:
Auto merged
sql/slave.cc:
Auto merged
sql/sp_head.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_prepare.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql/sql_view.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/table.h:
Auto merged
sql/sql_parse.cc:
Manual merge.
sql/sql_select.cc:
Manual merge.
177 files changed, 9488 insertions, 1721 deletions
diff --git a/.bzrignore b/.bzrignore index e1ad5a89015..c0bac9d05f1 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3004,3 +3004,4 @@ win/vs71cache.txt win/vs8cache.txt zlib/*.ds? zlib/*.vcproj +libmysql_r/client_settings.h diff --git a/include/sql_common.h b/include/sql_common.h index 80504140fae..56e7305130f 100644 --- a/include/sql_common.h +++ b/include/sql_common.h @@ -36,8 +36,10 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, const unsigned char *arg, ulong arg_length, my_bool skip_check, MYSQL_STMT *stmt); unsigned long cli_safe_read(MYSQL *mysql); -void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode, - const char *sqlstate); +void net_clear_error(NET *net); +void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net); +void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate, + const char *err); void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); #ifdef __cplusplus } diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index e2e42fe4a2d..cb326fa4685 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -686,9 +686,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd) if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) { - net->last_errno= CR_SERVER_LOST; - strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error,ER(net->last_errno)); + set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate); return 1; } /* Read what server thinks about out new auth message report */ @@ -701,7 +699,8 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd) my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db) { - char buff[512],*end=buff; + char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2]; + char *end= buff; int rc; CHARSET_INFO *saved_cs= mysql->charset; @@ -723,7 +722,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, passwd=""; /* Store user into the buffer */ - end=strmov(end,user)+1; + end= strmake(end, user, USERNAME_LENGTH) + 1; /* write scrambled password according to server capabilities */ if (passwd[0]) @@ -743,7 +742,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, else *end++= '\0'; /* empty password */ /* Add database if needed */ - end= strmov(end, db ? db : "") + 1; + end= strmake(end, db ? db : "", NAME_LEN) + 1; /* Add character set number. */ @@ -860,8 +859,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) /* copy filename into local memory and allocate read buffer */ if (!(buf=my_malloc(packet_length, MYF(0)))) { - strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY)); + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(1); } @@ -887,9 +885,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) { DBUG_PRINT("error", ("Lost connection to MySQL server during LOAD DATA of local file")); - strmov(net->sqlstate, unknown_sqlstate); - net->last_errno=CR_SERVER_LOST; - strmov(net->last_error,ER(net->last_errno)); + set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate); goto err; } } @@ -897,9 +893,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) /* Send empty packet to mark end of file */ if (my_net_write(net, (const uchar*) "", 0) || net_flush(net)) { - strmov(net->sqlstate, unknown_sqlstate); - net->last_errno=CR_SERVER_LOST; - sprintf(net->last_error,ER(net->last_errno),errno); + set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate); goto err; } @@ -1400,9 +1394,7 @@ const char *cli_read_statistics(MYSQL *mysql) mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */ if (!mysql->net.read_pos[0]) { - strmov(mysql->net.sqlstate, unknown_sqlstate); - mysql->net.last_errno=CR_WRONG_HOST_INFO; - strmov(mysql->net.last_error, ER(mysql->net.last_errno)); + set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate); return mysql->net.last_error; } return (char*) mysql->net.read_pos; @@ -1848,24 +1840,17 @@ static my_bool my_realloc_str(NET *net, ulong length) if (buf_length + length > net->max_packet) { res= net_realloc(net, buf_length + length); + if (res) + { + strmov(net->sqlstate, unknown_sqlstate); + strmov(net->last_error, ER(net->last_errno)); + } net->write_pos= net->buff+ buf_length; } DBUG_RETURN(res); } -/* Clear possible error statee of struct NET */ - -static void net_clear_error(NET *net) -{ - if (net->last_errno) - { - net->last_errno= 0; - net->last_error[0]= '\0'; - strmov(net->sqlstate, not_error_sqlstate); - } -} - static void stmt_clear_error(MYSQL_STMT *stmt) { if (stmt->last_errno) @@ -1876,18 +1861,21 @@ static void stmt_clear_error(MYSQL_STMT *stmt) } } -/* +/** Set statement error code, sqlstate, and error message from given errcode and sqlstate. */ -static void set_stmt_error(MYSQL_STMT * stmt, int errcode, - const char *sqlstate) +void set_stmt_error(MYSQL_STMT * stmt, int errcode, + const char *sqlstate, const char *err) { DBUG_ENTER("set_stmt_error"); DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode))); DBUG_ASSERT(stmt != 0); + if (err == 0) + err= ER(errcode); + stmt->last_errno= errcode; strmov(stmt->last_error, ER(errcode)); strmov(stmt->sqlstate, sqlstate); @@ -1896,21 +1884,24 @@ static void set_stmt_error(MYSQL_STMT * stmt, int errcode, } -/* - Set statement error code, sqlstate, and error message. +/** + Set statement error code, sqlstate, and error message from NET. + + @param stmt a statement handle. Copy the error here. + @param net mysql->net. Source of the error. */ -void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode, - const char *sqlstate) +void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net) { DBUG_ENTER("set_stmt_errmsg"); - DBUG_PRINT("enter", ("error: %d/%s '%s'", errcode, sqlstate, err)); + DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate, + net->last_error)); DBUG_ASSERT(stmt != 0); - stmt->last_errno= errcode; - if (err && err[0]) - strmov(stmt->last_error, err); - strmov(stmt->sqlstate, sqlstate); + stmt->last_errno= net->last_errno; + if (net->last_error && net->last_error[0]) + strmov(stmt->last_error, net->last_error); + strmov(stmt->sqlstate, net->sqlstate); DBUG_VOID_RETURN; } @@ -2085,7 +2076,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) if (!mysql) { /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -2123,23 +2114,20 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) stmt->state= MYSQL_STMT_INIT_DONE; if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); DBUG_RETURN(1); } } if (stmt_command(mysql, COM_STMT_PREPARE, (const uchar*) query, length, stmt)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); DBUG_RETURN(1); } if ((*mysql->methods->read_prepare_result)(mysql, stmt)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); DBUG_RETURN(1); } @@ -2154,7 +2142,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) (stmt->param_count + stmt->field_count)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); DBUG_RETURN(1); } stmt->bind= stmt->params + stmt->param_count; @@ -2284,7 +2272,7 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt) if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result), MYF(MY_WME | MY_ZEROFILL)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); DBUG_RETURN(0); } @@ -2517,7 +2505,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) */ if ((my_realloc_str(net, *param->length))) { - set_stmt_error(stmt, net->last_errno, unknown_sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } (*param->store_param_func)(net, param); @@ -2554,7 +2542,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) stmt->insert_id= mysql->insert_id; if (res) { - set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2577,13 +2565,13 @@ int cli_stmt_execute(MYSQL_STMT *stmt) if (!stmt->bind_param_done) { - set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate); + set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL); DBUG_RETURN(1); } if (mysql->status != MYSQL_STATUS_READY || mysql->server_status & SERVER_MORE_RESULTS_EXISTS) { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); + set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -2592,7 +2580,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt) null_count= (stmt->param_count+7) /8; if (my_realloc_str(net, null_count + 1)) { - set_stmt_error(stmt, net->last_errno, unknown_sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } bzero((char*) net->write_pos, null_count); @@ -2605,7 +2593,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt) { if (my_realloc_str(net, 2 * stmt->param_count)) { - set_stmt_error(stmt, net->last_errno, unknown_sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } /* @@ -2628,7 +2616,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt) /* TODO: Look into avoding the following memdup */ if (!(param_data= my_memdup(net->buff, length, MYF(0)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); DBUG_RETURN(1); } result= execute(stmt, param_data, length); @@ -2692,20 +2680,19 @@ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row) */ if (!mysql) { - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); return 1; } if (mysql->status != MYSQL_STATUS_GET_RESULT) { set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ? CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC, - unknown_sqlstate); + unknown_sqlstate, NULL); goto error; } if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); /* If there was an error, there are no more pending rows: reset statement status to not hang up in following @@ -2766,7 +2753,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) buff, sizeof(buff), (uchar*) 0, 0, 1, NULL)) { - set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + set_stmt_errmsg(stmt, net); return 1; } if ((*mysql->methods->read_rows_from_cursor)(stmt)) @@ -2797,7 +2784,7 @@ static int stmt_read_row_no_result_set(MYSQL_STMT *stmt __attribute__((unused)), unsigned char **row __attribute__((unused))) { - set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate); + set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate, NULL); return 1; } @@ -2847,7 +2834,7 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, } return FALSE; err_not_implemented: - set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate); + set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate, NULL); return TRUE; } @@ -3232,7 +3219,7 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *my_bind) { if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) { - set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate); + set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate, NULL); DBUG_RETURN(1); } DBUG_RETURN(0); @@ -3397,7 +3384,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, */ if (param_number >= stmt->param_count) { - set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate); + set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -3433,8 +3420,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, buff, sizeof(buff), (uchar*) data, length, 1, NULL)) { - set_stmt_errmsg(stmt, mysql->net.last_error, - mysql->net.last_errno, mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); DBUG_RETURN(1); } } @@ -3903,7 +3889,8 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, if (field->flags & ZEROFILL_FLAG && length < field->length && field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1) { - bmove_upp((char*) buff + field->length, buff + length, length); + bmove_upp((uchar*) buff + field->length, (uchar*) buff + length, + length); bfill((char*) buff, field->length - length, '0'); length= field->length; } @@ -4502,7 +4489,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *my_bind) { int errorcode= (int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE ? CR_NO_PREPARE_STMT : CR_NO_STMT_METADATA; - set_stmt_error(stmt, errorcode, unknown_sqlstate); + set_stmt_error(stmt, errorcode, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -4682,12 +4669,12 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *my_bind, if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE) { - set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate); + set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate, NULL); return 1; } if (column >= stmt->field_count) { - set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate); + set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -4733,7 +4720,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) if (!mysql) { - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -4748,7 +4735,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, sizeof(MYSQL_ROWS) + pkt_len - 1))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL); goto err; } cur->data= (MYSQL_ROW) (cur+1); @@ -4769,7 +4756,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) DBUG_RETURN(0); } } - set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + set_stmt_errmsg(stmt, net); err: DBUG_RETURN(1); @@ -4836,7 +4823,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE) { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); + set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -4856,13 +4843,13 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff), (uchar*) 0, 0, 1, NULL)) { - set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } } else if (mysql->status != MYSQL_STATUS_GET_RESULT) { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); + set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL); DBUG_RETURN(1); } @@ -5043,8 +5030,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff, sizeof(buff), 0, 0, 0, NULL)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); stmt->state= MYSQL_STMT_INIT_DONE; return 1; } @@ -5117,8 +5103,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) int4store(buff, stmt->stmt_id); if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); } } } @@ -5139,7 +5124,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) if (!stmt->mysql) { /* mysql can be reset in mysql_close called from mysql_reconnect */ - set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate); + set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL); DBUG_RETURN(1); } /* Reset the client and server sides of the prepared statement */ @@ -5243,15 +5228,11 @@ int STDCALL mysql_next_result(MYSQL *mysql) if (mysql->status != MYSQL_STATUS_READY) { - strmov(mysql->net.sqlstate, unknown_sqlstate); - strmov(mysql->net.last_error, - ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); DBUG_RETURN(1); } - mysql->net.last_error[0]= 0; - mysql->net.last_errno= 0; - strmov(mysql->net.sqlstate, not_error_sqlstate); + net_clear_error(&mysql->net); mysql->affected_rows= ~(my_ulonglong) 0; if (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 4e525f8447f..13847c324e1 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -81,8 +81,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, /* Check that we are calling the client functions in right order */ if (mysql->status != MYSQL_STATUS_READY) { - strmov(net->last_error, - ER(net->last_errno=CR_COMMANDS_OUT_OF_SYNC)); + set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); return 1; } @@ -90,7 +89,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, thd->clear_error(); mysql->affected_rows= ~(my_ulonglong) 0; mysql->field_count= 0; - net->last_errno= 0; + net_clear_error(net); thd->current_stmt= stmt; thd->store_globals(); // Fix if more than one connect @@ -245,8 +244,7 @@ static my_bool emb_read_query_result(MYSQL *mysql) mysql->fields= res->embedded_info->fields_list; mysql->affected_rows= res->embedded_info->affected_rows; mysql->insert_id= res->embedded_info->insert_id; - mysql->net.last_errno= 0; - mysql->net.last_error[0]= 0; + net_clear_error(&mysql->net); mysql->info= 0; if (res->embedded_info->info[0]) @@ -288,7 +286,7 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) if (res) { NET *net= &stmt->mysql->net; - set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); + set_stmt_errmsg(stmt, net); DBUG_RETURN(1); } DBUG_RETURN(0); @@ -299,14 +297,12 @@ int emb_read_binary_rows(MYSQL_STMT *stmt) MYSQL_DATA *data; if (!(data= emb_read_rows(stmt->mysql, 0, 0))) { - set_stmt_errmsg(stmt, stmt->mysql->net.last_error, - stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate); + set_stmt_errmsg(stmt, &stmt->mysql->net); return 1; } stmt->result= *data; my_free((char *) data, MYF(0)); - set_stmt_errmsg(stmt, stmt->mysql->net.last_error, - stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate); + set_stmt_errmsg(stmt, &stmt->mysql->net); return 0; } @@ -320,16 +316,14 @@ int emb_read_rows_from_cursor(MYSQL_STMT *stmt) if (res->embedded_info->last_errno) { embedded_get_error(mysql, res); - set_stmt_errmsg(stmt, mysql->net.last_error, - mysql->net.last_errno, mysql->net.sqlstate); + set_stmt_errmsg(stmt, &mysql->net); return 1; } thd->cur_data= res; mysql->warning_count= res->embedded_info->warning_count; mysql->server_status= res->embedded_info->server_status; - mysql->net.last_errno= 0; - mysql->net.last_error[0]= 0; + net_clear_error(&mysql->net); return emb_read_binary_rows(stmt); } diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test index 26b1e6d5ba0..d3959d10306 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test @@ -1,16 +1,22 @@ ############################################################# +# Author: Chuck +############################################################# # Purpose: To test having extra columns on the master WL#3915 # engine inspecific sourced part ############################################################# - +# Change Author: Jeb +# Change: Cleanup and extend testing +############################################################# # TODO: partition specific # -- source include/have_partition.inc +# Note: Will be done in different test due to NDB using this +# test case. +############################################################ ########### Clean up ################ --disable_warnings --disable_query_log -DROP TABLE IF EXISTS t1,t2,t3,t4,t31; - +DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t10,t11,t12,t13,t14,t15,t16,t17,t18,t31; --enable_query_log --enable_warnings @@ -70,154 +76,87 @@ DROP TABLE IF EXISTS t1,t2,t3,t4,t31; #VARCHAR(M) # - -connection master; -eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00') - ENGINE=$engine_type; - -sync_slave_with_master; -alter table t1 drop f5; - -connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0); - - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; - -connection master; -DROP TABLE t1; -eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST') - ENGINE=$engine_type; - -sync_slave_with_master; -alter table t1 drop f5, drop f6; - -connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi'); - - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; - -connection master; -DROP TABLE t1; -eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST', - f7 INT DEFAULT '0') - ENGINE=$engine_type; - -sync_slave_with_master; -alter table t1 drop f5, drop f6, drop f7; - -connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi', 1); - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; - -connection master; -DROP TABLE t1; -eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST', - f7 INT DEFAULT '0', - f8 TEXT) - ENGINE=$engine_type; - -sync_slave_with_master; -alter table t1 drop f5, drop f6, drop f7, drop f8; - -connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi', 1, 'lounge of happiness'); - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; - -connection master; -DROP TABLE t1; -eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST', - f7 INT DEFAULT '0', - f8 TEXT, - f9 LONGBLOB) - ENGINE=$engine_type; - -sync_slave_with_master; -alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9; - -connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi', 1, 'lounge of happiness', 'very fat blob'); - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; - +let $binformat = `SHOW VARIABLES LIKE '%binlog_format%'`; +--echo +--echo *********************************************************** +--echo *********************************************************** +--echo ***************** Start of Testing ************************ +--echo *********************************************************** +--echo *********************************************************** +--echo * This test format == $binformat and engine == $engine_type +--echo *********************************************************** +--echo *********************************************************** +--echo +--echo ***** Testing more columns on the Master ***** +--echo connection master; -DROP TABLE t1; eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST', - f7 INT DEFAULT '0', - f8 TEXT, - f9 LONGBLOB, - f10 BIT(63)) - ENGINE=$engine_type; - + /* extra */ + f5 FLOAT DEFAULT '2.00', + f6 CHAR(4) DEFAULT 'TEST', + f7 INT DEFAULT '0', + f8 TEXT, + f9 LONGBLOB, + f10 BIT(63), + f11 VARBINARY(64))ENGINE=$engine_type; +--echo +--echo * Alter Table on Slave and drop columns f5 through f11 * +--echo sync_slave_with_master; -alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10; +alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; +--echo +--echo * Insert data in Master then update and delete some rows* +--echo connection master; -INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi', 1, 'lounge of happiness', 'very fat blob', b'01010101010101'); - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # ---query_vertical show slave status; - select * from t1 order by f3; +let $j= 50; +--disable_query_log +while ($j) +{ + eval INSERT INTO t1 VALUES ($j, $j, $j, 'second', 2.0, 'kaks', 2, + 'got stolen from the paradise', + 'very fat blob', b'01010101010101', + 0x123456); + dec $j; +} +let $j= 30; +while ($j) +{ + eval update t1 set f4= 'next' where f1=$j; + dec $j; + dec $j; + eval delete from t1 where f1=$j; + dec $j; +} +--enable_query_log -connection master; -DROP TABLE t1; - eval CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), - /* extra */ - f5 FLOAT DEFAULT '2.00', - f6 CHAR(4) DEFAULT 'TEST', - f7 INT DEFAULT '0', - f8 TEXT, - f9 LONGBLOB, - f10 BIT(63), - f11 VARBINARY(64)) - ENGINE=$engine_type; +--echo * Select count and 20 rows from Master * +--echo +SELECT COUNT(*) FROM t1; +--echo +SELECT f1,f2,f3,f4,f5,f6,f7,f8,f9, + hex(f10),hex(f11) FROM t1 ORDER BY f3 LIMIT 20; #connection slave; - sync_slave_with_master; - alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; - -connection master; - - INSERT into t1 values (1, 1, 1, 'first', 1.0, 'yksi', 1, 'lounge of happiness', 'very fat blob', b'01010101010101', 0x123456); - INSERT into t1 values (2, 2, 2, 'second', 2.0, 'kaks', 2, 'got stolen from the paradise', 'very fat blob', b'01010101010101', 0x123456), (3, 3, 3, 'third', 3.0, 'kolm', 3, 'got stolen from the paradise', 'very fat blob', b'01010101010101', 0x123456); - update t1 set f4= 'next' where f1=1; - delete from t1 where f1=1; - - select * from t1 order by f3; - +sync_slave_with_master; +--echo +--echo * Select count and 20 rows from Slave * +--echo +SELECT COUNT(*) FROM t1; +--echo +SELECT * FROM t1 ORDER BY f3 LIMIT 20; -#connection slave; - sync_slave_with_master; ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # +--echo +--echo * Show Slave Status * +--echo +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # --query_vertical show slave status; - select * from t1 order by f3; - +--echo ### Altering table def scenario +--echo +--echo ***** Testing Altering table def scenario ***** +--echo connection master; @@ -232,7 +171,7 @@ connection master; f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', f12 SET('a', 'b', 'c') default 'b') ENGINE=$engine_type; - +--echo eval CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), /* extra */ f5 DOUBLE DEFAULT '2.00', @@ -243,7 +182,7 @@ connection master; f12 SET('a', 'b', 'c') default 'b') ENGINE=$engine_type; - +--echo # no ENUM and SET eval CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), /* extra */ @@ -256,7 +195,7 @@ connection master; f11 CHAR(255)) ENGINE=$engine_type; - +--echo eval CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), /* extra */ @@ -293,7 +232,9 @@ connection master; f34 VARBINARY(1025), f35 VARCHAR(257) ) ENGINE=$engine_type; - +--echo +--echo ** Alter tables on slave and drop columns ** +--echo #connection slave; sync_slave_with_master; alter table t2 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11, drop @@ -308,8 +249,8 @@ f12; drop f26, drop f27, drop f28, drop f29, drop f30, drop f31, drop f32, drop f33, drop f34, drop f35; - - +--echo +--echo ** Insert Data into Master ** connection master; INSERT into t2 set f1=1, f2=1, f3=1, f4='first', f8='f8: medium size blob', f10='f10: some var char'; @@ -458,7 +399,10 @@ binary data'; /*f34 VARBINARY(1025),*/ '3333 minus 3', /*f35 VARCHAR(257),*/ NULL ); - +--echo +--echo ** Sync slave with master ** +--echo ** Do selects from tables ** +--echo #connection slave; sync_slave_with_master; @@ -469,24 +413,33 @@ binary data'; select * from t31 order by f1; connection master; - +--echo +--echo ** Do updates master ** +--echo update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; +--echo +--echo ** Delete from Master ** +--echo + delete from t1; delete from t2; delete from t3; delete from t4; delete from t31; +--echo +--echo ** Check slave status ** +--echo #connection slave; sync_slave_with_master; select * from t31; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # --query_vertical show slave status; #### Clean Up #### @@ -496,11 +449,600 @@ connection master; --disable_query_log DROP TABLE t1,t2,t3,t4,t31; +###################################################### #connection slave; sync_slave_with_master; --enable_query_log --enable_warnings +--echo +--echo **************************************** +--echo * columns in master at middle of table * +--echo * Expect: Proper error message * +--echo **************************************** +--echo +--echo ** Stop and Reset Slave ** +--echo +STOP SLAVE; +RESET SLAVE; +--echo +--echo ** create table slave side ** +eval CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo ** Connect to master and create table ** +--echo +--connection master +eval CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233', + c CHAR(5), e INT DEFAULT '1')ENGINE=$engine_type; +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT), + (2,@b1,DEFAULT,'JOE',DEFAULT), + (3,@b1,DEFAULT,'QA',DEFAULT); + +--echo +--echo ******************************************** +--echo *** Expect slave to fail with Error 1523 *** +--echo ******************************************** +--echo +connection slave; +wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # +--query_vertical SHOW SLAVE STATUS +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +--echo +--echo *** Drop t10 *** +connection master; +DROP TABLE t10; +sync_slave_with_master; + +############################################ +############## Continued ################### +############################################ +--echo +--echo ********************************************* +--echo * More columns in master at middle of table * +--echo * Expect: Proper error message * +--echo ********************************************* +--echo +--echo *** Create t11 on slave *** +STOP SLAVE; +RESET SLAVE; + +eval CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t11 on Master *** +connection master; +eval CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, + c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT), + (2,@b1,'Testing is cool','JOE',DEFAULT), + (3,@b1,DEFAULT,'QA',DEFAULT); + +--echo +--echo ******************************************** +--echo *** Expect slave to fail with Error 1523 *** +--echo ******************************************** +--echo +connection slave; +wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # +--query_vertical SHOW SLAVE STATUS +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +--echo +--echo *** Drop t11 *** +connection master; +DROP TABLE t11; +sync_slave_with_master; + +############################################ +############## Continued ################### +############################################ +--echo +--echo ********************************************* +--echo * More columns in master at middle of table * +--echo * Expect: This one should pass blob-text * +--echo ********************************************* +--echo +--echo *** Create t12 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB + ) ENGINE=$engine_type; + +--echo +--echo *** Create t12 on Master *** +connection master; +eval CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT, + c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t12 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), + (2,@b1,'JOE',DEFAULT,DEFAULT), + (3,@b1,'QA',DEFAULT,DEFAULT); +--echo +SELECT a,hex(b),f,c,e FROM t12 ORDER BY a; + +--echo +--echo *** Select on Slave *** +sync_slave_with_master; +SELECT a,hex(b),c FROM t12 ORDER BY a; + +--echo +--echo *** Drop t12 *** +connection master; +DROP TABLE t12; +sync_slave_with_master; + +############################################ +############## Continued ################### +############################################ +--echo +--echo **************************************************** +--echo * - Alter Master adding columns at middle of table * +--echo * Expect: columns added * +--echo **************************************************** +--echo +--echo +--echo *** Create t14 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t14 on Master *** +connection master; +eval CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1; +ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2; +--echo +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle',DEFAULT,DEFAULT), + (2,2.00,'This Test Should work',@b1,'JOE',DEFAULT,DEFAULT), + (3,3.00,'If is does not, I will open a bug',@b1,'QA',DEFAULT,DEFAULT); +--echo +--replace_column 7 CURRENT_TIMESTAMP +SELECT c1,c2,c3,hex(c4),c5,c6,c7 FROM t14 ORDER BY c1; + +--echo +--echo *** Select on Slave **** +sync_slave_with_master; +SELECT c1,c2,c3,hex(c4),c5 FROM t14 ORDER BY c1; + +#################################################### +--echo +--echo **************************************************** +--echo * - Alter Master Dropping columns from the middle. * +--echo * Expect: columns dropped * +--echo **************************************************** +--echo +--echo *** connect to master and drop columns *** +connection master; +ALTER TABLE t14 DROP COLUMN c2; +ALTER TABLE t14 DROP COLUMN c7; +--echo +--echo *** Select from Master *** +SELECT c1,c3,hex(c4),c5,c6 FROM t14 ORDER BY c1; +--echo + +--echo ************ +--echo * Bug30415 * +--echo ************ +# Uncomment below once fixed + +#--echo *** Select from Slave *** +#sync_slave_with_master; +#SELECT c1,c2,c3,hex(c4),c5 FROM t14 ORDER BY c1; + +# Bug30415 +# Remove below once fixed +#*************************** +connection slave; +wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # +--query_vertical SHOW SLAVE STATUS +#*************************** + +STOP SLAVE; +RESET SLAVE; + +--echo +--echo *** Drop t14 *** +DROP TABLE t14; + +connection master; +DROP TABLE t14; +RESET MASTER; + +connection slave; +START SLAVE; + +################################################# +--echo +--echo ************************************************* +--echo * - Alter Master adding columns at end of table * +--echo * Expect: Error 1054 * +--echo ************************************************* +--echo +--echo *** Create t15 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t15 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t15 on Master *** +connection master; +eval CREATE TABLE t15 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t15 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT,3.00), + (2,@b1,'JOE',DEFAULT,DEFAULT,3.00), + (3,@b1,'QA',DEFAULT,DEFAULT,3.00); +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7,c2 FROM t15 ORDER BY c1; + +--echo +--echo ******************************************** +--echo *** Expect slave to fail with Error 1054 *** +--echo ******************************************** +--echo +connection slave; +wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # +--query_vertical SHOW SLAVE STATUS +STOP SLAVE; +RESET SLAVE; + +--echo +--echo *** Drop t15 *** +DROP TABLE t15; + +connection master; +DROP TABLE t15; +RESET MASTER; + +connection slave; +START SLAVE; + +#################################################### +--echo +--echo ************************************************ +--echo * - Create index on Master column not on slave * +--echo * Expect:Warning * +--echo ************************************************ +--echo +--echo *** Create t16 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t16 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t16 on Master *** +connection master; +eval CREATE TABLE t16 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Create Index and Data Insert *** +connection master; +CREATE INDEX part_of_c6 ON t16 (c6); +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t16 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), + (2,@b1,'JOE',2,DEFAULT), + (3,@b1,'QA',3,DEFAULT); +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7 FROM t16 ORDER BY c1; + +# Uncomment the below when bug 30434 is patched + +#--echo *** Select on Slave **** +#sync_slave_with_master; +#SELECT c1,hex(c4),c5 FROM t16 ORDER BY c1; +# +#--echo *** Drop t16 *** +#connection master; +#DROP TABLE t16; +#sync_slave_with_master; + +# Remove the below when bug 30434 is patched +#******************************************* +--echo +--echo ***************** +--echo *** BUG 30434 *** +--echo ***************** +--echo +connection slave; +wait_for_slave_to_stop; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 4 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # +--query_vertical SHOW SLAVE STATUS +STOP SLAVE; +RESET SLAVE; + +--echo +--echo *** Drop t16 *** +DROP TABLE t16; + +connection master; +DROP TABLE t16; +RESET MASTER; + +connection slave; +START SLAVE; +#******************************************* + +#################################################### +--echo +--echo ***************************************************** +--echo * - Delete rows using column on Master not on slave * +--echo * Expect: Rows Deleted * +--echo ***************************************************** +--echo +--echo *** Create t17 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t17 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t17 on Master *** +connection master; +eval CREATE TABLE t17 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t17 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), + (2,@b1,'JOE',2,DEFAULT), + (3,@b1,'QA',3,DEFAULT); +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; + +--echo +--echo ** Select * from Slave ** +sync_slave_with_master; +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; + +--echo +--echo ** Delete from master ** +connection master; +DELETE FROM t17 WHERE c6 = 3; +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; + +--echo +--echo ** Check slave ** +sync_slave_with_master; +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; + + +connection master; +DROP TABLE t17; +sync_slave_with_master; +--echo + +#################################################### +--echo +--echo ***************************************************** +--echo * - Update row using column on Master not on slave * +--echo * Expect: Rows updated * +--echo ***************************************************** +--echo +--echo ** Bug30674 ** +--echo +--echo *** Create t18 on slave *** +--echo + +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t18 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t18 on Master *** +connection master; +eval CREATE TABLE t18 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 INT DEFAULT '1', + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); + +INSERT INTO t18 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), + (2,@b1,'JOE',2,DEFAULT), + (3,@b1,'QA',3,DEFAULT); +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; + +--echo +--echo ** Select * from Slave ** +sync_slave_with_master; +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; + +--echo +--echo ** update from master ** +connection master; +####################################### +# This test should be uncommented +# once bug30674 is patched +####################################### + +#*************************** +#UPDATE t18 SET c5 = 'TEST' WHERE c6 = 3; +#*************************** + +--replace_column 5 CURRENT_TIMESTAMP +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; + +--echo +--echo ** Check slave ** +sync_slave_with_master; +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; + +connection master; +DROP TABLE t18; +sync_slave_with_master; +--echo + +#################################################### +--echo +--echo ***************************************************** +--echo * - Insert UUID column on Master not on slave * +--echo * Expect: Rows inserted * +--echo ***************************************************** +--echo +--echo *** Create t5 on slave *** +STOP SLAVE; +RESET SLAVE; +eval CREATE TABLE t5 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) + ) ENGINE=$engine_type; + +--echo +--echo *** Create t5 on Master *** +connection master; +eval CREATE TABLE t5 (c1 INT KEY, c4 BLOB, c5 CHAR(5), + c6 LONG, + c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP + )ENGINE=$engine_type; + +RESET MASTER; + +--echo +--echo *** Start Slave *** +connection slave; +START SLAVE; + +--echo +--echo *** Master Data Insert *** +connection master; +set @b1 = 'b1b1b1b1'; +INSERT INTO t5 () VALUES(1,@b1,'Kyle',UUID(),DEFAULT), + (2,@b1,'JOE',UUID(),DEFAULT), + (3,@b1,'QA',UUID(),DEFAULT); +--replace_column 4 UUID 5 TIME +SELECT c1,hex(c4),c5,c6,c7 FROM t5 ORDER BY c1; + +--echo +--echo ** Select * from Slave ** +sync_slave_with_master; +SELECT c1,hex(c4),c5 FROM t5 ORDER BY c1; + +connection master; +DROP TABLE t5; +sync_slave_with_master; +--echo -# END of the tests +# END of 5.1 tests case diff --git a/mysql-test/extra/rpl_tests/rpl_row_charset.test b/mysql-test/extra/rpl_tests/rpl_row_charset.test index a21ed5bb841..c1eccff9bd5 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_charset.test +++ b/mysql-test/extra/rpl_tests/rpl_row_charset.test @@ -38,7 +38,7 @@ show create database mysqltest3; connection master; use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100)); +--eval create table t1 (a int auto_increment primary key, b varchar(100))engine=$engine_type; set character_set_client=cp850, collation_connection=latin2_croatian_ci; insert into t1 (b) values(@@character_set_server); insert into t1 (b) values(@@collation_server); @@ -146,13 +146,15 @@ set collation_server=9999998; select "--- --3943--" as ""; use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); +--eval CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=$engine_type; SET CHARACTER_SET_CLIENT=koi8r, CHARACTER_SET_CONNECTION=cp1251, CHARACTER_SET_RESULTS=koi8r; INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; sync_slave_with_master; +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; connection master; diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 71647112126..79e21382d4c 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -566,3 +566,35 @@ reap; connection default; drop table t2; disconnect flush; + +# +# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash +# +# Test HANDLER statements in conjunction with temporary tables. While the temporary table +# is open by a HANDLER, no other statement can access it. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create temporary table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), + (5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +select a,b from t1; +handler t1 open as a1; +handler a1 read a first; +handler a1 read a next; +handler a1 read a next; +--error ER_CANT_REOPEN_TABLE +select a,b from t1; +handler a1 read a prev; +handler a1 read a prev; +handler a1 read a=(6) where b="g"; +handler a1 close; +select a,b from t1; +handler t1 open as a2; +handler a2 read a first; +handler a2 read a last; +handler a2 read a prev; +handler a2 close; +drop table t1; diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index c8d3ba79e39..d55b404621d 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1020,6 +1020,55 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +########################################################################### + +--echo +--echo # +--echo # Bug#27610: ALTER TABLE ROW_FORMAT=... does not rebuild the table. +--echo # + +--echo +--echo # - prepare; +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo + +CREATE TABLE t1(c INT) + ENGINE = InnoDB + ROW_FORMAT = COMPACT; + +--echo +--echo # - initial check; +--echo + +SELECT table_schema, table_name, row_format +FROM INFORMATION_SCHEMA.TABLES +WHERE table_schema = DATABASE() AND table_name = 't1'; + +--echo +--echo # - change ROW_FORMAT and check; +--echo + +ALTER TABLE t1 ROW_FORMAT = REDUNDANT; + +--echo + +SELECT table_schema, table_name, row_format +FROM INFORMATION_SCHEMA.TABLES +WHERE table_schema = DATABASE() AND table_name = 't1'; + +--echo +--echo # - that's it, cleanup. +--echo + +DROP TABLE t1; + +########################################################################### + --echo End of 5.0 tests # Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index 3c9e6384c64..b6b77101874 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -610,7 +610,6 @@ id ev_nm ev_cnt 6 ev_sched_1823 6 DROP TABLE event_log; SET GLOBAL event_scheduler = OFF; -DROP DATABASE events_test; SET GLOBAL event_scheduler= ON; CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00' DO BEGIN @@ -618,3 +617,105 @@ SELECT 1; END;| SET GLOBAL event_scheduler= OFF; DROP EVENT bug28641; + +##################################################################### +# +# BUG#31111: --read-only crashes MySQL (events fail to load). +# +##################################################################### + +DROP USER mysqltest_u1@localhost; +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e2; + +GRANT EVENT ON *.* TO mysqltest_u1@localhost; + +SET GLOBAL READ_ONLY = 1; + +# +# Connection: u1_con (mysqltest_u1@localhost/events_test). +# + +CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement + +ALTER EVENT e1 COMMENT 'comment'; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement + +DROP EVENT e1; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement + +# +# Connection: root_con (root@localhost/events_test). +# + +CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1; + +ALTER EVENT e1 COMMENT 'comment'; + +DROP EVENT e1; + +SET GLOBAL READ_ONLY = 0; + +# +# Connection: u1_con (mysqltest_u1@localhost/test). +# + +CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1; +CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1; + +SELECT +event_name, +last_executed IS NULL, +definer +FROM INFORMATION_SCHEMA.EVENTS +WHERE event_schema = 'events_test'; +event_name last_executed IS NULL definer +e1 1 mysqltest_u1@localhost +e2 1 mysqltest_u1@localhost + +# +# Connection: root_con (root@localhost/events_test). +# + +SET GLOBAL READ_ONLY = 1; + +SET GLOBAL EVENT_SCHEDULER = ON; + +# Waiting for the event scheduler to execute and drop event e1... + +# Waiting for the event scheduler to execute and update event e2... + +SET GLOBAL EVENT_SCHEDULER = OFF; + +SELECT +event_name, +last_executed IS NULL, +definer +FROM INFORMATION_SCHEMA.EVENTS +WHERE event_schema = 'events_test'; +event_name last_executed IS NULL definer +e2 0 mysqltest_u1@localhost + +DROP EVENT e1; +ERROR HY000: Unknown event 'e1' + +# Cleanup. + +DROP EVENT e2; + +SET GLOBAL READ_ONLY = 0; + +# +# Connection: default +# + +DROP USER mysqltest_u1@localhost; + +##################################################################### +# +# End of BUG#31111. +# +##################################################################### + +DROP DATABASE events_test; diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 02b1459afd0..a3744b36e87 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2299,8 +2299,7 @@ Handler_read_next 0 FLUSH STATUS; DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x FROM t1) > 10000; -Warnings: -Error 1242 Subquery returns more than 1 row +ERROR 21000: Subquery returns more than 1 row SHOW STATUS LIKE 'handler_read__e%'; Variable_name Value Handler_read_key 8 diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index e9e5c7dbdd5..d9a1a0aa12b 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -575,3 +575,65 @@ ERROR 42S02: Table 'test.t1' doesn't exist handler t1 close; handler t2 close; drop table t2; +drop table if exists t1; +create temporary table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), +(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +select a,b from t1; +a b +0 a +1 b +2 c +3 d +4 e +5 f +6 g +7 h +8 i +9 j +handler t1 open as a1; +handler a1 read a first; +a b +0 a +handler a1 read a next; +a b +1 b +handler a1 read a next; +a b +2 c +select a,b from t1; +ERROR HY000: Can't reopen table: 'a1' +handler a1 read a prev; +a b +1 b +handler a1 read a prev; +a b +0 a +handler a1 read a=(6) where b="g"; +a b +6 g +handler a1 close; +select a,b from t1; +a b +0 a +1 b +2 c +3 d +4 e +5 f +6 g +7 h +8 i +9 j +handler t1 open as a2; +handler a2 read a first; +a b +0 a +handler a2 read a last; +a b +9 j +handler a2 read a prev; +a b +8 i +handler a2 close; +drop table t1; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 715e5ab03d6..b42fdc864fe 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -575,3 +575,65 @@ ERROR 42S02: Table 'test.t1' doesn't exist handler t1 close; handler t2 close; drop table t2; +drop table if exists t1; +create temporary table t1 (a int, b char(1), key a(a), key b(a,b)); +insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"), +(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j"); +select a,b from t1; +a b +0 a +1 b +2 c +3 d +4 e +5 f +6 g +7 h +8 i +9 j +handler t1 open as a1; +handler a1 read a first; +a b +0 a +handler a1 read a next; +a b +1 b +handler a1 read a next; +a b +2 c +select a,b from t1; +ERROR HY000: Can't reopen table: 'a1' +handler a1 read a prev; +a b +1 b +handler a1 read a prev; +a b +0 a +handler a1 read a=(6) where b="g"; +a b +6 g +handler a1 close; +select a,b from t1; +a b +0 a +1 b +2 c +3 d +4 e +5 f +6 g +7 h +8 i +9 j +handler t1 open as a2; +handler a2 read a first; +a b +0 a +handler a2 read a last; +a b +9 j +handler a2 read a prev; +a b +8 i +handler a2 close; +drop table t1; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 44d874ef018..05db4436a65 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1288,6 +1288,40 @@ a b 3 2 1 1 DROP TABLE t1; + +# +# Bug#27610: ALTER TABLE ROW_FORMAT=... does not rebuild the table. +# + +# - prepare; + +DROP TABLE IF EXISTS t1; + +CREATE TABLE t1(c INT) +ENGINE = InnoDB +ROW_FORMAT = COMPACT; + +# - initial check; + +SELECT table_schema, table_name, row_format +FROM INFORMATION_SCHEMA.TABLES +WHERE table_schema = DATABASE() AND table_name = 't1'; +table_schema table_name row_format +test t1 Compact + +# - change ROW_FORMAT and check; + +ALTER TABLE t1 ROW_FORMAT = REDUNDANT; + +SELECT table_schema, table_name, row_format +FROM INFORMATION_SCHEMA.TABLES +WHERE table_schema = DATABASE() AND table_name = 't1'; +table_schema table_name row_format +test t1 Redundant + +# - that's it, cleanup. + +DROP TABLE t1; End of 5.0 tests CREATE TABLE `t2` ( `k` int(11) NOT NULL auto_increment, diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index a2bed75a709..3db5e926d30 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -530,3 +530,32 @@ ORDER BY c.b, c.d a b c d e f g h i j a b c d 2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL DROP TABLE t1, t2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT); +INSERT INTO t1 VALUES (), (), (); +SELECT 1 AS c1 +FROM t1 +ORDER BY ( +SELECT 1 AS c2 +FROM t1 +GROUP BY GREATEST(LAST_INSERT_ID(), t1.a) ASC +LIMIT 1); +c1 +1 +1 +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, INDEX (a,b)); +INSERT INTO t1 (a, b) +VALUES +(1,1), (1,2), (1,3), (1,4), (1,5), +(2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE +(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by +SELECT 1 as RES FROM t1 AS t1_outer WHERE +(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; +RES +DROP TABLE t1; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index f10ae4b4df5..287fbd7e7f3 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -328,4 +328,26 @@ drop table t1; drop table t1; End of 5.0 tests flush logs; +BUG#31611: Security risk with BINLOG statement +SET BINLOG_FORMAT=ROW; +CREATE DATABASE mysqltest1; +CREATE USER untrusted@localhost; +GRANT SELECT ON mysqltest1.* TO untrusted@localhost; +SHOW GRANTS FOR untrusted@localhost; +Grants for untrusted@localhost +GRANT USAGE ON *.* TO 'untrusted'@'localhost' +GRANT SELECT ON `mysqltest1`.* TO 'untrusted'@'localhost' +USE mysqltest1; +CREATE TABLE t1 (a INT, b CHAR(64)); +flush logs; +INSERT INTO t1 VALUES (1,USER()); +flush logs; +mysqlbinlog var/log/master-bin.000017 > var/tmp/bug31611.sql +mysql mysqltest1 -uuntrusted < var/tmp/bug31611.sql +INSERT INTO t1 VALUES (1,USER()); +ERROR 42000: INSERT command denied to user 'untrusted'@'localhost' for table 't1' +SELECT * FROM t1; +a b +1 root@localhost +DROP DATABASE mysqltest1; End of 5.1 tests diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index edac68a88d6..9d0906ad5e7 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -2680,4 +2680,21 @@ t1 CREATE TABLE `t1` ( KEY `c` (`c`(10)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +drop table if exists t1, t2; +create table t1 (a int, b int); +create table t2 like t1; +insert into t1 (a, b) values (1,1), (1,2), (1,3), (1,4), (1,5), +(2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); +insert into t2 select a, max(b) from t1 group by a; +prepare stmt from "delete from t2 where (select (select max(b) from t1 group +by a having a < 2) x from t1) > 10000"; +delete from t2 where (select (select max(b) from t1 group +by a having a < 2) x from t1) > 10000; +ERROR 21000: Subquery returns more than 1 row +execute stmt; +ERROR 21000: Subquery returns more than 1 row +execute stmt; +ERROR 21000: Subquery returns more than 1 row +deallocate prepare stmt; +drop table t1, t2; End of 5.1 tests. diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d1d85aef0ec..1acb82e4137 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4081,6 +4081,41 @@ SELECT `x` FROM v3; x 1 DROP VIEW v1, v2, v3; + +# +# Bug#30736: Row Size Too Large Error Creating a Table and +# Inserting Data. +# +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; + +CREATE TABLE t1( +c1 DECIMAL(10, 2), +c2 FLOAT); + +INSERT INTO t1 VALUES (0, 1), (2, 3), (4, 5); + +CREATE TABLE t2( +c3 DECIMAL(10, 2)) +SELECT +c1 * c2 AS c3 +FROM t1; + +SELECT * FROM t1; +c1 c2 +0.00 1 +2.00 3 +4.00 5 + +SELECT * FROM t2; +c3 +0.00 +6.00 +20.00 + +DROP TABLE t1; +DROP TABLE t2; + End of 5.0 tests create table t1(a INT, KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 1b14d75cd9c..b81f8ea64c9 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1428,7 +1428,6 @@ create function bug20701() returns varchar(25) binary return "test"; ERROR 42000: This version of MySQL doesn't yet support 'return value collation' create function bug20701() returns varchar(25) return "test"; drop function bug20701; -End of 5.1 tests create procedure proc_26503_error_1() begin retry: @@ -1523,3 +1522,60 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT ..inexistent(); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1 USE test; +create function f1() returns int +begin +set @test = 1, password = password('foo'); +return 1; +end| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +create trigger t1 +before insert on t2 for each row set password = password('foo');| +ERROR HY000: Not allowed to set autocommit from a stored function or trigger +drop function if exists f1; +drop function if exists f2; +drop table if exists t1, t2; +create function f1() returns int +begin +drop temporary table t1; +return 1; +end| +create temporary table t1 as select f1(); +ERROR HY000: Can't reopen table: 't1' +create function f2() returns int +begin +create temporary table t2 as select f1(); +return 1; +end| +create temporary table t1 as select f2(); +ERROR HY000: Can't reopen table: 't1' +drop function f1; +drop function f2; +create function f1() returns int +begin +drop temporary table t2,t1; +return 1; +end| +create function f2() returns int +begin +create temporary table t2 as select f1(); +return 1; +end| +create temporary table t1 as select f2(); +ERROR HY000: Can't reopen table: 't2' +drop function f1; +drop function f2; +create temporary table t2(a int); +select * from t2; +a +create function f2() returns int +begin +drop temporary table t2; +return 1; +end| +select f2(); +f2() +1 +drop function f2; +drop table t2; +ERROR 42S02: Unknown table 't2' +End of 5.1 tests diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index da27a71c1a1..cb5afcf5f17 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -11,7 +11,7 @@ RETURNS STRING SONAME "UDF_EXAMPLE_LIB"; CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "UDF_EXAMPLE_LIB"; select myfunc_double(); -ERROR HY000: myfunc_double must have at least one argument +ERROR HY000: Can't initialize function 'myfunc_double'; myfunc_double must have at least one argument select myfunc_double(1); myfunc_double(1) 49.00 @@ -24,26 +24,26 @@ select myfunc_int(); myfunc_int() 0 select lookup(); -ERROR HY000: Wrong arguments to lookup; Use the source +ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source select lookup("127.0.0.1"); lookup("127.0.0.1") 127.0.0.1 select lookup(127,0,0,1); -ERROR HY000: Wrong arguments to lookup; Use the source +ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source select lookup("localhost"); lookup("localhost") 127.0.0.1 select reverse_lookup(); -ERROR HY000: Wrong number of arguments to reverse_lookup; Use the source +ERROR HY000: Can't initialize function 'reverse_lookup'; Wrong number of arguments to reverse_lookup; Use the source select reverse_lookup("127.0.0.1"); select reverse_lookup(127,0,0,1); select reverse_lookup("localhost"); reverse_lookup("localhost") NULL select avgcost(); -ERROR HY000: wrong number of arguments: AVGCOST() requires two arguments +ERROR HY000: Can't initialize function 'avgcost'; wrong number of arguments: AVGCOST() requires two arguments select avgcost(100,23.76); -ERROR HY000: wrong argument type: AVGCOST() requires an INT and a REAL +ERROR HY000: Can't initialize function 'avgcost'; wrong argument type: AVGCOST() requires an INT and a REAL create table t1(sum int, price float(24)); insert into t1 values(100, 50.00), (100, 100.00); select avgcost(sum, price) from t1; diff --git a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result index 8d1dcc4ef18..1d61e2c59c2 100644 --- a/mysql-test/suite/ndb/r/ndb_condition_pushdown.result +++ b/mysql-test/suite/ndb/r/ndb_condition_pushdown.result @@ -1888,5 +1888,27 @@ set engine_condition_pushdown = 1; SELECT fname, lname FROM t1 WHERE (fname like 'Y%') or (lname like 'F%'); fname lname Young Foo +drop table t1; +create table t1 (a int, b int, c int, d int, primary key using hash(a)) +engine=ndbcluster; +insert into t1 values (10,1,100,0+0x1111); +insert into t1 values (20,2,200,0+0x2222); +insert into t1 values (30,3,300,0+0x3333); +insert into t1 values (40,4,400,0+0x4444); +insert into t1 values (50,5,500,0+0x5555); +set engine_condition_pushdown = on; +select a,b,d from t1 +where b in (0,1,2,5) +order by b; +a b d +10 1 4369 +20 2 8738 +50 5 21845 +a b d +10 1 4369 +20 2 8738 +50 5 21845 +Warnings: +Warning 4294 Scan filter is too large, discarded set engine_condition_pushdown = @old_ecpd; DROP TABLE t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/ndb/r/ndb_lock_table.result b/mysql-test/suite/ndb/r/ndb_lock_table.result new file mode 100644 index 00000000000..a0550273e1a --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_lock_table.result @@ -0,0 +1,11 @@ +drop table if exists t1; +create table t1 (a int) engine ndb; +set autocommit=1; +lock table t1 write; +set autocommit=0; +insert into t1 values (0); +rollback; +select * from t1; +a +unlock tables; +drop table t1; diff --git a/mysql-test/suite/ndb/r/ndb_multi.result b/mysql-test/suite/ndb/r/ndb_multi.result index 2bc49bf9b45..17380b10fd7 100644 --- a/mysql-test/suite/ndb/r/ndb_multi.result +++ b/mysql-test/suite/ndb/r/ndb_multi.result @@ -121,3 +121,24 @@ show tables; Tables_in_db t2 drop database db; +use test; +create table `test`.`t1$EX` + (server_id int unsigned, +master_server_id int unsigned, +master_epoch bigint unsigned, +count int unsigned, +primary key(server_id, master_server_id, +master_epoch, count)) +engine ndb; +show tables like '%$%'; +Tables_in_test (%$%) +t1$ex +use test; +show tables like '%$%'; +Tables_in_test (%$%) +t1$ex +drop table `test`.`t1$EX`; +show tables like '%$%'; +Tables_in_test (%$%) +show tables like '%$%'; +Tables_in_test (%$%) diff --git a/mysql-test/suite/ndb/r/ndb_update.result b/mysql-test/suite/ndb/r/ndb_update.result index daea0e27a6a..ed51daee5cb 100644 --- a/mysql-test/suite/ndb/r/ndb_update.result +++ b/mysql-test/suite/ndb/r/ndb_update.result @@ -41,6 +41,14 @@ pk1 b c 10 0 0 12 2 2 14 1 1 +create unique index ib on t1(b); +update t1 set c = 4 where pk1 = 12; +update ignore t1 set b = 55 where pk1 = 14; +select * from t1 order by pk1; +pk1 b c +10 0 0 +12 2 4 +14 55 1 DROP TABLE IF EXISTS t1; CREATE TABLE t1 (a int, b int, KEY (a, b)) ENGINE=ndbcluster; CREATE TABLE t2 (a int, b int, UNIQUE KEY (a, b)) ENGINE=ndbcluster; diff --git a/mysql-test/suite/ndb/r/ndb_update_no_read.result b/mysql-test/suite/ndb/r/ndb_update_no_read.result new file mode 100644 index 00000000000..4373800d338 --- /dev/null +++ b/mysql-test/suite/ndb/r/ndb_update_no_read.result @@ -0,0 +1,75 @@ +DROP TABLE IF EXISTS t1; +create table t1 (a int not null primary key, b int not null, c int, +unique index_b (b) using hash) +engine ndb; +insert into t1 values (1,10,1),(2,9,1),(3,8,1),(4,7,1),(5,6,1),(6,5,2),(7,4,2),(8,3,2), +(9,2,2),(10,1,2); +update t1 set c = 111, b = 20 where a = 1; +select * from t1 where a = 1 order by a; +a b c +1 20 111 +delete from t1 where a = 1; +select * from t1 where a = 1 order by a; +a b c +update t1 set c = 12, b = 19 where b = 2; +select * from t1 where b = 2 order by a; +a b c +delete from t1 where b = 19; +select * from t1 where b = 19 order by a; +a b c +update t1 set c = 22 where a = 10 or a >= 10; +select * from t1 order by a; +a b c +2 9 1 +3 8 1 +4 7 1 +5 6 1 +6 5 2 +7 4 2 +8 3 2 +10 1 22 +update t1 set c = 23 where a in (8,10); +select * from t1 order by a; +a b c +2 9 1 +3 8 1 +4 7 1 +5 6 1 +6 5 2 +7 4 2 +8 3 23 +10 1 23 +update t1 set c = 23 where a in (7,8) or a >= 10; +select * from t1 order by a; +a b c +2 9 1 +3 8 1 +4 7 1 +5 6 1 +6 5 2 +7 4 23 +8 3 23 +10 1 23 +update t1 set c = 11 where a = 3 or b = 7; +select * from t1 where a = 3 or b = 7 order by a; +a b c +3 8 11 +4 7 11 +update t1 set a = 13, b = 20 where a = 3; +select * from t1 where a = 13 order by a; +a b c +13 20 11 +update t1 set a = 12, b = 19 where b = 7; +select * from t1 where b = 19 order by a; +a b c +12 19 11 +select * from t1 where b = 7 order by a; +a b c +update t1 set c = 12, b = 29 where a = 5 and b = 6; +select * from t1 where b = 19 order by a; +a b c +12 19 11 +delete from t1 where b = 6 and c = 12; +select * from t1 where b = 6 order by a; +a b c +drop table t1; diff --git a/mysql-test/suite/ndb/t/disabled.def b/mysql-test/suite/ndb/t/disabled.def index 9c2dc80d5ee..f876039a042 100644 --- a/mysql-test/suite/ndb/t/disabled.def +++ b/mysql-test/suite/ndb/t/disabled.def @@ -9,9 +9,6 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -ndb_dd_sql_features : Bug#29102 ndb_dd_sql_features fails in pushbuild -ndb_load : BUG#17233 2006-05-04 tomas failed load data from infile causes mysqld dbug_assert, binlog not flushed - partition_03ndb : BUG#16385 2006-03-24 mikael Partitions: crash when updating a range partitioned NDB table ndb_partition_error2 : HF is not sure if the test can work as internded on all the platforms diff --git a/mysql-test/suite/ndb/t/ndb_condition_pushdown.test b/mysql-test/suite/ndb/t/ndb_condition_pushdown.test index ab56430ac1d..9e6a5e90e40 100644 --- a/mysql-test/suite/ndb/t/ndb_condition_pushdown.test +++ b/mysql-test/suite/ndb/t/ndb_condition_pushdown.test @@ -1752,5 +1752,1030 @@ SELECT fname, lname FROM t1 WHERE (fname like 'Y%') or (lname like 'F%'); set engine_condition_pushdown = 1; SELECT fname, lname FROM t1 WHERE (fname like 'Y%') or (lname like 'F%'); +# bug#29390 (scan filter is too large, discarded) + +drop table t1; + +create table t1 (a int, b int, c int, d int, primary key using hash(a)) + engine=ndbcluster; + +insert into t1 values (10,1,100,0+0x1111); +insert into t1 values (20,2,200,0+0x2222); +insert into t1 values (30,3,300,0+0x3333); +insert into t1 values (40,4,400,0+0x4444); +insert into t1 values (50,5,500,0+0x5555); + +set engine_condition_pushdown = on; + +select a,b,d from t1 + where b in (0,1,2,5) + order by b; + +--disable_query_log +select a,b,d from t1 + where b in ( +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2, +0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2,5,0,1,2) + order by b; +--enable_query_log + set engine_condition_pushdown = @old_ecpd; DROP TABLE t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/ndb/t/ndb_lock_table.test b/mysql-test/suite/ndb/t/ndb_lock_table.test new file mode 100644 index 00000000000..6c21e8e8232 --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_lock_table.test @@ -0,0 +1,15 @@ +-- source include/have_ndb.inc + +# BUG 30996 +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int) engine ndb; +set autocommit=1; +lock table t1 write; +set autocommit=0; +insert into t1 values (0); +rollback; +select * from t1; +unlock tables; +drop table t1; diff --git a/mysql-test/suite/ndb/t/ndb_multi.test b/mysql-test/suite/ndb/t/ndb_multi.test index b8e052d606b..c2217b51d08 100644 --- a/mysql-test/suite/ndb/t/ndb_multi.test +++ b/mysql-test/suite/ndb/t/ndb_multi.test @@ -122,4 +122,33 @@ connection server2; show tables; drop database db; + +# +# bug#31470, ndb table with special characters in name +# are not discovered correctly +connection server1; +use test; +create table `test`.`t1$EX` + (server_id int unsigned, + master_server_id int unsigned, + master_epoch bigint unsigned, + count int unsigned, + primary key(server_id, master_server_id, + master_epoch, count)) + engine ndb; + +# check that table shows up ok on both servers +# before bugfix table would not show up on server2 +--replace_regex /EX/ex/ +show tables like '%$%'; +connection server2; +use test; +--replace_regex /EX/ex/ +show tables like '%$%'; + +# check cleanup +drop table `test`.`t1$EX`; +show tables like '%$%'; + connection server1; +show tables like '%$%'; diff --git a/mysql-test/suite/ndb/t/ndb_update.test b/mysql-test/suite/ndb/t/ndb_update.test index c45f990edcc..ab0fbee171e 100644 --- a/mysql-test/suite/ndb/t/ndb_update.test +++ b/mysql-test/suite/ndb/t/ndb_update.test @@ -35,6 +35,11 @@ UPDATE IGNORE t1 set pk1 = 1, c = 2 where pk1 = 4; select * from t1 order by pk1; UPDATE t1 set pk1 = pk1 + 10; select * from t1 order by pk1; +# bug#25817 +create unique index ib on t1(b); +update t1 set c = 4 where pk1 = 12; +update ignore t1 set b = 55 where pk1 = 14; +select * from t1 order by pk1; --disable_warnings DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/ndb/t/ndb_update_no_read.test b/mysql-test/suite/ndb/t/ndb_update_no_read.test new file mode 100644 index 00000000000..60bea53b7b5 --- /dev/null +++ b/mysql-test/suite/ndb/t/ndb_update_no_read.test @@ -0,0 +1,79 @@ +-- source include/have_ndb.inc +-- source include/not_embedded.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +# +# New test case for WL 3686 (which is not until CGE-6.3) +# but test is committed in 5.1 to verify consistant results. +# +# When only constant expressions in update statements and +# only PK or UK in WHERE clause. No extra WHERE parts are +# allowed. WL #3687 takes of more advanced variants of +# avoiding the read before the update/delete + +create table t1 (a int not null primary key, b int not null, c int, + unique index_b (b) using hash) +engine ndb; + +insert into t1 values (1,10,1),(2,9,1),(3,8,1),(4,7,1),(5,6,1),(6,5,2),(7,4,2),(8,3,2), + (9,2,2),(10,1,2); + +# These ones should use optimisation + +update t1 set c = 111, b = 20 where a = 1; + +select * from t1 where a = 1 order by a; + +delete from t1 where a = 1; + +select * from t1 where a = 1 order by a; + +update t1 set c = 12, b = 19 where b = 2; + +select * from t1 where b = 2 order by a; + +delete from t1 where b = 19; + +select * from t1 where b = 19 order by a; + +update t1 set c = 22 where a = 10 or a >= 10; + +select * from t1 order by a; + +update t1 set c = 23 where a in (8,10); + +select * from t1 order by a; + +update t1 set c = 23 where a in (7,8) or a >= 10; + +select * from t1 order by a; + +# These ones should not use optimisation + +update t1 set c = 11 where a = 3 or b = 7; + +select * from t1 where a = 3 or b = 7 order by a; + +update t1 set a = 13, b = 20 where a = 3; + +select * from t1 where a = 13 order by a; + +update t1 set a = 12, b = 19 where b = 7; + +select * from t1 where b = 19 order by a; + +select * from t1 where b = 7 order by a; + +update t1 set c = 12, b = 29 where a = 5 and b = 6; + +select * from t1 where b = 19 order by a; + +delete from t1 where b = 6 and c = 12; + +select * from t1 where b = 6 order by a; + +drop table t1; + diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 96dfdbed541..a3ff022c43c 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -53,7 +53,7 @@ DELETE FROM t2 WHERE a = 2; --echo ******************** LOAD DATA INFILE ******************** --exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/ LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat SELECT * FROM t1; --source suite/rpl/include/rpl_mixed_check_select.inc --source suite/rpl/include/rpl_mixed_clear_tables.inc diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result Binary files differindex 18906617925..a7d9e12aabd 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result Binary files differindex 5bc1a13b107..a8762d447d6 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result diff --git a/mysql-test/suite/rpl/r/rpl_row_charset.result b/mysql-test/suite/rpl/r/rpl_row_charset.result index e51f3e57d1f..caaa9d8332b 100644 --- a/mysql-test/suite/rpl/r/rpl_row_charset.result +++ b/mysql-test/suite/rpl/r/rpl_row_charset.result @@ -40,7 +40,7 @@ show create database mysqltest3; Database Create Database mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100)); +create table t1 (a int auto_increment primary key, b varchar(100))engine=myisam;; set character_set_client=cp850, collation_connection=latin2_croatian_ci; insert into t1 (b) values(@@character_set_server); insert into t1 (b) values(@@collation_server); @@ -117,7 +117,7 @@ master-bin.000001 # Query # # create database mysqltest2 character set latin2 master-bin.000001 # Query # # create database mysqltest3 master-bin.000001 # Query # # drop database mysqltest3 master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100)) +master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=myisam master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) @@ -177,14 +177,16 @@ select "--- --3943--" as ""; --- --3943-- use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); +CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=myisam;; SET CHARACTER_SET_CLIENT=koi8r, CHARACTER_SET_CONNECTION=cp1251, CHARACTER_SET_RESULTS=koi8r; INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 diff --git a/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result b/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result new file mode 100644 index 00000000000..eb1dc585457 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_charset_innodb.result @@ -0,0 +1,215 @@ +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; +set timestamp=1000000000; +drop database if exists mysqltest2; +drop database if exists mysqltest3; +create database mysqltest2 character set latin2; +set @@character_set_server=latin5; +create database mysqltest3; + +--- --master-- +show create database mysqltest2; +Database Create Database +mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ +show create database mysqltest3; +Database Create Database +mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ + +--- --slave-- +show create database mysqltest2; +Database Create Database +mysqltest2 CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET latin2 */ +show create database mysqltest3; +Database Create Database +mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET latin5 */ +set @@collation_server=armscii8_bin; +drop database mysqltest3; +create database mysqltest3; + +--- --master-- +show create database mysqltest3; +Database Create Database +mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ + +--- --slave-- +show create database mysqltest3; +Database Create Database +mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ +use mysqltest2; +create table t1 (a int auto_increment primary key, b varchar(100))engine=innodb;; +set character_set_client=cp850, collation_connection=latin2_croatian_ci; +insert into t1 (b) values(@@character_set_server); +insert into t1 (b) values(@@collation_server); +insert into t1 (b) values(@@character_set_client); +insert into t1 (b) values(@@character_set_connection); +insert into t1 (b) values(@@collation_connection); + +--- --master-- +select * from t1 order by a; +a b +1 armscii8 +2 armscii8_bin +3 cp850 +4 latin2 +5 latin2_croatian_ci + +--- --slave-- +select * from mysqltest2.t1 order by a; +a b +1 armscii8 +2 armscii8_bin +3 cp850 +4 latin2 +5 latin2_croatian_ci +select "--- --muller--" as ""; + +--- --muller-- +set character_set_client=latin1, collation_connection=latin1_german1_ci; +truncate table t1; +insert into t1 (b) values(@@collation_connection); +insert into t1 (b) values(LEAST("Müller","Muffler")); +set collation_connection=latin1_german2_ci; +insert into t1 (b) values(@@collation_connection); +insert into t1 (b) values(LEAST("Müller","Muffler")); + +--- --master-- +select * from t1 order by a; +a b +1 latin1_german1_ci +2 Muffler +3 latin1_german2_ci +4 Müller + +--- --slave-- +select * from mysqltest2.t1 order by a; +a b +1 latin1_german1_ci +2 Muffler +3 latin1_german2_ci +4 Müller +select "--- --INSERT--" as ""; + +--- --INSERT-- +set @a= _cp850 'Müller' collate cp850_general_ci; +truncate table t1; +insert into t1 (b) values(collation(@a)); + +--- --master-- +select * from t1 order by a; +a b +1 cp850_general_ci + +--- --slave-- +select * from mysqltest2.t1 order by a; +a b +1 cp850_general_ci +drop database mysqltest2; +drop database mysqltest3; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # drop database if exists mysqltest2 +master-bin.000001 # Query # # drop database if exists mysqltest3 +master-bin.000001 # Query # # create database mysqltest2 character set latin2 +master-bin.000001 # Query # # create database mysqltest3 +master-bin.000001 # Query # # drop database mysqltest3 +master-bin.000001 # Query # # create database mysqltest3 +master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=innodb +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # drop database mysqltest2 +master-bin.000001 # Query # # drop database mysqltest3 +select "--- --global--" as ""; + +--- --global-- +set global character_set_server=latin2; +set global character_set_server=latin1; +set global character_set_server=latin2; +set global character_set_server=latin1; +select "--- --oneshot--" as ""; + +--- --oneshot-- +set one_shot @@character_set_server=latin5; +set @@max_join_size=1000; +select @@character_set_server; +@@character_set_server +latin5 +select @@character_set_server; +@@character_set_server +latin1 +set @@character_set_server=latin5; +select @@character_set_server; +@@character_set_server +latin5 +select @@character_set_server; +@@character_set_server +latin5 +set one_shot max_join_size=10; +ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server +set character_set_client=9999999; +ERROR 42000: Unknown character set: '9999999' +set collation_server=9999998; +ERROR HY000: Unknown collation: '9999998' +select "--- --3943--" as ""; + +--- --3943-- +use test; +CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=innodb;; +SET CHARACTER_SET_CLIENT=koi8r, +CHARACTER_SET_CONNECTION=cp1251, +CHARACTER_SET_RESULTS=koi8r; +INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); +SET SQL_BIG_SELECTS=1; +select hex(c1), hex(c2) from t1; +hex(c1) hex(c2) +CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +SET SQL_BIG_SELECTS=1; +select hex(c1), hex(c2) from t1; +hex(c1) hex(c2) +CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +drop table t1; +select "--- --6676--" as ""; + +--- --6676-- +create table `t1` ( +`pk` varchar(10) not null default '', +primary key (`pk`) +) engine=innodb default charset=latin1; +set @p=_latin1 'test'; +update t1 set pk='test' where pk=@p; +drop table t1; diff --git a/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result b/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result Binary files differdeleted file mode 100644 index 0b1f2e6c8bf..00000000000 --- a/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result +++ /dev/null diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 0c90eaa4378..426bf93ae97 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -13,5 +13,5 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file -rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. -rpl_row_extraColmaster_ndb : BUG#29549 : Replication of BLOBs fail for NDB +rpl_extraColmaster_innodb : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris +rpl_extraColmaster_myisam : BUG#30854 diff --git a/mysql-test/suite/rpl/t/rpl_extraColmaster_innodb.test b/mysql-test/suite/rpl/t/rpl_extraColmaster_innodb.test index 082c22329fa..5255a9cfbad 100644 --- a/mysql-test/suite/rpl/t/rpl_extraColmaster_innodb.test +++ b/mysql-test/suite/rpl/t/rpl_extraColmaster_innodb.test @@ -12,4 +12,5 @@ set binlog_format=row; set binlog_format=statement; -- source extra/rpl_tests/rpl_extraMaster_Col.test - +set binlog_format=mixed; +-- source extra/rpl_tests/rpl_extraMaster_Col.test diff --git a/mysql-test/suite/rpl/t/rpl_extraColmaster_myisam.test b/mysql-test/suite/rpl/t/rpl_extraColmaster_myisam.test index 5bbd7953294..e6b41eabd0d 100644 --- a/mysql-test/suite/rpl/t/rpl_extraColmaster_myisam.test +++ b/mysql-test/suite/rpl/t/rpl_extraColmaster_myisam.test @@ -11,3 +11,5 @@ set binlog_format=row; set binlog_format=statement; -- source extra/rpl_tests/rpl_extraMaster_Col.test +set binlog_format=mixed; +-- source extra/rpl_tests/rpl_extraMaster_Col.test diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-master.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_charset_innodb-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test b/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test new file mode 100644 index 00000000000..1465500d0eb --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_charset_innodb.test @@ -0,0 +1,9 @@ +######################################################## +# By JBM 2005-02-15 Wrapped to allow reuse of test code# +# Added to skip if ndb is default # +######################################################## +-- source include/not_ndb_default.inc +-- source include/have_binlog_format_row.inc +-- source include/master-slave.inc +let $engine_type=innodb; +-- source extra/rpl_tests/rpl_row_charset.test diff --git a/mysql-test/suite/rpl/t/rpl_row_extraColmaster_ndb.test b/mysql-test/suite/rpl/t/rpl_row_extraColmaster_ndb.test deleted file mode 100644 index b91947e52e2..00000000000 --- a/mysql-test/suite/rpl/t/rpl_row_extraColmaster_ndb.test +++ /dev/null @@ -1,12 +0,0 @@ -########################################### -# Purpose: Wrapper for rpl_extraMaster_Col.test -# Using NDB -########################################### --- source include/have_ndb.inc --- source include/ndb_master-slave.inc --- source include/have_binlog_format_row.inc - -let $engine_type = 'NDB'; - --- source extra/rpl_tests/rpl_extraMaster_Col.test - diff --git a/mysql-test/suite/rpl/t/rpl_stm_extraColmaster_ndb.test b/mysql-test/suite/rpl/t/rpl_stm_extraColmaster_ndb.test deleted file mode 100644 index 84734204439..00000000000 --- a/mysql-test/suite/rpl/t/rpl_stm_extraColmaster_ndb.test +++ /dev/null @@ -1,13 +0,0 @@ -########################################### -# Purpose: Wrapper for rpl_extraMaster_Col.test -# Using NDB -########################################### --- source include/have_ndb.inc --- source include/ndb_master-slave.inc --- source include/have_binlog_format_statement.inc - -let $engine_type = 'NDB'; - --- source extra/rpl_tests/rpl_extraMaster_Col.test - - diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result index ed9b3cfbfa8..8b1f3093332 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_charset.result @@ -40,7 +40,7 @@ show create database mysqltest3; Database Create Database mysqltest3 CREATE DATABASE `mysqltest3` /*!40100 DEFAULT CHARACTER SET armscii8 COLLATE armscii8_bin */ use mysqltest2; -create table t1 (a int auto_increment primary key, b varchar(100)); +create table t1 (a int auto_increment primary key, b varchar(100))engine=NDB;; set character_set_client=cp850, collation_connection=latin2_croatian_ci; insert into t1 (b) values(@@character_set_server); insert into t1 (b) values(@@collation_server); @@ -117,29 +117,27 @@ master-bin.000001 # Query # # create database mysqltest2 character set latin2 master-bin.000001 # Query # # create database mysqltest3 master-bin.000001 # Query # # drop database mysqltest3 master-bin.000001 # Query # # create database mysqltest3 -master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100)) -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))engine=NDB +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) +master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) +master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `mysqltest2`; truncate table t1 +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (mysqltest2.t1) +master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) +master-bin.000001 # Write_rows # # table_id: # master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # drop database mysqltest2 master-bin.000001 # Query # # drop database mysqltest3 select "--- --global--" as ""; @@ -177,14 +175,16 @@ select "--- --3943--" as ""; --- --3943-- use test; -CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255)); +CREATE TABLE t1 (c1 VARBINARY(255), c2 VARBINARY(255))ENGINE=NDB;; SET CHARACTER_SET_CLIENT=koi8r, CHARACTER_SET_CONNECTION=cp1251, CHARACTER_SET_RESULTS=koi8r; INSERT INTO t1 (c1, c2) VALUES ('îÕ, ÚÁ ÒÙÂÁÌËÕ','îÕ, ÚÁ ÒÙÂÁÌËÕ'); +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 +SET SQL_BIG_SELECTS=1; select hex(c1), hex(c2) from t1; hex(c1) hex(c2) CDF32C20E7E020F0FBE1E0EBEAF3 CDF32C20E7E020F0FBE1E0EBEAF3 diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result new file mode 100644 index 00000000000..d5d4658c01f --- /dev/null +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraColMaster.result @@ -0,0 +1,2286 @@ +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; +set binlog_format=row; + +*********************************************************** +*********************************************************** +***************** Start of Testing ************************ +*********************************************************** +*********************************************************** +* This test format == binlog_format ROW and engine == 'NDB' +*********************************************************** +*********************************************************** + +***** Testing more columns on the Master ***** + +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 FLOAT DEFAULT '2.00', +f6 CHAR(4) DEFAULT 'TEST', +f7 INT DEFAULT '0', +f8 TEXT, +f9 LONGBLOB, +f10 BIT(63), +f11 VARBINARY(64))ENGINE='NDB'; + +* Alter Table on Slave and drop columns f5 through f11 * + +alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; + +* Insert data in Master then update and delete some rows* + +* Select count and 20 rows from Master * + +SELECT COUNT(*) FROM t1; +COUNT(*) +40 + +SELECT f1,f2,f3,f4,f5,f6,f7,f8,f9, +hex(f10),hex(f11) FROM t1 ORDER BY f3 LIMIT 20; +f1 f2 f3 f4 f5 f6 f7 f8 f9 hex(f10) hex(f11) +2 2 2 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +3 3 3 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +5 5 5 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +6 6 6 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +8 8 8 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +9 9 9 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +11 11 11 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +12 12 12 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +14 14 14 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +15 15 15 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +17 17 17 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +18 18 18 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +20 20 20 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +21 21 21 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +23 23 23 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +24 24 24 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +26 26 26 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +27 27 27 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +29 29 29 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +30 30 30 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 + +* Select count and 20 rows from Slave * + +SELECT COUNT(*) FROM t1; +COUNT(*) +40 + +SELECT * FROM t1 ORDER BY f3 LIMIT 20; +f1 f2 f3 f4 +2 2 2 second +3 3 3 next +5 5 5 second +6 6 6 next +8 8 8 second +9 9 9 next +11 11 11 second +12 12 12 next +14 14 14 second +15 15 15 next +17 17 17 second +18 18 18 next +20 20 20 second +21 21 21 next +23 23 23 second +24 24 24 next +26 26 26 second +27 27 27 next +29 29 29 second +30 30 30 next + +* Show Slave Status * + +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error + + +***** Testing Altering table def scenario ***** + +CREATE TABLE t2 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 ENUM('a', 'b', 'c') default 'a', +f7 DECIMAL(17,9) default '1000.00', +f8 MEDIUMBLOB, +f9 NUMERIC(6,4) default '2000.00', +f10 VARCHAR(1024), +f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f12 SET('a', 'b', 'c') default 'b') +ENGINE='NDB'; +Warnings: +Warning 1264 Out of range value for column 'f9' at row 1 + +CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 ENUM('a', 'b', 'c') default 'a', +f8 MEDIUMBLOB, +f10 VARCHAR(1024), +f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f12 SET('a', 'b', 'c') default 'b') +ENGINE='NDB'; + +CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 DECIMAL(17,9) default '1000.00', +f7 MEDIUMBLOB, +f8 NUMERIC(6,4) default '2000.00', +f9 VARCHAR(1024), +f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f11 CHAR(255)) +ENGINE='NDB'; +Warnings: +Warning 1264 Out of range value for column 'f8' at row 1 + +CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 BIGINT, +f6 BLOB, +f7 DATE, +f8 DATETIME, +f9 FLOAT, +f10 INT, +f11 LONGBLOB, +f12 LONGTEXT, +f13 MEDIUMBLOB, +f14 MEDIUMINT, +f15 MEDIUMTEXT, +f16 REAL, +f17 SMALLINT, +f18 TEXT, +f19 TIME, +f20 TIMESTAMP, +f21 TINYBLOB, +f22 TINYINT, +f23 TINYTEXT, +f24 YEAR, +f25 BINARY(255), +f26 BIT(64), +f27 CHAR(255), +f28 DECIMAL(30,7), +f29 DOUBLE, +f30 ENUM ('a','b', 'c') default 'a', +f31 FLOAT, +f32 NUMERIC(17,9), +f33 SET ('a', 'b', 'c') default 'b', +f34 VARBINARY(1025), +f35 VARCHAR(257) +) ENGINE='NDB'; + +** Alter tables on slave and drop columns ** + +alter table t2 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11, drop +f12; +alter table t3 drop f5, drop f6, drop f8, drop f10, drop f11, drop f12; +alter table t4 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; +alter table t31 +drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11, +drop f12, drop f13, drop f14, drop f15, drop f16, drop f17, drop f18, +drop f19, drop f20, drop f21, drop f22, drop f23, drop f24, drop f25, +drop f26, drop f27, drop f28, drop f29, drop f30, drop f31, drop f32, +drop f33, drop f34, drop f35; + +** Insert Data into Master ** +INSERT into t2 set f1=1, f2=1, f3=1, f4='first', f8='f8: medium size blob', f10='f10: +some var char'; +INSERT into t2 values (2, 2, 2, 'second', +2.0, 'b', 2000.0002, 'f8: medium size blob', 2000, 'f10: some var char', +'01234567', 'c'), +(3, 3, 3, 'third', +3.0, 'b', 3000.0003, 'f8: medium size blob', 3000, 'f10: some var char', +'01234567', 'c'); +Warnings: +Warning 1264 Out of range value for column 'f9' at row 1 +Warning 1264 Out of range value for column 'f9' at row 2 +INSERT into t3 set f1=1, f2=1, f3=1, f4='first', f10='f10: some var char'; +INSERT into t4 set f1=1, f2=1, f3=1, f4='first', f7='f7: medium size blob', f10='f10: +binary data'; +INSERT into t31 set f1=1, f2=1, f3=1, f4='first'; +INSERT into t31 set f1=1, f2=1, f3=2, f4='second', +f9=2.2, f10='seven samurai', f28=222.222, f35='222'; +Warnings: +Warning 1366 Incorrect integer value: 'seven samurai' for column 'f10' at row 1 +INSERT into t31 values (1, 1, 3, 'third', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ); +Warnings: +Warning 1264 Out of range value for column 'f5' at row 1 +Warning 1264 Out of range value for column 'f24' at row 1 +INSERT into t31 values (1, 1, 4, 'fourth', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ), +(1, 1, 5, 'fifth', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ), +(1, 1, 6, 'sixth', +/* f5 BIGINT, */ NULL, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ NULL +); +Warnings: +Warning 1264 Out of range value for column 'f5' at row 1 +Warning 1264 Out of range value for column 'f24' at row 1 +Warning 1264 Out of range value for column 'f5' at row 2 +Warning 1264 Out of range value for column 'f24' at row 2 +Warning 1264 Out of range value for column 'f24' at row 3 + +** Sync slave with master ** +** Do selects from tables ** + +select * from t1 order by f3; +f1 f2 f3 f4 +2 2 2 second +3 3 3 next +5 5 5 second +6 6 6 next +8 8 8 second +9 9 9 next +11 11 11 second +12 12 12 next +14 14 14 second +15 15 15 next +17 17 17 second +18 18 18 next +20 20 20 second +21 21 21 next +23 23 23 second +24 24 24 next +26 26 26 second +27 27 27 next +29 29 29 second +30 30 30 next +31 31 31 second +32 32 32 second +33 33 33 second +34 34 34 second +35 35 35 second +36 36 36 second +37 37 37 second +38 38 38 second +39 39 39 second +40 40 40 second +41 41 41 second +42 42 42 second +43 43 43 second +44 44 44 second +45 45 45 second +46 46 46 second +47 47 47 second +48 48 48 second +49 49 49 second +50 50 50 second +select * from t2 order by f1; +f1 f2 f3 f4 +1 1 1 first +2 2 2 second +3 3 3 third +select * from t3 order by f1; +f1 f2 f3 f4 +1 1 1 first +select * from t4 order by f1; +f1 f2 f3 f4 +1 1 1 first +select * from t31 order by f1; +f1 f2 f3 f4 +1 1 5 fifth +1 1 3 third +1 1 1 first +1 1 6 sixth +1 1 2 second +1 1 4 fourth + +** Do updates master ** + +update t31 set f5=555555555555555 where f3=6; +update t31 set f2=2 where f3=2; +update t31 set f1=NULL where f3=1; +update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; +Warnings: +Warning 1048 Column 'f3' cannot be null + +** Delete from Master ** + +delete from t1; +delete from t2; +delete from t3; +delete from t4; +delete from t31; + +** Check slave status ** + +select * from t31; +f1 f2 f3 f4 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error + +**************************************** +* columns in master at middle of table * +* Expect: Proper error message * +**************************************** + +** Stop and Reset Slave ** + +STOP SLAVE; +RESET SLAVE; + +** create table slave side ** +CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5) +) ENGINE='NDB'; + +** Connect to master and create table ** + +CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233', +c CHAR(5), e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT), +(2,@b1,DEFAULT,'JOE',DEFAULT), +(3,@b1,DEFAULT,'QA',DEFAULT); + +******************************************** +*** Expect slave to fail with Error 1523 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1534 +Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1534 +Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +*** Drop t10 *** +DROP TABLE t10; + +********************************************* +* More columns in master at middle of table * +* Expect: Proper error message * +********************************************* + +*** Create t11 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) +) ENGINE='NDB'; + +*** Create t11 on Master *** +CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT), +(2,@b1,'Testing is cool','JOE',DEFAULT), +(3,@b1,DEFAULT,'QA',DEFAULT); + +******************************************** +*** Expect slave to fail with Error 1523 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1534 +Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1534 +Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +*** Drop t11 *** +DROP TABLE t11; + +********************************************* +* More columns in master at middle of table * +* Expect: This one should pass blob-text * +********************************************* + +*** Create t12 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB +) ENGINE='NDB'; + +*** Create t12 on Master *** +CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT, +c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t12 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',DEFAULT,DEFAULT), +(3,@b1,'QA',DEFAULT,DEFAULT); + +SELECT a,hex(b),f,c,e FROM t12 ORDER BY a; +a hex(b) f c e +1 62316231623162316231623162316231 Kyle test 1 +2 62316231623162316231623162316231 JOE test 1 +3 62316231623162316231623162316231 QA test 1 + +*** Select on Slave *** +SELECT a,hex(b),c FROM t12 ORDER BY a; +a hex(b) c +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +*** Drop t12 *** +DROP TABLE t12; + +**************************************************** +* - Alter Master adding columns at middle of table * +* Expect: columns added * +**************************************************** + + +*** Create t14 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t14 on Master *** +CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1; +ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2; + +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle',DEFAULT,DEFAULT), +(2,2.00,'This Test Should work',@b1,'JOE',DEFAULT,DEFAULT), +(3,3.00,'If is does not, I will open a bug',@b1,'QA',DEFAULT,DEFAULT); + +SELECT c1,c2,c3,hex(c4),c5,c6,c7 FROM t14 ORDER BY c1; +c1 c2 c3 hex(c4) c5 c6 c7 +1 1.00 Replication Testing Extra Col 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 2.00 This Test Should work 62316231623162316231623162316231 JOE 1 CURRENT_TIMESTAMP +3 3.00 If is does not, I will open a bug 62316231623162316231623162316231 QA 1 CURRENT_TIMESTAMP + +*** Select on Slave **** +SELECT c1,c2,c3,hex(c4),c5 FROM t14 ORDER BY c1; +c1 c2 c3 hex(c4) c5 +1 1.00 Replication Testing Extra Col 62316231623162316231623162316231 Kyle +2 2.00 This Test Should work 62316231623162316231623162316231 JOE +3 3.00 If is does not, I will open a bug 62316231623162316231623162316231 QA + +**************************************************** +* - Alter Master Dropping columns from the middle. * +* Expect: columns dropped * +**************************************************** + +*** connect to master and drop columns *** +ALTER TABLE t14 DROP COLUMN c2; +ALTER TABLE t14 DROP COLUMN c7; + +*** Select from Master *** +SELECT c1,c3,hex(c4),c5,c6 FROM t14 ORDER BY c1; +c1 c3 hex(c4) c5 c6 +1 Replication Testing Extra Col 62316231623162316231623162316231 Kyle 1 +2 This Test Should work 62316231623162316231623162316231 JOE 1 +3 If is does not, I will open a bug 62316231623162316231623162316231 QA 1 + +************ +* Bug30415 * +************ +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1091 +Last_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1091 +Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +STOP SLAVE; +RESET SLAVE; + +*** Drop t14 *** +DROP TABLE t14; +DROP TABLE t14; +RESET MASTER; +START SLAVE; + +************************************************* +* - Alter Master adding columns at end of table * +* Expect: Error 1054 * +************************************************* + +*** Create t15 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t15 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t15 on Master *** +CREATE TABLE t15 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t15 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT,3.00), +(2,@b1,'JOE',DEFAULT,DEFAULT,3.00), +(3,@b1,'QA',DEFAULT,DEFAULT,3.00); +SELECT c1,hex(c4),c5,c6,c7,c2 FROM t15 ORDER BY c1; +c1 hex(c4) c5 c6 c7 c2 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP 3.00 +2 62316231623162316231623162316231 JOE 1 CURRENT_TIMESTAMP 3.00 +3 62316231623162316231623162316231 QA 1 CURRENT_TIMESTAMP 3.00 + +******************************************** +*** Expect slave to fail with Error 1054 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1054 +Last_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1054 +Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +STOP SLAVE; +RESET SLAVE; + +*** Drop t15 *** +DROP TABLE t15; +DROP TABLE t15; +RESET MASTER; +START SLAVE; + +************************************************ +* - Create index on Master column not on slave * +* Expect:Warning * +************************************************ + +*** Create t16 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t16 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t16 on Master *** +CREATE TABLE t16 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Create Index and Data Insert *** +CREATE INDEX part_of_c6 ON t16 (c6); +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t16 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t16 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +***************** +*** BUG 30434 *** +***************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1072 +Last_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1072 +Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +STOP SLAVE; +RESET SLAVE; + +*** Drop t16 *** +DROP TABLE t16; +DROP TABLE t16; +RESET MASTER; +START SLAVE; + +***************************************************** +* - Delete rows using column on Master not on slave * +* Expect: Rows Deleted * +***************************************************** + +*** Create t17 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t17 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t17 on Master *** +CREATE TABLE t17 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t17 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +** Delete from master ** +DELETE FROM t17 WHERE c6 = 3; +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP + +** Check slave ** +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +DROP TABLE t17; + + +***************************************************** +* - Update row using column on Master not on slave * +* Expect: Rows updated * +***************************************************** + +** Bug30674 ** + +*** Create t18 on slave *** + +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t18 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t18 on Master *** +CREATE TABLE t18 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t18 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +** update from master ** +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Check slave ** +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA +DROP TABLE t18; + + +***************************************************** +* - Insert UUID column on Master not on slave * +* Expect: Rows inserted * +***************************************************** + +*** Create t5 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t5 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t5 on Master *** +CREATE TABLE t5 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 LONG, +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +INSERT INTO t5 () VALUES(1,@b1,'Kyle',UUID(),DEFAULT), +(2,@b1,'JOE',UUID(),DEFAULT), +(3,@b1,'QA',UUID(),DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t5 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 6231623162316231 Kyle UUID TIME +2 6231623162316231 JOE UUID TIME +3 6231623162316231 QA UUID TIME + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t5 ORDER BY c1; +c1 hex(c4) c5 +1 6231623162316231 Kyle +2 6231623162316231 JOE +3 6231623162316231 QA +DROP TABLE t5; + +set binlog_format=mixed; + +*********************************************************** +*********************************************************** +***************** Start of Testing ************************ +*********************************************************** +*********************************************************** +* This test format == binlog_format MIXED and engine == 'NDB' +*********************************************************** +*********************************************************** + +***** Testing more columns on the Master ***** + +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 FLOAT DEFAULT '2.00', +f6 CHAR(4) DEFAULT 'TEST', +f7 INT DEFAULT '0', +f8 TEXT, +f9 LONGBLOB, +f10 BIT(63), +f11 VARBINARY(64))ENGINE='NDB'; + +* Alter Table on Slave and drop columns f5 through f11 * + +alter table t1 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; + +* Insert data in Master then update and delete some rows* + +* Select count and 20 rows from Master * + +SELECT COUNT(*) FROM t1; +COUNT(*) +40 + +SELECT f1,f2,f3,f4,f5,f6,f7,f8,f9, +hex(f10),hex(f11) FROM t1 ORDER BY f3 LIMIT 20; +f1 f2 f3 f4 f5 f6 f7 f8 f9 hex(f10) hex(f11) +2 2 2 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +3 3 3 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +5 5 5 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +6 6 6 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +8 8 8 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +9 9 9 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +11 11 11 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +12 12 12 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +14 14 14 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +15 15 15 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +17 17 17 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +18 18 18 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +20 20 20 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +21 21 21 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +23 23 23 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +24 24 24 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +26 26 26 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +27 27 27 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +29 29 29 second 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 +30 30 30 next 2 kaks 2 got stolen from the paradise very fat blob 1555 123456 + +* Select count and 20 rows from Slave * + +SELECT COUNT(*) FROM t1; +COUNT(*) +40 + +SELECT * FROM t1 ORDER BY f3 LIMIT 20; +f1 f2 f3 f4 +2 2 2 second +3 3 3 next +5 5 5 second +6 6 6 next +8 8 8 second +9 9 9 next +11 11 11 second +12 12 12 next +14 14 14 second +15 15 15 next +17 17 17 second +18 18 18 next +20 20 20 second +21 21 21 next +23 23 23 second +24 24 24 next +26 26 26 second +27 27 27 next +29 29 29 second +30 30 30 next + +* Show Slave Status * + +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error + + +***** Testing Altering table def scenario ***** + +CREATE TABLE t2 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 ENUM('a', 'b', 'c') default 'a', +f7 DECIMAL(17,9) default '1000.00', +f8 MEDIUMBLOB, +f9 NUMERIC(6,4) default '2000.00', +f10 VARCHAR(1024), +f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f12 SET('a', 'b', 'c') default 'b') +ENGINE='NDB'; +Warnings: +Warning 1264 Out of range value for column 'f9' at row 1 + +CREATE TABLE t3 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 ENUM('a', 'b', 'c') default 'a', +f8 MEDIUMBLOB, +f10 VARCHAR(1024), +f11 BINARY(20) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f12 SET('a', 'b', 'c') default 'b') +ENGINE='NDB'; + +CREATE TABLE t4 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 DOUBLE DEFAULT '2.00', +f6 DECIMAL(17,9) default '1000.00', +f7 MEDIUMBLOB, +f8 NUMERIC(6,4) default '2000.00', +f9 VARCHAR(1024), +f10 BINARY(20) not null default '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0', +f11 CHAR(255)) +ENGINE='NDB'; +Warnings: +Warning 1264 Out of range value for column 'f8' at row 1 + +CREATE TABLE t31 (f1 INT, f2 INT, f3 INT PRIMARY KEY, f4 CHAR(20), +/* extra */ +f5 BIGINT, +f6 BLOB, +f7 DATE, +f8 DATETIME, +f9 FLOAT, +f10 INT, +f11 LONGBLOB, +f12 LONGTEXT, +f13 MEDIUMBLOB, +f14 MEDIUMINT, +f15 MEDIUMTEXT, +f16 REAL, +f17 SMALLINT, +f18 TEXT, +f19 TIME, +f20 TIMESTAMP, +f21 TINYBLOB, +f22 TINYINT, +f23 TINYTEXT, +f24 YEAR, +f25 BINARY(255), +f26 BIT(64), +f27 CHAR(255), +f28 DECIMAL(30,7), +f29 DOUBLE, +f30 ENUM ('a','b', 'c') default 'a', +f31 FLOAT, +f32 NUMERIC(17,9), +f33 SET ('a', 'b', 'c') default 'b', +f34 VARBINARY(1025), +f35 VARCHAR(257) +) ENGINE='NDB'; + +** Alter tables on slave and drop columns ** + +alter table t2 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11, drop +f12; +alter table t3 drop f5, drop f6, drop f8, drop f10, drop f11, drop f12; +alter table t4 drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11; +alter table t31 +drop f5, drop f6, drop f7, drop f8, drop f9, drop f10, drop f11, +drop f12, drop f13, drop f14, drop f15, drop f16, drop f17, drop f18, +drop f19, drop f20, drop f21, drop f22, drop f23, drop f24, drop f25, +drop f26, drop f27, drop f28, drop f29, drop f30, drop f31, drop f32, +drop f33, drop f34, drop f35; + +** Insert Data into Master ** +INSERT into t2 set f1=1, f2=1, f3=1, f4='first', f8='f8: medium size blob', f10='f10: +some var char'; +INSERT into t2 values (2, 2, 2, 'second', +2.0, 'b', 2000.0002, 'f8: medium size blob', 2000, 'f10: some var char', +'01234567', 'c'), +(3, 3, 3, 'third', +3.0, 'b', 3000.0003, 'f8: medium size blob', 3000, 'f10: some var char', +'01234567', 'c'); +Warnings: +Warning 1264 Out of range value for column 'f9' at row 1 +Warning 1264 Out of range value for column 'f9' at row 2 +INSERT into t3 set f1=1, f2=1, f3=1, f4='first', f10='f10: some var char'; +INSERT into t4 set f1=1, f2=1, f3=1, f4='first', f7='f7: medium size blob', f10='f10: +binary data'; +INSERT into t31 set f1=1, f2=1, f3=1, f4='first'; +INSERT into t31 set f1=1, f2=1, f3=2, f4='second', +f9=2.2, f10='seven samurai', f28=222.222, f35='222'; +Warnings: +Warning 1366 Incorrect integer value: 'seven samurai' for column 'f10' at row 1 +INSERT into t31 values (1, 1, 3, 'third', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ); +Warnings: +Warning 1264 Out of range value for column 'f5' at row 1 +Warning 1264 Out of range value for column 'f24' at row 1 +INSERT into t31 values (1, 1, 4, 'fourth', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ), +(1, 1, 5, 'fifth', +/* f5 BIGINT, */ 333333333333333333333333, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ 'three times three' + ), +(1, 1, 6, 'sixth', +/* f5 BIGINT, */ NULL, +/* f6 BLOB, */ '3333333333333333333333', +/* f7 DATE, */ '2007-07-18', +/* f8 DATETIME, */ "2007-07-18", +/* f9 FLOAT, */ 3.33333333, +/* f10 INT, */ 333333333, +/* f11 LONGBLOB, */ '3333333333333333333', +/* f12 LONGTEXT, */ '3333333333333333333', +/* f13 MEDIUMBLOB, */ '3333333333333333333', +/* f14 MEDIUMINT, */ 33, +/* f15 MEDIUMTEXT, */ 3.3, +/* f16 REAL, */ 3.3, +/* f17 SMALLINT, */ 3, +/* f18 TEXT, */ '33', +/* f19 TIME, */ '2:59:58.999', +/* f20 TIMESTAMP, */ 20000303000000, +/* f21 TINYBLOB, */ '3333', +/* f22 TINYINT, */ 3, +/* f23 TINYTEXT, */ '3', +/* f24 YEAR, */ 3000, +/* f25 BINARY(255), */ 'three_33333', +/* f26 BIT(64), */ b'011', +/* f27 CHAR(255), */ 'three', +/* f28 DECIMAL(30,7), */ 3.333, +/* f29 DOUBLE, */ 3.333333333333333333333333333, +/* f30 ENUM ('a','b','c')*/ 'c', +/* f31 FLOAT, */ 3.0, +/* f32 NUMERIC(17,9), */ 3.3333, +/* f33 SET ('a','b','c'),*/ 'c', +/*f34 VARBINARY(1025),*/ '3333 minus 3', +/*f35 VARCHAR(257),*/ NULL +); +Warnings: +Warning 1264 Out of range value for column 'f5' at row 1 +Warning 1264 Out of range value for column 'f24' at row 1 +Warning 1264 Out of range value for column 'f5' at row 2 +Warning 1264 Out of range value for column 'f24' at row 2 +Warning 1264 Out of range value for column 'f24' at row 3 + +** Sync slave with master ** +** Do selects from tables ** + +select * from t1 order by f3; +f1 f2 f3 f4 +2 2 2 second +3 3 3 next +5 5 5 second +6 6 6 next +8 8 8 second +9 9 9 next +11 11 11 second +12 12 12 next +14 14 14 second +15 15 15 next +17 17 17 second +18 18 18 next +20 20 20 second +21 21 21 next +23 23 23 second +24 24 24 next +26 26 26 second +27 27 27 next +29 29 29 second +30 30 30 next +31 31 31 second +32 32 32 second +33 33 33 second +34 34 34 second +35 35 35 second +36 36 36 second +37 37 37 second +38 38 38 second +39 39 39 second +40 40 40 second +41 41 41 second +42 42 42 second +43 43 43 second +44 44 44 second +45 45 45 second +46 46 46 second +47 47 47 second +48 48 48 second +49 49 49 second +50 50 50 second +select * from t2 order by f1; +f1 f2 f3 f4 +1 1 1 first +2 2 2 second +3 3 3 third +select * from t3 order by f1; +f1 f2 f3 f4 +1 1 1 first +select * from t4 order by f1; +f1 f2 f3 f4 +1 1 1 first +select * from t31 order by f1; +f1 f2 f3 f4 +1 1 5 fifth +1 1 3 third +1 1 1 first +1 1 6 sixth +1 1 2 second +1 1 4 fourth + +** Do updates master ** + +update t31 set f5=555555555555555 where f3=6; +update t31 set f2=2 where f3=2; +update t31 set f1=NULL where f3=1; +update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; +Warnings: +Warning 1048 Column 'f3' cannot be null + +** Delete from Master ** + +delete from t1; +delete from t2; +delete from t3; +delete from t4; +delete from t31; + +** Check slave status ** + +select * from t31; +f1 f2 f3 f4 +show slave status;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 0 +Last_SQL_Error + +**************************************** +* columns in master at middle of table * +* Expect: Proper error message * +**************************************** + +** Stop and Reset Slave ** + +STOP SLAVE; +RESET SLAVE; + +** create table slave side ** +CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5) +) ENGINE='NDB'; + +** Connect to master and create table ** + +CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233', +c CHAR(5), e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t10 () VALUES(1,@b1,DEFAULT,'Kyle',DEFAULT), +(2,@b1,DEFAULT,'JOE',DEFAULT), +(3,@b1,DEFAULT,'QA',DEFAULT); + +******************************************** +*** Expect slave to fail with Error 1523 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1534 +Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1534 +Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 5, test.t10 has type 254 +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +*** Drop t10 *** +DROP TABLE t10; + +********************************************* +* More columns in master at middle of table * +* Expect: Proper error message * +********************************************* + +*** Create t11 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254) +) ENGINE='NDB'; + +*** Create t11 on Master *** +CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT, +c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t11 () VALUES(1,@b1,'Testing is fun','Kyle',DEFAULT), +(2,@b1,'Testing is cool','JOE',DEFAULT), +(3,@b1,DEFAULT,'QA',DEFAULT); + +******************************************** +*** Expect slave to fail with Error 1523 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1534 +Last_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1534 +Last_SQL_Error Table definition on master and slave does not match: Column 2 type mismatch - received type 252, test.t11 has type 15 +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; + +*** Drop t11 *** +DROP TABLE t11; + +********************************************* +* More columns in master at middle of table * +* Expect: This one should pass blob-text * +********************************************* + +*** Create t12 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB +) ENGINE='NDB'; + +*** Create t12 on Master *** +CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT, +c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t12 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',DEFAULT,DEFAULT), +(3,@b1,'QA',DEFAULT,DEFAULT); + +SELECT a,hex(b),f,c,e FROM t12 ORDER BY a; +a hex(b) f c e +1 62316231623162316231623162316231 Kyle test 1 +2 62316231623162316231623162316231 JOE test 1 +3 62316231623162316231623162316231 QA test 1 + +*** Select on Slave *** +SELECT a,hex(b),c FROM t12 ORDER BY a; +a hex(b) c +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +*** Drop t12 *** +DROP TABLE t12; + +**************************************************** +* - Alter Master adding columns at middle of table * +* Expect: columns added * +**************************************************** + + +*** Create t14 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t14 on Master *** +CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1; +ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2; + +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle',DEFAULT,DEFAULT), +(2,2.00,'This Test Should work',@b1,'JOE',DEFAULT,DEFAULT), +(3,3.00,'If is does not, I will open a bug',@b1,'QA',DEFAULT,DEFAULT); + +SELECT c1,c2,c3,hex(c4),c5,c6,c7 FROM t14 ORDER BY c1; +c1 c2 c3 hex(c4) c5 c6 c7 +1 1.00 Replication Testing Extra Col 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 2.00 This Test Should work 62316231623162316231623162316231 JOE 1 CURRENT_TIMESTAMP +3 3.00 If is does not, I will open a bug 62316231623162316231623162316231 QA 1 CURRENT_TIMESTAMP + +*** Select on Slave **** +SELECT c1,c2,c3,hex(c4),c5 FROM t14 ORDER BY c1; +c1 c2 c3 hex(c4) c5 +1 1.00 Replication Testing Extra Col 62316231623162316231623162316231 Kyle +2 2.00 This Test Should work 62316231623162316231623162316231 JOE +3 3.00 If is does not, I will open a bug 62316231623162316231623162316231 QA + +**************************************************** +* - Alter Master Dropping columns from the middle. * +* Expect: columns dropped * +**************************************************** + +*** connect to master and drop columns *** +ALTER TABLE t14 DROP COLUMN c2; +ALTER TABLE t14 DROP COLUMN c7; + +*** Select from Master *** +SELECT c1,c3,hex(c4),c5,c6 FROM t14 ORDER BY c1; +c1 c3 hex(c4) c5 c6 +1 Replication Testing Extra Col 62316231623162316231623162316231 Kyle 1 +2 This Test Should work 62316231623162316231623162316231 JOE 1 +3 If is does not, I will open a bug 62316231623162316231623162316231 QA 1 + +************ +* Bug30415 * +************ +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1091 +Last_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1091 +Last_SQL_Error Error 'Can't DROP 'c7'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t14 DROP COLUMN c7' +STOP SLAVE; +RESET SLAVE; + +*** Drop t14 *** +DROP TABLE t14; +DROP TABLE t14; +RESET MASTER; +START SLAVE; + +************************************************* +* - Alter Master adding columns at end of table * +* Expect: Error 1054 * +************************************************* + +*** Create t15 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t15 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t15 on Master *** +CREATE TABLE t15 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7; +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t15 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT,3.00), +(2,@b1,'JOE',DEFAULT,DEFAULT,3.00), +(3,@b1,'QA',DEFAULT,DEFAULT,3.00); +SELECT c1,hex(c4),c5,c6,c7,c2 FROM t15 ORDER BY c1; +c1 hex(c4) c5 c6 c7 c2 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP 3.00 +2 62316231623162316231623162316231 JOE 1 CURRENT_TIMESTAMP 3.00 +3 62316231623162316231623162316231 QA 1 CURRENT_TIMESTAMP 3.00 + +******************************************** +*** Expect slave to fail with Error 1054 *** +******************************************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1054 +Last_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1054 +Last_SQL_Error Error 'Unknown column 'c7' in 't15'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c2 DECIMAL(8,2) AFTER c7' +STOP SLAVE; +RESET SLAVE; + +*** Drop t15 *** +DROP TABLE t15; +DROP TABLE t15; +RESET MASTER; +START SLAVE; + +************************************************ +* - Create index on Master column not on slave * +* Expect:Warning * +************************************************ + +*** Create t16 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t16 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t16 on Master *** +CREATE TABLE t16 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Create Index and Data Insert *** +CREATE INDEX part_of_c6 ON t16 (c6); +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t16 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t16 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +***************** +*** BUG 30434 *** +***************** + +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port # +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1072 +Last_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1072 +Last_SQL_Error Error 'Key column 'c6' doesn't exist in table' on query. Default database: 'test'. Query: 'CREATE INDEX part_of_c6 ON t16 (c6)' +STOP SLAVE; +RESET SLAVE; + +*** Drop t16 *** +DROP TABLE t16; +DROP TABLE t16; +RESET MASTER; +START SLAVE; + +***************************************************** +* - Delete rows using column on Master not on slave * +* Expect: Rows Deleted * +***************************************************** + +*** Create t17 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t17 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t17 on Master *** +CREATE TABLE t17 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t17 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +** Delete from master ** +DELETE FROM t17 WHERE c6 = 3; +SELECT c1,hex(c4),c5,c6,c7 FROM t17 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP + +** Check slave ** +SELECT c1,hex(c4),c5 FROM t17 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +DROP TABLE t17; + + +***************************************************** +* - Update row using column on Master not on slave * +* Expect: Rows updated * +***************************************************** + +** Bug30674 ** + +*** Create t18 on slave *** + +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t18 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t18 on Master *** +CREATE TABLE t18 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 INT DEFAULT '1', +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +set @b1 = concat(@b1,@b1); +INSERT INTO t18 () VALUES(1,@b1,'Kyle',DEFAULT,DEFAULT), +(2,@b1,'JOE',2,DEFAULT), +(3,@b1,'QA',3,DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA + +** update from master ** +SELECT c1,hex(c4),c5,c6,c7 FROM t18 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 62316231623162316231623162316231 Kyle 1 CURRENT_TIMESTAMP +2 62316231623162316231623162316231 JOE 2 CURRENT_TIMESTAMP +3 62316231623162316231623162316231 QA 3 CURRENT_TIMESTAMP + +** Check slave ** +SELECT c1,hex(c4),c5 FROM t18 ORDER BY c1; +c1 hex(c4) c5 +1 62316231623162316231623162316231 Kyle +2 62316231623162316231623162316231 JOE +3 62316231623162316231623162316231 QA +DROP TABLE t18; + + +***************************************************** +* - Insert UUID column on Master not on slave * +* Expect: Rows inserted * +***************************************************** + +*** Create t5 on slave *** +STOP SLAVE; +RESET SLAVE; +CREATE TABLE t5 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5) +) ENGINE='NDB'; + +*** Create t5 on Master *** +CREATE TABLE t5 (c1 INT KEY, c4 BLOB, c5 CHAR(5), +c6 LONG, +c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP +)ENGINE='NDB'; +RESET MASTER; + +*** Start Slave *** +START SLAVE; + +*** Master Data Insert *** +set @b1 = 'b1b1b1b1'; +INSERT INTO t5 () VALUES(1,@b1,'Kyle',UUID(),DEFAULT), +(2,@b1,'JOE',UUID(),DEFAULT), +(3,@b1,'QA',UUID(),DEFAULT); +SELECT c1,hex(c4),c5,c6,c7 FROM t5 ORDER BY c1; +c1 hex(c4) c5 c6 c7 +1 6231623162316231 Kyle UUID TIME +2 6231623162316231 JOE UUID TIME +3 6231623162316231 QA UUID TIME + +** Select * from Slave ** +SELECT c1,hex(c4),c5 FROM t5 ORDER BY c1; +c1 hex(c4) c5 +1 6231623162316231 Kyle +2 6231623162316231 JOE +3 6231623162316231 QA +DROP TABLE t5; + diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index f372d44cb90..05e8297bf0e 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -11,8 +11,8 @@ ############################################################################## -rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated -rpl_ndb_2myisam : BUG#19227 Seems to pass currently +rpl_ndb_2innodb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue +rpl_ndb_2myisam : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue rpl_ndb_2other : BUG#21842 2007-08-30 tsmith test has never worked on bigendian (sol10-sparc-a, powermacg5 rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_innodb2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue @@ -20,7 +20,7 @@ rpl_ndb_myisam2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb faile rpl_ndb_ddl : BUG#28798 2007-05-31 lars Valgrind failure in NDB rpl_ndb_mix_innodb : BUG#28123 rpl_ndb_mix_innodb.test casue slave to core on sol10-sparc-a rpl_ndb_ctype_ucs2_def : BUG#27404 util thd mysql_parse sig11 when mysqld default multibyte charset - +rpl_ndb_extraColMaster : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test index 4bac267443e..f14229a52f9 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_charset.test @@ -1,8 +1,8 @@ ######################################################## # By JBM 2005-02-15 Wrapped to allow reuse of test code# ######################################################## ---source include/have_ndb.inc --- source include/have_binlog_format_row.inc +-- source include/have_ndb.inc +-- source include/have_binlog_format_mixed_or_row.inc -- source include/ndb_master-slave.inc let $engine_type=NDB; -- source extra/rpl_tests/rpl_row_charset.test diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_extraColMaster.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_extraColMaster.test new file mode 100644 index 00000000000..d78eda7eef1 --- /dev/null +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_extraColMaster.test @@ -0,0 +1,14 @@ +############################################################# +# Purpose: To test having extra columns on the master WL#3915 +############################################################# +-- source include/have_ndb.inc +-- source include/ndb_master-slave.inc +-- source include/have_binlog_format_mixed_or_row.inc + +let $engine_type = 'NDB'; + +set binlog_format=row; +-- source extra/rpl_tests/rpl_extraMaster_Col.test + +set binlog_format=mixed; +-- source extra/rpl_tests/rpl_extraMaster_Col.test diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index d1ca5f1b609..a4c7eaebc30 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -454,7 +454,8 @@ create event закачка on schedule every 10 hour do select get_lock("test_l --echo "Should have only 2 processes: the scheduler and the locked event" let $wait_condition= select count(*) = 2 from information_schema.processlist where ( (state like 'User lock%' AND info like 'select get_lock%') - OR (command='Daemon' AND user='event_scheduler')); + OR (command='Daemon' AND user='event_scheduler' AND + state = 'Waiting for next activation')); --source include/wait_condition.inc select /*2*/ user, host, db, command, state, info diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test index 36052fdb9af..ebd86f3a3d2 100644 --- a/mysql-test/t/events_bugs.test +++ b/mysql-test/t/events_bugs.test @@ -712,18 +712,6 @@ DROP TABLE event_log; #DROP DATABASE ev_db_1; SET GLOBAL event_scheduler = OFF; -# -# End of tests -# - -let $wait_condition= - select count(*) = 0 from information_schema.processlist - where db='events_test' and command = 'Connect' and user=current_user(); ---source include/wait_condition.inc - -DROP DATABASE events_test; - - # # Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash. # @@ -737,3 +725,215 @@ CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00' DELIMITER ;| SET GLOBAL event_scheduler= OFF; DROP EVENT bug28641; + +########################################################################### + +--echo +--echo ##################################################################### +--echo # +--echo # BUG#31111: --read-only crashes MySQL (events fail to load). +--echo # +--echo ##################################################################### +--echo + +--error 0,ER_CANNOT_USER +DROP USER mysqltest_u1@localhost; + +--disable_warnings +DROP EVENT IF EXISTS e1; +DROP EVENT IF EXISTS e2; +--enable_warnings + +--echo + +# Check that an ordinary user can not create/update/drop events in the +# read-only mode. + +GRANT EVENT ON *.* TO mysqltest_u1@localhost; + +--echo + +SET GLOBAL READ_ONLY = 1; + +--echo + +--echo # +--echo # Connection: u1_con (mysqltest_u1@localhost/events_test). +--echo # + +--connect(u1_con,localhost,mysqltest_u1,,events_test) + +--echo + +--error ER_OPTION_PREVENTS_STATEMENT +CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1; + +--echo + +--error ER_OPTION_PREVENTS_STATEMENT +ALTER EVENT e1 COMMENT 'comment'; + +--echo + +--error ER_OPTION_PREVENTS_STATEMENT +DROP EVENT e1; + +--echo + +# Check that the super user still can create/update/drop events. + +--echo # +--echo # Connection: root_con (root@localhost/events_test). +--echo # + +--connect(root_con,localhost,root,,events_test) + +--echo + +CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1; + +--echo + +ALTER EVENT e1 COMMENT 'comment'; + +--echo + +DROP EVENT e1; + +--echo + +# +# Switch to read-write mode; create test events under the user mysqltest_u1; +# switch back to read-only mode. +# + +SET GLOBAL READ_ONLY = 0; + +--echo + +--echo # +--echo # Connection: u1_con (mysqltest_u1@localhost/test). +--echo # + +--connection u1_con + +--echo + +CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1; +CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1; + +--echo + +SELECT + event_name, + last_executed IS NULL, + definer +FROM INFORMATION_SCHEMA.EVENTS +WHERE event_schema = 'events_test'; + +--echo + +--echo # +--echo # Connection: root_con (root@localhost/events_test). +--echo # + +--connection root_con + +--echo + +SET GLOBAL READ_ONLY = 1; + +# Check that the event scheduler is able to update event. + +--echo + +SET GLOBAL EVENT_SCHEDULER = ON; + +--echo + +--echo # Waiting for the event scheduler to execute and drop event e1... + +let $wait_timeout = 2; +let $wait_condition = + SELECT COUNT(*) = 0 + FROM INFORMATION_SCHEMA.EVENTS + WHERE event_schema = 'events_test' AND event_name = 'e1'; +--source include/wait_condition.inc + +--echo + +--echo # Waiting for the event scheduler to execute and update event e2... + +let $wait_condition = + SELECT last_executed IS NOT NULL + FROM INFORMATION_SCHEMA.EVENTS + WHERE event_schema = 'events_test' AND event_name = 'e2'; +--source include/wait_condition.inc + +--echo + +SET GLOBAL EVENT_SCHEDULER = OFF; + +--echo + +SELECT + event_name, + last_executed IS NULL, + definer +FROM INFORMATION_SCHEMA.EVENTS +WHERE event_schema = 'events_test'; + +--echo + +--error ER_EVENT_DOES_NOT_EXIST +DROP EVENT e1; + +--echo +--echo # Cleanup. +--echo + +DROP EVENT e2; + +--echo + +SET GLOBAL READ_ONLY = 0; + +--echo + +--echo # +--echo # Connection: default +--echo # + +--disconnect u1_con +--disconnect root_con +--connection default + +--echo + +DROP USER mysqltest_u1@localhost; + +--echo +--echo ##################################################################### +--echo # +--echo # End of BUG#31111. +--echo # +--echo ##################################################################### +--echo + + +########################################################################### +# +# End of tests +# +# !!! KEEP this section AT THE END of this file !!! +# +########################################################################### + +let $wait_condition= + select count(*) = 0 from information_schema.processlist + where db='events_test' and command = 'Connect' and user=current_user(); +--source include/wait_condition.inc + +DROP DATABASE events_test; + +# THIS MUST BE THE LAST LINE in this file. diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index cf25b4c61be..9d1e065797d 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -890,6 +890,7 @@ FLUSH STATUS; DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000; SHOW STATUS LIKE 'handler_read__e%'; FLUSH STATUS; +--error ER_SUBQUERY_NO_1_ROW DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x FROM t1) > 10000; SHOW STATUS LIKE 'handler_read__e%'; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index f1eb8e68b49..31d5ac5201b 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -501,3 +501,43 @@ ORDER BY c.b, c.d ; DROP TABLE t1, t2; + +# +# Bug #31148: bool close_thread_table(THD*, TABLE**): Assertion +# `table->key_read == 0' failed. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT); + +INSERT INTO t1 VALUES (), (), (); + +SELECT 1 AS c1 +FROM t1 +ORDER BY ( + SELECT 1 AS c2 + FROM t1 + GROUP BY GREATEST(LAST_INSERT_ID(), t1.a) ASC + LIMIT 1); + +DROP TABLE t1; + + +# +# Bug #31974: Wrong EXPLAIN output +# + +CREATE TABLE t1 (a INT, b INT, INDEX (a,b)); +INSERT INTO t1 (a, b) + VALUES + (1,1), (1,2), (1,3), (1,4), (1,5), + (2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); +EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE + (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; +SELECT 1 as RES FROM t1 AS t1_outer WHERE + (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12; + +DROP TABLE t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 25bd9a402ae..8635bbfab87 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -250,4 +250,31 @@ flush logs; --exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000016 >/dev/null 2>/dev/null --exec $MYSQL_BINLOG --force-if-open $MYSQLTEST_VARDIR/log/master-bin.000016 >/dev/null 2>/dev/null +--echo BUG#31611: Security risk with BINLOG statement + +SET BINLOG_FORMAT=ROW; +CREATE DATABASE mysqltest1; +CREATE USER untrusted@localhost; +GRANT SELECT ON mysqltest1.* TO untrusted@localhost; + +SHOW GRANTS FOR untrusted@localhost; +USE mysqltest1; +CREATE TABLE t1 (a INT, b CHAR(64)); +flush logs; +INSERT INTO t1 VALUES (1,USER()); +flush logs; +echo mysqlbinlog var/log/master-bin.000017 > var/tmp/bug31611.sql; +exec $MYSQL_BINLOG $MYSQLTEST_VARDIR/log/master-bin.000017 > $MYSQLTEST_VARDIR/tmp/bug31611.sql; +connect (unsecure,localhost,untrusted,,mysqltest1); +echo mysql mysqltest1 -uuntrusted < var/tmp/bug31611.sql; +error 1; +exec $MYSQL mysqltest1 -uuntrusted < $MYSQLTEST_VARDIR/tmp/bug31611.sql; +connection unsecure; +error ER_TABLEACCESS_DENIED_ERROR; +INSERT INTO t1 VALUES (1,USER()); + +SELECT * FROM t1; +connection default; +DROP DATABASE mysqltest1; + --echo End of 5.1 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index dea86bdd2fa..fd7caeb195e 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -2778,4 +2778,38 @@ execute stmt; show create table t1; drop table t1; +# +# Bug #32030 DELETE does not return an error and deletes rows if error +# evaluating WHERE +# +# Test that there is an error for prepared delete just like for the normal +# one. +# +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int, b int); +create table t2 like t1; + +insert into t1 (a, b) values (1,1), (1,2), (1,3), (1,4), (1,5), + (2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6); + +insert into t2 select a, max(b) from t1 group by a; + +prepare stmt from "delete from t2 where (select (select max(b) from t1 group +by a having a < 2) x from t1) > 10000"; + +--error ER_SUBQUERY_NO_1_ROW +delete from t2 where (select (select max(b) from t1 group +by a having a < 2) x from t1) > 10000; +--error ER_SUBQUERY_NO_1_ROW +execute stmt; +--error ER_SUBQUERY_NO_1_ROW +execute stmt; + +deallocate prepare stmt; +drop table t1, t2; + + + --echo End of 5.1 tests. diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 76a66cc4783..71a7caba399 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3473,6 +3473,54 @@ DROP VIEW v1, v2, v3; --enable_ps_protocol +########################################################################### + +--echo +--echo # +--echo # Bug#30736: Row Size Too Large Error Creating a Table and +--echo # Inserting Data. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +--echo + +CREATE TABLE t1( + c1 DECIMAL(10, 2), + c2 FLOAT); + +--echo + +INSERT INTO t1 VALUES (0, 1), (2, 3), (4, 5); + +--echo + +CREATE TABLE t2( + c3 DECIMAL(10, 2)) + SELECT + c1 * c2 AS c3 + FROM t1; + +--echo + +SELECT * FROM t1; + +--echo + +SELECT * FROM t2; + +--echo + +DROP TABLE t1; +DROP TABLE t2; + +--echo + +########################################################################### + --echo End of 5.0 tests # diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index a956a246770..606c2a673bc 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2078,10 +2078,6 @@ create function bug20701() returns varchar(25) binary return "test"; create function bug20701() returns varchar(25) return "test"; drop function bug20701; - ---echo End of 5.1 tests - - # # Bug#26503 (Illegal SQL exception handler code causes the server to crash) # @@ -2223,6 +2219,93 @@ SELECT ..inexistent(); USE test; # +# Bug#30904 SET PASSWORD statement is non-transactional +# + +delimiter |; + +--error ER_SP_CANT_SET_AUTOCOMMIT +create function f1() returns int +begin + set @test = 1, password = password('foo'); + return 1; +end| + +--error ER_SP_CANT_SET_AUTOCOMMIT +create trigger t1 + before insert on t2 for each row set password = password('foo');| + +delimiter ;| + +# +# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash +# + +--disable_warnings +drop function if exists f1; +drop function if exists f2; +drop table if exists t1, t2; +--enable_warnings + +delimiter |; +create function f1() returns int +begin + drop temporary table t1; + return 1; +end| +delimiter ;| +--error ER_CANT_REOPEN_TABLE +create temporary table t1 as select f1(); + +delimiter |; +create function f2() returns int +begin + create temporary table t2 as select f1(); + return 1; +end| +delimiter ;| +--error ER_CANT_REOPEN_TABLE +create temporary table t1 as select f2(); + +drop function f1; +drop function f2; + +delimiter |; +create function f1() returns int +begin + drop temporary table t2,t1; + return 1; +end| +create function f2() returns int +begin + create temporary table t2 as select f1(); + return 1; +end| +delimiter ;| +--error ER_CANT_REOPEN_TABLE +create temporary table t1 as select f2(); + +drop function f1; +drop function f2; + +create temporary table t2(a int); +select * from t2; +delimiter |; +create function f2() returns int +begin + drop temporary table t2; + return 1; +end| +delimiter ;| +select f2(); + +drop function f2; +--error ER_BAD_TABLE_ERROR +drop table t2; + +--echo End of 5.1 tests + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index 663dc08d72e..32cfca57546 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -35,20 +35,20 @@ eval CREATE FUNCTION reverse_lookup eval CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "$UDF_EXAMPLE_LIB"; ---error 0 +--error ER_CANT_INITIALIZE_UDF select myfunc_double(); select myfunc_double(1); select myfunc_double(78654); --error 1305 select myfunc_nonexist(); select myfunc_int(); ---error 0 +--error ER_CANT_INITIALIZE_UDF select lookup(); select lookup("127.0.0.1"); ---error 0 +--error ER_CANT_INITIALIZE_UDF select lookup(127,0,0,1); select lookup("localhost"); ---error 0 +--error ER_CANT_INITIALIZE_UDF select reverse_lookup(); # These two functions should return "localhost", but it's @@ -59,9 +59,9 @@ select reverse_lookup(127,0,0,1); --enable_result_log select reverse_lookup("localhost"); ---error 0 +--error ER_CANT_INITIALIZE_UDF select avgcost(); ---error 0 +--error ER_CANT_INITIALIZE_UDF select avgcost(100,23.76); create table t1(sum int, price float(24)); insert into t1 values(100, 50.00), (100, 100.00); diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index 6d6ebbee57d..276d1ca3b49 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -79,6 +79,9 @@ int main(int argc, char *argv[]) { int return_value; + puts("\n" + "WARNING: This program is deprecated and will be removed in 6.0.\n"); + /* Initialize. */ MY_INIT(argv[0]); diff --git a/sql-common/client.c b/sql-common/client.c index baf154dcc43..0ca7ef16c0d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -272,6 +272,76 @@ static int wait_for_data(my_socket fd, uint timeout) } #endif /* defined(__WIN__) || defined(__NETWARE__) */ +/** + Set the internal error message to mysql handler + + @param mysql connection handle (client side) + @param errcode CR_ error code, passed to ER macro to get + error text + @parma sqlstate SQL standard sqlstate +*/ + +void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) +{ + NET *net; + DBUG_ENTER("set_mysql_error"); + DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode))); + DBUG_ASSERT(mysql != 0); + + net= &mysql->net; + net->last_errno= errcode; + strmov(net->last_error, ER(errcode)); + strmov(net->sqlstate, sqlstate); + + DBUG_VOID_RETURN; +} + +/** + Clear possible error state of struct NET + + @param net clear the state of the argument +*/ + +void net_clear_error(NET *net) +{ + net->last_errno= 0; + net->last_error[0]= '\0'; + strmov(net->sqlstate, not_error_sqlstate); +} + +/** + Set an error message on the client. + + @param mysql connection handle + @param errcode CR_* errcode, for client errors + @param sqlstate SQL standard sql state, unknown_sqlstate for the + majority of client errors. + @param format error message template, in sprintf format + @param ... variable number of arguments +*/ + +static void set_mysql_extended_error(MYSQL *mysql, int errcode, + const char *sqlstate, + const char *format, ...) +{ + NET *net; + va_list args; + DBUG_ENTER("set_mysql_extended_error"); + DBUG_PRINT("enter", ("error :%d '%s'", errcode, format)); + DBUG_ASSERT(mysql != 0); + + net= &mysql->net; + net->last_errno= errcode; + va_start(args, format); + my_vsnprintf(net->last_error, sizeof(net->last_error)-1, + format, args); + va_end(args); + strmov(net->sqlstate, sqlstate); + + DBUG_VOID_RETURN; +} + + /* Create a named pipe connection @@ -279,7 +349,7 @@ static int wait_for_data(my_socket fd, uint timeout) #ifdef __WIN__ -HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, +HANDLE create_named_pipe(MYSQL *mysql, uint connect_timeout, char **arg_host, char **arg_unix_socket) { HANDLE hPipe=INVALID_HANDLE_VALUE; @@ -312,42 +382,34 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, break; if (GetLastError() != ERROR_PIPE_BUSY) { - net->last_errno=CR_NAMEDPIPEOPEN_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), host, unix_socket, - (ulong) GetLastError()); + set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, + unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR), + host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; } /* wait for for an other instance */ if (! WaitNamedPipe(pipe_name, connect_timeout*1000) ) { - net->last_errno=CR_NAMEDPIPEWAIT_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), host, unix_socket, - (ulong) GetLastError()); + set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate, + ER(CR_NAMEDPIPEWAIT_ERROR), + host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; } } if (hPipe == INVALID_HANDLE_VALUE) { - net->last_errno=CR_NAMEDPIPEOPEN_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), host, unix_socket, - (ulong) GetLastError()); + set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate, + ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket, + (ulong) GetLastError()); return INVALID_HANDLE_VALUE; } dwMode = PIPE_READMODE_BYTE | PIPE_WAIT; if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) ) { CloseHandle( hPipe ); - net->last_errno=CR_NAMEDPIPESETSTATE_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno),host, unix_socket, - (ulong) GetLastError()); + set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR, + unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR), + host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; } *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */ @@ -566,14 +628,12 @@ err: CloseHandle(handle_connect_file_map); if (error_allow) { - net->last_errno=error_allow; - strmov(net->sqlstate, unknown_sqlstate); if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR) - my_snprintf(net->last_error,sizeof(net->last_error)-1, - ER(net->last_errno),suffix_pos,error_code); + set_mysql_extended_error(mysql, error_allow, unknown_sqlstate, + ER(error_allow), suffix_pos, error_code); else - my_snprintf(net->last_error,sizeof(net->last_error)-1, - ER(net->last_errno),error_code); + set_mysql_extended_error(mysql, error_allow, unknown_sqlstate, + ER(error_allow), error_code); return(INVALID_HANDLE_VALUE); } return(handle_map); @@ -683,10 +743,8 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, DBUG_RETURN(1); } - net->last_error[0]=0; - net->last_errno= 0; - strmov(net->sqlstate, not_error_sqlstate); - mysql->net.report_error=0; + net_clear_error(net); + net->report_error=0; mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; /* @@ -703,8 +761,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, socket_errno)); if (net->last_errno == ER_NET_PACKET_TOO_LARGE) { - net->last_errno=CR_NET_PACKET_TOO_LARGE; - strmov(net->last_error,ER(net->last_errno)); + set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate); goto end; } end_server(mysql); @@ -713,8 +770,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, if (net_write_command(net,(uchar) command, header, header_length, arg, arg_length)) { - net->last_errno=CR_SERVER_GONE_ERROR; - strmov(net->last_error,ER(net->last_errno)); + set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate); goto end; } } @@ -742,48 +798,6 @@ void free_old_query(MYSQL *mysql) } /* - Set the internal error message to mysql handler -*/ - -void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) -{ - NET *net; - DBUG_ENTER("set_mysql_error"); - DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode))); - DBUG_ASSERT(mysql != 0); - - net= &mysql->net; - net->last_errno= errcode; - strmov(net->last_error, ER(errcode)); - strmov(net->sqlstate, sqlstate); - - DBUG_VOID_RETURN; -} - - -static void set_mysql_extended_error(MYSQL *mysql, int errcode, - const char *sqlstate, - const char *format, ...) -{ - NET *net; - va_list args; - DBUG_ENTER("set_mysql_extended_error"); - DBUG_PRINT("enter", ("error :%d '%s'", errcode, format)); - DBUG_ASSERT(mysql != 0); - - net= &mysql->net; - net->last_errno= errcode; - va_start(args, format); - my_vsnprintf(net->last_error, sizeof(net->last_error)-1, - format, args); - va_end(args); - strmov(net->sqlstate, sqlstate); - - DBUG_VOID_RETURN; -} - - -/* Flush result set sent from server */ @@ -846,9 +860,8 @@ static int check_license(MYSQL *mysql) { if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) { - net->last_errno= CR_WRONG_LICENSE; - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), required_license); + set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate, + ER(CR_WRONG_LICENSE), required_license); } return 1; } @@ -864,9 +877,8 @@ static int check_license(MYSQL *mysql) (!row || !row[0] || strncmp(row[0], required_license, sizeof(required_license)))) { - net->last_errno= CR_WRONG_LICENSE; - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), required_license); + set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate, + ER(CR_WRONG_LICENSE), required_license); } mysql_free_result(res); return net->last_errno; @@ -1717,7 +1729,6 @@ static MYSQL_METHODS client_methods= C_MODE_START int mysql_init_character_set(MYSQL *mysql) { - NET *net= &mysql->net; const char *default_collation_name; /* Set character set */ @@ -1761,24 +1772,22 @@ int mysql_init_character_set(MYSQL *mysql) } charsets_dir= save; } - + if (!mysql->charset) { - net->last_errno=CR_CANT_READ_CHARSET; - strmov(net->sqlstate, unknown_sqlstate); if (mysql->options.charset_dir) - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), - mysql->options.charset_name, - mysql->options.charset_dir); + set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, + ER(CR_CANT_READ_CHARSET), + mysql->options.charset_name, + mysql->options.charset_dir); else { char cs_dir_name[FN_REFLEN]; get_charsets_dir(cs_dir_name); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(net->last_errno), - mysql->options.charset_name, - cs_dir_name); + set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, + ER(CR_CANT_READ_CHARSET), + mysql->options.charset_name, + cs_dir_name); } return 1; } @@ -1910,10 +1919,10 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket)); if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR) { - net->last_errno=CR_SOCKET_CREATE_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error,sizeof(net->last_error)-1, - ER(net->last_errno),socket_errno); + set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR, + unknown_sqlstate, + ER(CR_SOCKET_CREATE_ERROR), + socket_errno); goto error; } net->vio= vio_new(sock, VIO_TYPE_SOCKET, @@ -1926,10 +1935,10 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, { DBUG_PRINT("error",("Got error %d on connect to local server", socket_errno)); - net->last_errno=CR_CONNECTION_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error,sizeof(net->last_error)-1, - ER(net->last_errno),unix_socket,socket_errno); + set_mysql_extended_error(mysql, CR_CONNECTION_ERROR, + unknown_sqlstate, + ER(CR_CONNECTION_ERROR), + unix_socket, socket_errno); goto error; } mysql->options.protocol=MYSQL_PROTOCOL_SOCKET; @@ -1941,8 +1950,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, (! have_tcpip && (unix_socket || !host && is_NT())))) { sock=0; - if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout, - (char**) &host, (char**) &unix_socket)) == + if ((hPipe= create_named_pipe(mysql, mysql->options.connect_timeout, + (char**) &host, (char**) &unix_socket)) == INVALID_HANDLE_VALUE) { DBUG_PRINT("error", @@ -1986,10 +1995,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, #endif if (sock == SOCKET_ERROR) { - net->last_errno=CR_IPSOCK_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error,sizeof(net->last_error)-1, - ER(net->last_errno),socket_errno); + set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate, + ER(CR_IPSOCK_ERROR), socket_errno); goto error; } net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ); @@ -2014,10 +2021,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, if (!hp) { my_gethostbyname_r_free(); - net->last_errno=CR_UNKNOWN_HOST; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(CR_UNKNOWN_HOST), host, tmp_errno); + set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate, + ER(CR_UNKNOWN_HOST), host, tmp_errno); goto error; } memcpy(&sock_addr.sin_addr, hp->h_addr, @@ -2030,10 +2035,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, { DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno, host)); - net->last_errno= CR_CONN_HOST_ERROR; - strmov(net->sqlstate, unknown_sqlstate); - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(CR_CONN_HOST_ERROR), host, socket_errno); + set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate, + ER(CR_CONN_HOST_ERROR), host, socket_errno); goto error; } } @@ -2097,11 +2100,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, PROTOCOL_VERSION, mysql->protocol_version)); if (mysql->protocol_version != PROTOCOL_VERSION) { - strmov(net->sqlstate, unknown_sqlstate); - net->last_errno= CR_VERSION_ERROR; - my_snprintf(net->last_error, sizeof(net->last_error)-1, - ER(CR_VERSION_ERROR), mysql->protocol_version, - PROTOCOL_VERSION); + set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate, + ER(CR_VERSION_ERROR), mysql->protocol_version, + PROTOCOL_VERSION); goto error; } end=strend((char*) net->read_pos+1); @@ -2625,7 +2626,7 @@ void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)), for (; element; element= element->next) { MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; - set_stmt_errmsg(stmt, buff, CR_STMT_CLOSED, unknown_sqlstate); + set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff); stmt->mysql= 0; /* No need to call list_delete for statement here */ } @@ -3142,11 +3143,8 @@ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) { char cs_dir_name[FN_REFLEN]; get_charsets_dir(cs_dir_name); - mysql->net.last_errno= CR_CANT_READ_CHARSET; - strmov(mysql->net.sqlstate, unknown_sqlstate); - my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1, - ER(mysql->net.last_errno), cs_name, cs_dir_name); - + set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate, + ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name); } charsets_dir= save_csdir; return mysql->net.last_errno; diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 787b04c12c6..adac2b596c1 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -2017,6 +2017,7 @@ end_no_lex_start: ret= 1; else { + ulong saved_master_access; /* Peculiar initialization order is a crutch to avoid races in SHOW PROCESSLIST which reads thd->{query/query_length} without a mutex. @@ -2024,8 +2025,19 @@ end_no_lex_start: thd->query_length= 0; thd->query= sp_sql.c_ptr_safe(); thd->query_length= sp_sql.length(); - if (Events::drop_event(thd, dbname, name, FALSE)) - ret= 1; + + /* + NOTE: even if we run in read-only mode, we should be able to lock + the mysql.event table for writing. In order to achieve this, we + should call mysql_lock_tables() under the super-user. + */ + + saved_master_access= thd->security_ctx->master_access; + thd->security_ctx->master_access |= SUPER_ACL; + + ret= Events::drop_event(thd, dbname, name, FALSE); + + thd->security_ctx->master_access= saved_master_access; } } #ifndef NO_EMBEDDED_ACCESS_CHECKS diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 705bd8b2704..9a33b33d8c9 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -525,6 +525,10 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, - whether this open mode would work under LOCK TABLES, or inside a stored function or trigger. + Note that if the table can't be locked successfully this operation will + close it. Therefore it provides guarantee that it either opens and locks + table or fails without leaving any tables open. + @param[in] thd Thread context @param[in] lock_type How to lock the table @param[out] table We will store the open table here @@ -544,7 +548,10 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, tables.init_one_table("mysql", "event", lock_type); if (simple_open_n_lock_tables(thd, &tables)) + { + close_thread_tables(thd); DBUG_RETURN(TRUE); + } *table= tables.table; tables.table->use_all_columns(); @@ -995,6 +1002,8 @@ update_timing_fields_for_event(THD *thd, if (thd->current_stmt_binlog_row_based) thd->clear_current_stmt_binlog_row_based(); + DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL); + if (open_event_table(thd, TL_WRITE, &table)) goto end; diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index b03b51f1134..d3a031fd8f8 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -399,6 +399,13 @@ Event_scheduler::start() new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER; new_thd->command= COM_DAEMON; + /* + We should run the event scheduler thread under the super-user privileges. + In particular, this is needed to be able to lock the mysql.event table + for writing when the server is running in the read-only mode. + */ + new_thd->security_ctx->master_access |= SUPER_ACL; + scheduler_param_value= (struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0)); scheduler_param_value->thd= new_thd; diff --git a/sql/events.cc b/sql/events.cc index 5246bccc388..1bfbc5d6645 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1124,11 +1124,25 @@ Events::load_events_from_db(THD *thd) READ_RECORD read_record_info; bool ret= TRUE; uint count= 0; + ulong saved_master_access; DBUG_ENTER("Events::load_events_from_db"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); - if (db_repository->open_event_table(thd, TL_WRITE, &table)) + /* + NOTE: even if we run in read-only mode, we should be able to lock the + mysql.event table for writing. In order to achieve this, we should call + mysql_lock_tables() under the super user. + */ + + saved_master_access= thd->security_ctx->master_access; + thd->security_ctx->master_access |= SUPER_ACL; + + ret= db_repository->open_event_table(thd, TL_WRITE, &table); + + thd->security_ctx->master_access= saved_master_access; + + if (ret) { sql_print_error("Event Scheduler: Failed to open table mysql.event"); DBUG_RETURN(TRUE); diff --git a/sql/filesort.cc b/sql/filesort.cc index c074f90e780..2e6f0ecaf05 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -555,7 +555,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, else file->unlock_row(); /* It does not make sense to read more keys in case of a fatal error */ - if (thd->net.report_error) + if (thd->is_error()) break; } if (quick_select) @@ -573,7 +573,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, file->ha_rnd_end(); } - if (thd->net.report_error) + if (thd->is_error()) DBUG_RETURN(HA_POS_ERROR); /* Signal we should use orignal column read and write maps */ diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b2152fbb906..436710e3dee 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -325,9 +325,9 @@ Thd_ndb::Thd_ndb() { ndb= new Ndb(g_ndb_cluster_connection, ""); lock_count= 0; + start_stmt_count= 0; count= 0; - all= NULL; - stmt= NULL; + trans= NULL; m_error= FALSE; m_error_code= 0; query_state&= NDB_QUERY_NORMAL; @@ -382,6 +382,11 @@ Thd_ndb::get_open_table(THD *thd, const void *key) { thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, sizeof(THD_NDB_SHARE)); + if (!thd_ndb_share) + { + mem_alloc_error(sizeof(THD_NDB_SHARE)); + DBUG_RETURN(NULL); + } thd_ndb_share->key= key; thd_ndb_share->stat.last_count= count; thd_ndb_share->stat.no_uncommitted_rows_count= 0; @@ -1638,6 +1643,26 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re DBUG_RETURN(0); } +bool ha_ndbcluster::check_index_fields_in_write_set(uint keyno) +{ + KEY* key_info= table->key_info + keyno; + KEY_PART_INFO* key_part= key_info->key_part; + KEY_PART_INFO* end= key_part+key_info->key_parts; + uint i; + DBUG_ENTER("check_index_fields_in_write_set"); + + for (i= 0; key_part != end; key_part++, i++) + { + Field* field= key_part->field; + if (!bitmap_is_set(table->write_set, field->field_index)) + { + DBUG_RETURN(false); + } + } + + DBUG_RETURN(true); +} + int ha_ndbcluster::set_index_key_from_record(NdbOperation *op, const uchar *record, uint keyno) { @@ -1956,8 +1981,8 @@ check_null_in_record(const KEY* key_info, const uchar *record) * primary key or unique index values */ -int ha_ndbcluster::peek_indexed_rows(const uchar *record, - bool check_pk) +int ha_ndbcluster::peek_indexed_rows(const uchar *record, + NDB_WRITE_OP write_op) { NdbTransaction *trans= m_active_trans; NdbOperation *op; @@ -1969,7 +1994,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); first= NULL; - if (check_pk && table->s->primary_key != MAX_KEY) + if (write_op != NDB_UPDATE && table->s->primary_key != MAX_KEY) { /* * Fetch any row with colliding primary key @@ -2019,6 +2044,11 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, DBUG_PRINT("info", ("skipping check for key with NULL")); continue; } + if (write_op != NDB_INSERT && !check_index_fields_in_write_set(i)) + { + DBUG_PRINT("info", ("skipping check for key %u not in write_set", i)); + continue; + } NdbIndexOperation *iop; const NDBINDEX *unique_index = m_index[i].unique_index; key_part= key_info->key_part; @@ -2716,7 +2746,7 @@ int ha_ndbcluster::write_row(uchar *record) start_bulk_insert will set parameters to ensure that each write_row is committed individually */ - int peek_res= peek_indexed_rows(record, TRUE); + int peek_res= peek_indexed_rows(record, NDB_INSERT); if (!peek_res) { @@ -2765,7 +2795,7 @@ int ha_ndbcluster::write_row(uchar *record) if (ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1) == -1) { if (--retries && - ndb->getNdbError().status == NdbError::TemporaryError); + ndb->getNdbError().status == NdbError::TemporaryError) { my_sleep(retry_sleep); continue; @@ -2960,7 +2990,8 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) if (m_ignore_dup_key && (thd->lex->sql_command == SQLCOM_UPDATE || thd->lex->sql_command == SQLCOM_UPDATE_MULTI)) { - int peek_res= peek_indexed_rows(new_data, pk_update); + NDB_WRITE_OP write_op= (pk_update) ? NDB_PK_UPDATE : NDB_UPDATE; + int peek_res= peek_indexed_rows(new_data, write_op); if (!peek_res) { @@ -4327,7 +4358,7 @@ static int ndbcluster_update_apply_status(THD *thd, int do_update) Ndb *ndb= thd_ndb->ndb; NDBDICT *dict= ndb->getDictionary(); const NDBTAB *ndbtab; - NdbTransaction *trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt; + NdbTransaction *trans= thd_ndb->trans; ndb->setDatabaseName(NDB_REP_DB); Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE); if (!(ndbtab= ndbtab_g.get_table())) @@ -4371,10 +4402,110 @@ static int ndbcluster_update_apply_status(THD *thd, int do_update) } #endif /* HAVE_NDB_BINLOG */ +void ha_ndbcluster::transaction_checks(THD *thd) +{ + if (thd->lex->sql_command == SQLCOM_LOAD) + { + m_transaction_on= FALSE; + /* Would be simpler if has_transactions() didn't always say "yes" */ + thd->transaction.all.modified_non_trans_table= + thd->transaction.stmt.modified_non_trans_table= TRUE; + } + else if (!thd->transaction.on) + m_transaction_on= FALSE; + else + m_transaction_on= thd->variables.ndb_use_transactions; +} + +int ha_ndbcluster::start_statement(THD *thd, + Thd_ndb *thd_ndb, + Ndb *ndb) +{ + DBUG_ENTER("ha_ndbcluster::start_statement"); + PRINT_OPTION_FLAGS(thd); + + trans_register_ha(thd, FALSE, ndbcluster_hton); + if (!thd_ndb->trans) + { + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trans_register_ha(thd, TRUE, ndbcluster_hton); + DBUG_PRINT("trans",("Starting transaction")); + thd_ndb->trans= ndb->startTransaction(); + if (thd_ndb->trans == NULL) + ERR_RETURN(ndb->getNdbError()); + thd_ndb->init_open_tables(); + thd_ndb->query_state&= NDB_QUERY_NORMAL; + thd_ndb->trans_options= 0; + thd_ndb->m_slow_path= FALSE; + if (!(thd->options & OPTION_BIN_LOG) || + thd->variables.binlog_format == BINLOG_FORMAT_STMT) + { + thd_ndb->trans_options|= TNTO_NO_LOGGING; + thd_ndb->m_slow_path= TRUE; + } + else if (thd->slave_thread) + thd_ndb->m_slow_path= TRUE; + } + /* + If this is the start of a LOCK TABLE, a table look + should be taken on the table in NDB + + Check if it should be read or write lock + */ + if (thd->options & (OPTION_TABLE_LOCK)) + { + //lockThisTable(); + DBUG_PRINT("info", ("Locking the table..." )); + } + DBUG_RETURN(0); +} + +int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) +{ + /* + This is the place to make sure this handler instance + has a started transaction. + + The transaction is started by the first handler on which + MySQL Server calls external lock + + Other handlers in the same stmt or transaction should use + the same NDB transaction. This is done by setting up the m_active_trans + pointer to point to the NDB transaction. + */ + + DBUG_ENTER("ha_ndbcluster::init_handler_for_statement"); + // store thread specific data first to set the right context + m_force_send= thd->variables.ndb_force_send; + m_ha_not_exact_count= !thd->variables.ndb_use_exact_count; + m_autoincrement_prefetch= + (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz; + + m_active_trans= thd_ndb->trans; + DBUG_ASSERT(m_active_trans); + // Start of transaction + m_rows_changed= 0; + m_ops_pending= 0; + m_slow_path= thd_ndb->m_slow_path; +#ifdef HAVE_NDB_BINLOG + if (unlikely(m_slow_path)) + { + if (m_share == ndb_apply_status_share && thd->slave_thread) + thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS; + } +#endif + // TODO remove double pointers... + if (!(m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table))) + { + DBUG_RETURN(1); + } + m_table_info= &m_thd_ndb_share->stat; + DBUG_RETURN(0); +} + int ha_ndbcluster::external_lock(THD *thd, int lock_type) { int error=0; - NdbTransaction* trans= NULL; DBUG_ENTER("external_lock"); /* @@ -4395,124 +4526,15 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (lock_type != F_UNLCK) { DBUG_PRINT("info", ("lock_type != F_UNLCK")); - if (thd->lex->sql_command == SQLCOM_LOAD) - { - m_transaction_on= FALSE; - /* Would be simpler if has_transactions() didn't always say "yes" */ - thd->transaction.all.modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table= TRUE; - } - else if (!thd->transaction.on) - m_transaction_on= FALSE; - else - m_transaction_on= thd->variables.ndb_use_transactions; + transaction_checks(thd); if (!thd_ndb->lock_count++) { - PRINT_OPTION_FLAGS(thd); - if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) - { - // Autocommit transaction - DBUG_ASSERT(!thd_ndb->stmt); - DBUG_PRINT("trans",("Starting transaction stmt")); - - trans= ndb->startTransaction(); - if (trans == NULL) - { - thd_ndb->lock_count= 0; - ERR_RETURN(ndb->getNdbError()); - } - thd_ndb->init_open_tables(); - thd_ndb->stmt= trans; - thd_ndb->query_state&= NDB_QUERY_NORMAL; - thd_ndb->trans_options= 0; - thd_ndb->m_slow_path= FALSE; - if (!(thd->options & OPTION_BIN_LOG) || - thd->variables.binlog_format == BINLOG_FORMAT_STMT) - { - thd_ndb->trans_options|= TNTO_NO_LOGGING; - thd_ndb->m_slow_path= TRUE; - } - else if (thd->slave_thread) - thd_ndb->m_slow_path= TRUE; - trans_register_ha(thd, FALSE, ndbcluster_hton); - } - else - { - if (!thd_ndb->all) - { - // Not autocommit transaction - // A "master" transaction ha not been started yet - DBUG_PRINT("trans",("starting transaction, all")); - - trans= ndb->startTransaction(); - if (trans == NULL) - { - thd_ndb->lock_count= 0; - ERR_RETURN(ndb->getNdbError()); - } - thd_ndb->init_open_tables(); - thd_ndb->all= trans; - thd_ndb->query_state&= NDB_QUERY_NORMAL; - thd_ndb->trans_options= 0; - thd_ndb->m_slow_path= FALSE; - if (!(thd->options & OPTION_BIN_LOG) || - thd->variables.binlog_format == BINLOG_FORMAT_STMT) - { - thd_ndb->trans_options|= TNTO_NO_LOGGING; - thd_ndb->m_slow_path= TRUE; - } - else if (thd->slave_thread) - thd_ndb->m_slow_path= TRUE; - trans_register_ha(thd, TRUE, ndbcluster_hton); - - /* - If this is the start of a LOCK TABLE, a table look - should be taken on the table in NDB - - Check if it should be read or write lock - */ - if (thd->options & (OPTION_TABLE_LOCK)) - { - //lockThisTable(); - DBUG_PRINT("info", ("Locking the table..." )); - } - - } - } - } - /* - This is the place to make sure this handler instance - has a started transaction. - - The transaction is started by the first handler on which - MySQL Server calls external lock - - Other handlers in the same stmt or transaction should use - the same NDB transaction. This is done by setting up the m_active_trans - pointer to point to the NDB transaction. - */ - - // store thread specific data first to set the right context - m_force_send= thd->variables.ndb_force_send; - m_ha_not_exact_count= !thd->variables.ndb_use_exact_count; - m_autoincrement_prefetch= - (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz; - - m_active_trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt; - DBUG_ASSERT(m_active_trans); - // Start of transaction - m_rows_changed= 0; - m_ops_pending= 0; - m_slow_path= thd_ndb->m_slow_path; -#ifdef HAVE_NDB_BINLOG - if (unlikely(m_slow_path)) - { - if (m_share == ndb_apply_status_share && thd->slave_thread) - thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS; + if ((error= start_statement(thd, thd_ndb, ndb))) + goto error; } -#endif - // TODO remove double pointers... - m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table); - m_table_info= &m_thd_ndb_share->stat; + if ((error= init_handler_for_statement(thd, thd_ndb))) + goto error; + DBUG_RETURN(0); } else { @@ -4540,16 +4562,19 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_PRINT("trans", ("Last external_lock")); PRINT_OPTION_FLAGS(thd); - if (thd_ndb->stmt) + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - /* - Unlock is done without a transaction commit / rollback. - This happens if the thread didn't update any rows - We must in this case close the transaction to release resources - */ - DBUG_PRINT("trans",("ending non-updating transaction")); - ndb->closeTransaction(m_active_trans); - thd_ndb->stmt= NULL; + if (thd_ndb->trans) + { + /* + Unlock is done without a transaction commit / rollback. + This happens if the thread didn't update any rows + We must in this case close the transaction to release resources + */ + DBUG_PRINT("trans",("ending non-updating transaction")); + ndb->closeTransaction(thd_ndb->trans); + thd_ndb->trans= NULL; + } } } m_table_info= NULL; @@ -4578,7 +4603,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (m_ops_pending) DBUG_PRINT("warning", ("ops_pending != 0L")); m_ops_pending= 0; + DBUG_RETURN(0); } +error: + thd_ndb->lock_count--; DBUG_RETURN(error); } @@ -4610,25 +4638,20 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; DBUG_ENTER("start_stmt"); - PRINT_OPTION_FLAGS(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); - NdbTransaction *trans= (thd_ndb->stmt)?thd_ndb->stmt:thd_ndb->all; - if (!trans){ + transaction_checks(thd); + if (!thd_ndb->start_stmt_count++) + { Ndb *ndb= thd_ndb->ndb; - DBUG_PRINT("trans",("Starting transaction stmt")); - trans= ndb->startTransaction(); - if (trans == NULL) - ERR_RETURN(ndb->getNdbError()); - no_uncommitted_rows_reset(thd); - thd_ndb->stmt= trans; - thd_ndb->query_state&= NDB_QUERY_NORMAL; - trans_register_ha(thd, FALSE, ndbcluster_hton); + if ((error= start_statement(thd, thd_ndb, ndb))) + goto error; } - m_active_trans= trans; - // Start of statement - m_ops_pending= 0; - + if ((error= init_handler_for_statement(thd, thd_ndb))) + goto error; + DBUG_RETURN(0); +error: + thd_ndb->start_stmt_count--; DBUG_RETURN(error); } @@ -4642,15 +4665,29 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) int res= 0; Thd_ndb *thd_ndb= get_thd_ndb(thd); Ndb *ndb= thd_ndb->ndb; - NdbTransaction *trans= all ? thd_ndb->all : thd_ndb->stmt; + NdbTransaction *trans= thd_ndb->trans; DBUG_ENTER("ndbcluster_commit"); - DBUG_PRINT("transaction",("%s", - trans == thd_ndb->stmt ? - "stmt" : "all")); DBUG_ASSERT(ndb); - if (trans == NULL) + PRINT_OPTION_FLAGS(thd); + DBUG_PRINT("enter", ("Commit %s", (all ? "all" : "stmt"))); + thd_ndb->start_stmt_count= 0; + if (trans == NULL || (!all && + thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + { + /* + An odditity in the handler interface is that commit on handlerton + is called to indicate end of statement only in cases where + autocommit isn't used and the all flag isn't set. + + We also leave quickly when a transaction haven't even been started, + in this case we are safe that no clean up is needed. In this case + the MySQL Server could handle the query without contacting the + NDB kernel. + */ + DBUG_PRINT("info", ("Commit before start or end-of-statement only")); DBUG_RETURN(0); + } #ifdef HAVE_NDB_BINLOG if (unlikely(thd_ndb->m_slow_path)) @@ -4671,11 +4708,7 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) ndbcluster_print_error(res, error_op); } ndb->closeTransaction(trans); - - if (all) - thd_ndb->all= NULL; - else - thd_ndb->stmt= NULL; + thd_ndb->trans= NULL; /* Clear commit_count for tables changed by transaction */ NDB_SHARE* share; @@ -4704,13 +4737,18 @@ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) int res= 0; Thd_ndb *thd_ndb= get_thd_ndb(thd); Ndb *ndb= thd_ndb->ndb; - NdbTransaction *trans= all ? thd_ndb->all : thd_ndb->stmt; + NdbTransaction *trans= thd_ndb->trans; DBUG_ENTER("ndbcluster_rollback"); - DBUG_PRINT("transaction",("%s", - trans == thd_ndb->stmt ? - "stmt" : "all")); - DBUG_ASSERT(ndb && trans); + DBUG_ASSERT(ndb); + thd_ndb->start_stmt_count= 0; + if (trans == NULL || (!all && + thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + { + /* Ignore end-of-statement until real rollback or commit is called */ + DBUG_PRINT("info", ("Rollback before start or end-of-statement only")); + DBUG_RETURN(0); + } if (trans->execute(NdbTransaction::Rollback) != 0) { @@ -4722,11 +4760,7 @@ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) ndbcluster_print_error(res, error_op); } ndb->closeTransaction(trans); - - if (all) - thd_ndb->all= NULL; - else - thd_ndb->stmt= NULL; + thd_ndb->trans= NULL; /* Clear list of tables changed by transaction */ thd_ndb->changed_tables.empty(); @@ -6155,7 +6189,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size, increment, offset)) { if (--retries && - ndb->getNdbError().status == NdbError::TemporaryError); + ndb->getNdbError().status == NdbError::TemporaryError) { my_sleep(retry_sleep); continue; diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index a6f992226c2..fd337303853 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -81,6 +81,12 @@ typedef struct ndb_index_data { uint index_stat_query_count; } NDB_INDEX_DATA; +typedef enum ndb_write_op { + NDB_INSERT = 0, + NDB_UPDATE = 1, + NDB_PK_UPDATE = 2 +} NDB_WRITE_OP; + typedef union { const NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue; int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, @@ -204,8 +210,8 @@ class Thd_ndb Ndb *ndb; ulong count; uint lock_count; - NdbTransaction *all; - NdbTransaction *stmt; + uint start_stmt_count; + NdbTransaction *trans; bool m_error; bool m_slow_path; int m_error_code; @@ -438,7 +444,7 @@ private: const NdbOperation *first, const NdbOperation *last, uint errcode); - int peek_indexed_rows(const uchar *record, bool check_pk); + int peek_indexed_rows(const uchar *record, NDB_WRITE_OP write_op); int fetch_next(NdbScanOperation* op); int next_result(uchar *buf); int define_read_attrs(uchar* buf, NdbOperation* op); @@ -463,6 +469,7 @@ private: friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg); int set_primary_key(NdbOperation *op, const uchar *key); int set_primary_key_from_record(NdbOperation *op, const uchar *record); + bool check_index_fields_in_write_set(uint keyno); int set_index_key_from_record(NdbOperation *op, const uchar *record, uint keyno); int set_bounds(NdbIndexScanOperation*, uint inx, bool rir, @@ -496,6 +503,10 @@ private: friend int execute_no_commit(ha_ndbcluster*, NdbTransaction*, bool); friend int execute_no_commit_ie(ha_ndbcluster*, NdbTransaction*, bool); + void transaction_checks(THD *thd); + int start_statement(THD *thd, Thd_ndb *thd_ndb, Ndb* ndb); + int init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb); + NdbTransaction *m_active_trans; NdbScanOperation *m_active_cursor; const NdbDictionary::Table *m_table; diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 5d5c8a26447..fc35a7a930e 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -259,7 +259,7 @@ static void run_query(THD *thd, char *buf, char *end, DBUG_PRINT("query", ("%s", thd->query)); mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); - if (no_print_error && thd->query_error) + if (no_print_error && thd->is_slave_error) { int i; Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -271,7 +271,7 @@ static void run_query(THD *thd, char *buf, char *end, sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d", buf, thd->net.last_error, thd->net.last_errno, thd_ndb->m_error_code, - thd->net.report_error, thd->query_error); + (int) thd->is_error(), thd->is_slave_error); } thd->options= save_thd_options; diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc index 94342c6d2ad..d8dff3c7e2f 100644 --- a/sql/ha_ndbcluster_cond.cc +++ b/sql/ha_ndbcluster_cond.cc @@ -1338,9 +1338,23 @@ ha_ndbcluster_cond::generate_scan_filter(NdbScanOperation *op) if (m_cond_stack) { - NdbScanFilter filter(op); + NdbScanFilter filter(op, false); // don't abort on too large - DBUG_RETURN(generate_scan_filter_from_cond(filter)); + int ret=generate_scan_filter_from_cond(filter); + if (ret != 0) + { + const NdbError& err=filter.getNdbError(); + if (err.code == NdbScanFilter::FilterTooLarge) + { + // err.message has static storage + DBUG_PRINT("info", ("%s", err.message)); + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + err.code, err.message); + ret=0; + } + } + if (ret != 0) + DBUG_RETURN(ret); } else { @@ -1391,7 +1405,7 @@ int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op, { KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - NdbScanFilter filter(op); + NdbScanFilter filter(op, true); // abort on too large int res; DBUG_ENTER("generate_scan_filter_from_key"); diff --git a/sql/handler.cc b/sql/handler.cc index 3939873ec7d..1606c160238 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1414,6 +1414,36 @@ static const char *check_lowercase_names(handler *file, const char *path, } +/** + An interceptor to hijack the text of the error message without + setting an error in the thread. We need the text to present it + in the form of a warning to the user. +*/ + +struct Ha_delete_table_error_handler: public Internal_error_handler +{ +public: + virtual bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + char buff[MYSQL_ERRMSG_SIZE]; +}; + + +bool +Ha_delete_table_error_handler:: +handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + /* Grab the error message */ + strmake(buff, message, sizeof(buff)-1); + return TRUE; +} + + /** @brief This should return ENOENT if the file doesn't exists. The .frm file will be deleted only if we return 0 or ENOENT @@ -1442,23 +1472,11 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, { /* Because file->print_error() use my_error() to generate the error message - we must store the error state in thd, reset it and restore it to - be able to get hold of the error message. - (We should in the future either rewrite handler::print_error() or make - a nice method of this. + we use an internal error handler to intercept it and store the text + in a temporary buffer. Later the message will be presented to user + as a warning. */ - bool query_error= thd->query_error; - sp_rcontext *spcont= thd->spcont; - SELECT_LEX *current_select= thd->lex->current_select; - char buff[sizeof(thd->net.last_error)]; - char new_error[sizeof(thd->net.last_error)]; - int last_errno= thd->net.last_errno; - - strmake(buff, thd->net.last_error, sizeof(buff)-1); - thd->query_error= 0; - thd->spcont= NULL; - thd->lex->current_select= 0; - thd->net.last_error[0]= 0; + Ha_delete_table_error_handler ha_delete_table_error_handler; /* Fill up strucutures that print_error may need */ dummy_share.path.str= (char*) path; @@ -1471,16 +1489,18 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, file->table_share= &dummy_share; file->table= &dummy_table; + + thd->push_internal_handler(&ha_delete_table_error_handler); file->print_error(error, 0); - strmake(new_error, thd->net.last_error, sizeof(buff)-1); - /* restore thd */ - thd->query_error= query_error; - thd->spcont= spcont; - thd->lex->current_select= current_select; - thd->net.last_errno= last_errno; - strmake(thd->net.last_error, buff, sizeof(buff)-1); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error); + thd->pop_internal_handler(); + + /* + XXX: should we convert *all* errors to warnings here? + What if the error is fatal? + */ + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, + ha_delete_table_error_handler.buff); } delete file; DBUG_RETURN(error); @@ -2203,7 +2223,7 @@ void handler::print_error(int error, myf errflag) case HA_ERR_NO_SUCH_TABLE: my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str, table_share->table_name.str); - break; + DBUG_VOID_RETURN; case HA_ERR_RBR_LOGGING_FAILED: textno= ER_BINLOG_ROW_LOGGING_FAILED; break; @@ -2641,8 +2661,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) frmblob and frmlen are set, write the frm to disk */ - (void)strxnmov(path,FN_REFLEN-1,mysql_data_home,FN_ROOTDIR, - db,FN_ROOTDIR,name,NullS); + build_table_filename(path, FN_REFLEN-1, db, name, "", 0); // Save the frm file error= writefrm(path, frmblob, frmlen); my_free(frmblob, MYF(0)); diff --git a/sql/item_func.cc b/sql/item_func.cc index 67969a12774..fcc1846ed6d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -187,7 +187,7 @@ Item_func::fix_fields(THD *thd, Item **ref) } } fix_length_and_dec(); - if (thd->net.report_error) // An error inside fix_length_and_dec occured + if (thd->is_error()) // An error inside fix_length_and_dec occured return TRUE; fixed= 1; return FALSE; @@ -2897,6 +2897,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, if (u_d->func_init) { + char init_msg_buff[MYSQL_ERRMSG_SIZE]; char *to=num_buffer; for (uint i=0; i < arg_count; i++) { @@ -2949,10 +2950,10 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, } thd->net.last_error[0]=0; Udf_func_init init= u_d->func_init; - if ((error=(uchar) init(&initid, &f_args, thd->net.last_error))) + if ((error=(uchar) init(&initid, &f_args, init_msg_buff))) { my_error(ER_CANT_INITIALIZE_UDF, MYF(0), - u_d->name.str, thd->net.last_error); + u_d->name.str, init_msg_buff); free_udf(u_d); DBUG_RETURN(TRUE); } @@ -4073,7 +4074,7 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) NOTES For now it always return OK. All problem with value evaluating - will be caught by thd->net.report_error check in sql_set_variables(). + will be caught by thd->is_error() check in sql_set_variables(). RETURN FALSE OK. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 843c6ced263..8eb7421f854 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -248,7 +248,7 @@ bool Item_subselect::exec() { int res; - if (thd->net.report_error) + if (thd->is_error()) /* Do not execute subselect in case of a fatal error */ return 1; diff --git a/sql/log.cc b/sql/log.cc index e923418b23a..688ed03d5d1 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -72,13 +72,14 @@ public: virtual ~Silence_log_table_errors() {} - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd); }; bool Silence_log_table_errors::handle_error(uint /* sql_errno */, + const char * /* message */, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { @@ -2891,8 +2892,8 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, *decrease_log_space-= file_size; ha_binlog_index_purge_file(current_thd, log_info.log_file_name); - if (current_thd->query_error) { - DBUG_PRINT("info",("query error: %d", current_thd->query_error)); + if (current_thd->is_slave_error) { + DBUG_PRINT("info",("slave error: %d", current_thd->is_slave_error)); if (my_errno == EMFILE) { DBUG_PRINT("info",("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); ret = LOG_INFO_EMFILE; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3ff1ff13069..4353c9499b5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -148,7 +148,7 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len) static void clear_all_errors(THD *thd, Relay_log_info *rli) { - thd->query_error = 0; + thd->is_slave_error = 0; thd->clear_error(); rli->clear_error(); } @@ -2106,7 +2106,7 @@ and was aborted. There is a chance that your master is inconsistent at this \ point. If you are sure that your master is ok, run this query manually on the \ slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \ START SLAVE; . Query: '%s'", expected_error, thd->query); - thd->query_error= 1; + thd->is_slave_error= 1; } goto end; } @@ -2138,7 +2138,7 @@ Default database: '%s'. Query: '%s'", actual_error ? thd->net.last_error: "no error", actual_error, print_slave_db_safe(db), query_arg); - thd->query_error= 1; + thd->is_slave_error= 1; } /* If we get the same error code as expected, or they should be ignored. @@ -2153,14 +2153,14 @@ Default database: '%s'. Query: '%s'", /* Other cases: mostly we expected no error and get one. */ - else if (thd->query_error || thd->is_fatal_error) + else if (thd->is_slave_error || thd->is_fatal_error) { rli->report(ERROR_LEVEL, actual_error, "Error '%s' on query. Default database: '%s'. Query: '%s'", (actual_error ? thd->net.last_error : "unexpected success or fatal error"), print_slave_db_safe(thd->db), query_arg); - thd->query_error= 1; + thd->is_slave_error= 1; } /* @@ -2171,7 +2171,7 @@ Default database: '%s'. Query: '%s'", sql_print_error("Slave: did not get the expected number of affected \ rows running query from master - expected %d, got %d (this numbers \ should have matched modulo 4294967296).", 0, ...); - thd->query_error = 1; + thd->is_slave_error = 1; } We may also want an option to tell the slave to ignore "affected" mismatch. This mismatch could be implemented with a new ER_ code, and @@ -2215,7 +2215,7 @@ end: thd->first_successful_insert_id_in_prev_stmt= 0; thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); - return thd->query_error; + return thd->is_slave_error; } int Query_log_event::do_update_pos(Relay_log_info *rli) @@ -3255,7 +3255,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, thd->set_db(new_db.str, new_db.length); DBUG_ASSERT(thd->query == 0); thd->query_length= 0; // Should not be needed - thd->query_error= 0; + thd->is_slave_error= 0; clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* see Query_log_event::do_apply_event() and BUG#13360 */ @@ -3429,7 +3429,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, List<Item> tmp_list; if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list, handle_dup, ignore, net != 0)) - thd->query_error= 1; + thd->is_slave_error= 1; if (thd->cuted_fields) { /* log_pos is the position of the LOAD event in the master log */ @@ -3468,9 +3468,9 @@ error: close_thread_tables(thd); DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", - thd->query_error= 0; thd->is_fatal_error= 1;); + thd->is_slave_error= 0; thd->is_fatal_error= 1;); - if (thd->query_error) + if (thd->is_slave_error) { /* this err/sql_errno code is copy-paste from net_send_error() */ const char *err; @@ -5655,7 +5655,7 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, m_width(tbl_arg ? tbl_arg->s->fields : 1), m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0) #ifdef HAVE_REPLICATION - ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) + , m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL) #endif { /* @@ -5703,7 +5703,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, #endif m_table_id(0), m_rows_buf(0), m_rows_cur(0), m_rows_end(0) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) + , m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL) #endif { DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)"); @@ -5951,7 +5951,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) { if (!need_reopen) { - if (thd->query_error || thd->is_fatal_error) + if (thd->is_slave_error || thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -5995,7 +5995,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) uint tables_count= rli->tables_to_lock_count; if ((error= open_tables(thd, &tables, &tables_count, 0))) { - if (thd->query_error || thd->is_fatal_error) + if (thd->is_slave_error || thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -6006,7 +6006,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) "Error '%s' on reopening tables", (actual_error ? thd->net.last_error : "unexpected success or fatal error")); - thd->query_error= 1; + thd->is_slave_error= 1; } const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(error); @@ -6029,7 +6029,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) { mysql_unlock_tables(thd, thd->lock); thd->lock= 0; - thd->query_error= 1; + thd->is_slave_error= 1; const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(ERR_BAD_TABLE_DEF); } @@ -6159,7 +6159,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) "Error in %s event: row application failed. %s", get_type_str(), thd->net.last_error ? thd->net.last_error : ""); - thd->query_error= 1; + thd->is_slave_error= 1; break; } @@ -6221,7 +6221,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ thd->reset_current_stmt_binlog_row_based(); const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); - thd->query_error= 1; + thd->is_slave_error= 1; DBUG_RETURN(error); } @@ -6519,9 +6519,15 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, m_dblen(m_dbnam ? tbl->s->db.length : 0), m_tblnam(tbl->s->table_name.str), m_tbllen(tbl->s->table_name.length), - m_colcnt(tbl->s->fields), m_field_metadata(0), - m_field_metadata_size(0), m_memory(NULL), m_meta_memory(NULL), m_data_size(0), - m_table_id(tid), m_null_bits(0), m_flags(flags) + m_colcnt(tbl->s->fields), + m_memory(NULL), + m_table_id(tid), + m_flags(flags), + m_data_size(0), + m_field_metadata(0), + m_field_metadata_size(0), + m_null_bits(0), + m_meta_memory(NULL) { DBUG_ASSERT(m_table_id != ~0UL); /* @@ -6798,7 +6804,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) TABLE_LIST *tmp_table_list= table_list; if ((error= open_tables(thd, &tmp_table_list, &count, 0))) { - if (thd->query_error || thd->is_fatal_error) + if (thd->is_slave_error || thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -6810,7 +6816,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) (actual_error ? thd->net.last_error : "unexpected success or fatal error"), table_list->db, table_list->table_name); - thd->query_error= 1; + thd->is_slave_error= 1; } goto err; } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 949179386ea..c6b691ec010 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -68,7 +68,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli { if (!need_reopen) { - if (thd->query_error || thd->is_fatal_error) + if (thd->is_slave_error || thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -112,7 +112,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli uint tables_count= rli->tables_to_lock_count; if ((error= open_tables(thd, &tables, &tables_count, 0))) { - if (thd->query_error || thd->is_fatal_error) + if (thd->is_slave_error || thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -123,7 +123,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli "Error '%s' on reopening tables", (actual_error ? thd->net.last_error : "unexpected success or fatal error")); - thd->query_error= 1; + thd->is_slave_error= 1; } const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(error); @@ -146,7 +146,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli { mysql_unlock_tables(thd, thd->lock); thd->lock= 0; - thd->query_error= 1; + thd->is_slave_error= 1; const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); DBUG_RETURN(Rows_log_event::ERR_BAD_TABLE_DEF); } @@ -255,7 +255,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli "Error in %s event: row application failed. %s", ev->get_type_str(), thd->net.last_error ? thd->net.last_error : ""); - thd->query_error= 1; + thd->is_slave_error= 1; break; } @@ -300,7 +300,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli */ thd->reset_current_stmt_binlog_row_based(); const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); - thd->query_error= 1; + thd->is_slave_error= 1; DBUG_RETURN(error); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d83df03de82..0a649e59ce6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -695,7 +695,7 @@ extern my_decimal decimal_zero; void free_items(Item *item); void cleanup_items(Item *item); class THD; -void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0); +void close_thread_tables(THD *thd); bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *tables, bool no_errors); @@ -936,7 +936,6 @@ bool init_new_connection_handler_thread(); void reset_mqh(LEX_USER *lu, bool get_them); bool check_mqh(THD *thd, uint check_command); void time_out_user_resource_limits(THD *thd, USER_CONN *uc); -int check_for_max_user_connections(THD *thd, USER_CONN *uc); void decrease_user_connections(USER_CONN *uc); void thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); @@ -1436,7 +1435,7 @@ TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, bool check_alias); TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name); TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list); -bool close_temporary_table(THD *thd, TABLE_LIST *table_list); +int drop_temporary_table(THD *thd, TABLE_LIST *table_list); void close_temporary_table(THD *thd, TABLE *table, bool free_share, bool delete_table); void close_temporary(TABLE *table, bool free_share, bool delete_table); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a490c63fa79..0f38c45729e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2584,7 +2584,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) TODO: There are two exceptions mechanism (THD and sp_rcontext), this could be improved by having a common stack of handlers. */ - if (thd->handle_error(error, + if (thd->handle_error(error, str, MYSQL_ERROR::WARN_LEVEL_ERROR)) DBUG_RETURN(0); @@ -2594,7 +2594,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) DBUG_RETURN(0); } - thd->query_error= 1; // needed to catch query errors during replication + thd->is_slave_error= 1; // needed to catch query errors during replication if (!thd->no_warnings_for_error) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); @@ -4303,6 +4303,7 @@ void create_thread_to_handle_connection(THD *thd) } else { + char error_message_buff[MYSQL_ERRMSG_SIZE]; /* Create new thread to handle connection */ int error; thread_created++; @@ -4321,7 +4322,10 @@ void create_thread_to_handle_connection(THD *thd) thd->killed= THD::KILL_CONNECTION; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); statistic_increment(aborted_connects,&LOCK_status); - net_printf_error(thd, ER_CANT_CREATE_THREAD, error); + /* Can't use my_error() since store_globals has not been called. */ + my_snprintf(error_message_buff, sizeof(error_message_buff), + ER(ER_CANT_CREATE_THREAD), error); + net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff); (void) pthread_mutex_lock(&LOCK_thread_count); close_connection(thd,0,0); delete thd; diff --git a/sql/protocol.cc b/sql/protocol.cc index 838d9e373b3..bf8faec006a 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -58,7 +58,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) Design note: - net_printf_error and net_send_error are low-level functions + net_send_error is a low-level functions that shall be used only when a new connection is being established or at server startup. For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's @@ -84,7 +84,7 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) DBUG_VOID_RETURN; } - thd->query_error= 1; // needed to catch query errors during replication + thd->is_slave_error= 1; // needed to catch query errors during replication if (!err) { if (sql_errno) @@ -120,124 +120,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) DBUG_VOID_RETURN; } -/* - Write error package and flush to client - It's a little too low level, but I don't want to use another buffer for - this - - Design note: - - net_printf_error and net_send_error are low-level functions - that shall be used only when a new connection is being - established or at server startup. - For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's - critical that every error that can be intercepted is issued in one - place only, my_message_sql. -*/ - -void -net_printf_error(THD *thd, uint errcode, ...) -{ - va_list args; - uint length,offset; - const char *format; -#ifndef EMBEDDED_LIBRARY - const char *text_pos; - int head_length= NET_HEADER_SIZE; -#else - char text_pos[1024]; -#endif - NET *net= &thd->net; - - DBUG_ENTER("net_printf_error"); - DBUG_PRINT("enter",("message: %u",errcode)); - - DBUG_ASSERT(!thd->spcont); - - if (net && net->no_send_error) - { - thd->clear_error(); - thd->is_fatal_error= 0; // Error message is given - DBUG_PRINT("info", ("sending error messages prohibited")); - DBUG_VOID_RETURN; - } - - thd->query_error= 1; // needed to catch query errors during replication -#ifndef EMBEDDED_LIBRARY - query_cache_abort(net); // Safety -#endif - va_start(args,errcode); - /* - The following is needed to make net_printf_error() work with 0 argument - for errorcode and use the argument after that as the format string. This - is useful for rare errors that are not worth the hassle to put in - errmsg.sys, but at the same time, the message is not fixed text - */ - if (errcode) - format= ER(errcode); - else - { - format=va_arg(args,char*); - errcode= ER_UNKNOWN_ERROR; - } - offset= (net->return_errno ? - ((thd->client_capabilities & CLIENT_PROTOCOL_41) ? - 2+SQLSTATE_LENGTH+1 : 2) : 0); -#ifndef EMBEDDED_LIBRARY - text_pos=(char*) net->buff + head_length + offset + 1; - length= (uint) ((char*)net->buff_end - text_pos); -#else - length=sizeof(text_pos)-1; -#endif - length=my_vsnprintf(my_const_cast(char*) (text_pos), - min(length, sizeof(net->last_error)), - format,args); - va_end(args); - - /* Replication slave relies on net->last_* to see if there was error */ - net->last_errno= errcode; - strmake(net->last_error, text_pos, sizeof(net->last_error)-1); - -#ifndef EMBEDDED_LIBRARY - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* - In bootstrap it's ok to print on stderr - This may also happen when we get an error from a slave thread - */ - fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); - thd->fatal_error(); - } - DBUG_VOID_RETURN; - } - - int3store(net->buff,length+1+offset); - net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); - net->buff[head_length]=(uchar) 255; // Error package - if (offset) - { - uchar *pos= net->buff+head_length+1; - int2store(pos, errcode); - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - pos[2]= '#'; /* To make the protocol backward compatible */ - memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH); - } - } - VOID(net_real_write(net, net->buff, length+head_length+1+offset)); -#else - net->last_errno= errcode; - strmake(net->last_error, text_pos, length); - strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH); -#endif - if (thd->killed != THD::KILL_CONNECTION) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, errcode, - text_pos ? text_pos : ER(errcode)); - thd->is_fatal_error=0; // Error message is given - DBUG_VOID_RETURN; -} /* Return ok to the client. diff --git a/sql/protocol.h b/sql/protocol.h index 46a2b6d36b6..53584326f03 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -172,7 +172,6 @@ public: }; void send_warning(THD *thd, uint sql_errno, const char *err=0); -void net_printf_error(THD *thd, uint sql_errno, ...); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); diff --git a/sql/set_var.cc b/sql/set_var.cc index 5564a58ce5d..c40f978526f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3059,7 +3059,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list) if ((error= var->check(thd))) goto err; } - if (!(error= test(thd->net.report_error))) + if (!(error= test(thd->is_error()))) { it.rewind(); while ((var= it++)) diff --git a/sql/slave.cc b/sql/slave.cc index 1c87f3122d1..675715da541 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -980,7 +980,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, DBUG_RETURN(1); } thd->query= query; - thd->query_error = 0; + thd->is_slave_error = 0; thd->net.no_send_ok = 1; bzero((char*) &tables,sizeof(tables)); @@ -1009,7 +1009,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, thd->db_length= save_db_length; thd->options = save_options; - if (thd->query_error) + if (thd->is_slave_error) goto err; // mysql_parse took care of the error send thd_proc_info(thd, "Opening master dump table"); @@ -2353,7 +2353,7 @@ err: change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE); DBUG_ASSERT(thd->net.buff != 0); net_end(&thd->net); // destructor will not free it, because net.vio is 0 - close_thread_tables(thd, 0); + close_thread_tables(thd); pthread_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); delete thd; @@ -2501,7 +2501,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, if (sys_init_slave.value_length) { execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave); - if (thd->query_error) + if (thd->is_slave_error) { sql_print_error("\ Slave SQL thread aborted. Can't execute init_slave query"); diff --git a/sql/sp.cc b/sql/sp.cc index 1b5d8ca87b8..b4f0ec7729b 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1866,7 +1866,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, an error with it's return value without calling my_error(), we set the generic "mysql.proc table corrupt" error here. */ - if (!thd->net.report_error) + if (! thd->is_error()) { /* SP allows full NAME_LEN chars thus he have to allocate enough diff --git a/sql/sp_head.cc b/sql/sp_head.cc index bf102c1cb13..09ae572152f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -370,7 +370,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) thd->abort_on_warning= save_abort_on_warning; thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table; - if (thd->net.report_error) + if (thd->is_error()) { /* Return error status if something went wrong. */ err_status= TRUE; @@ -1108,7 +1108,7 @@ sp_head::execute(THD *thd) if ((ctx= thd->spcont)) ctx->clear_handler(); - thd->query_error= 0; + thd->is_slave_error= 0; old_arena= thd->stmt_arena; /* @@ -1275,9 +1275,9 @@ sp_head::execute(THD *thd) state= EXECUTED; done: - DBUG_PRINT("info", ("err_status: %d killed: %d query_error: %d report_error: %d", - err_status, thd->killed, thd->query_error, - thd->net.report_error)); + DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d", + err_status, thd->killed, thd->is_slave_error, + thd->is_error())); if (thd->killed) err_status= TRUE; @@ -1872,7 +1872,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) we'll leave it here. */ if (!thd->in_sub_stmt) - close_thread_tables(thd, 0, 0); + close_thread_tables(thd); DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, m_name.str)); @@ -2673,7 +2673,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, cleanup_items() is called in sp_head::execute() */ - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(res || thd->is_error()); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0c8c4b8c2d8..070a943da9e 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -428,7 +428,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) continue; } - const char *password= get_field(&mem, table->field[2]); + const char *password= get_field(thd->mem_root, table->field[2]); uint password_len= password ? strlen(password) : 0; set_user_salt(&user, password, password_len); if (user.salt_len == 0 && password_len != 0) @@ -495,7 +495,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) /* Starting from 4.0.2 we have more fields */ if (table->s->fields >= 31) { - char *ssl_type=get_field(&mem, table->field[next_field++]); + char *ssl_type=get_field(thd->mem_root, table->field[next_field++]); if (!ssl_type) user.ssl_type=SSL_TYPE_NONE; else if (!strcmp(ssl_type, "ANY")) @@ -509,11 +509,11 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) user.x509_issuer= get_field(&mem, table->field[next_field++]); user.x509_subject= get_field(&mem, table->field[next_field++]); - char *ptr = get_field(&mem, table->field[next_field++]); + char *ptr = get_field(thd->mem_root, table->field[next_field++]); user.user_resource.questions=ptr ? atoi(ptr) : 0; - ptr = get_field(&mem, table->field[next_field++]); + ptr = get_field(thd->mem_root, table->field[next_field++]); user.user_resource.updates=ptr ? atoi(ptr) : 0; - ptr = get_field(&mem, table->field[next_field++]); + ptr = get_field(thd->mem_root, table->field[next_field++]); user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0; if (user.user_resource.questions || user.user_resource.updates || user.user_resource.conn_per_hour) @@ -522,7 +522,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) if (table->s->fields >= 36) { /* Starting from 5.0.3 we have max_user_connections field */ - ptr= get_field(&mem, table->field[next_field++]); + ptr= get_field(thd->mem_root, table->field[next_field++]); user.user_resource.user_conn= ptr ? atoi(ptr) : 0; } else @@ -5050,6 +5050,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop, uchar user_key[MAX_KEY_LENGTH]; uint key_prefix_length; DBUG_ENTER("handle_grant_table"); + THD *thd= current_thd; table->use_all_columns(); if (! table_no) // mysql.user table @@ -5118,17 +5119,18 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop, DBUG_PRINT("info",("scan error: %d", error)); continue; } - if (! (host= get_field(&mem, host_field))) + if (! (host= get_field(thd->mem_root, host_field))) host= ""; - if (! (user= get_field(&mem, user_field))) + if (! (user= get_field(thd->mem_root, user_field))) user= ""; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'", user, host, - get_field(&mem, table->field[1]) /*db*/, - get_field(&mem, table->field[3]) /*table*/, - get_field(&mem, table->field[4]) /*column*/)); + get_field(thd->mem_root, table->field[1]) /*db*/, + get_field(thd->mem_root, table->field[3]) /*table*/, + get_field(thd->mem_root, + table->field[4]) /*column*/)); #endif if (strcmp(user_str, user) || my_strcasecmp(system_charset_info, host_str, host)) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c4c860c48f4..ed0ddbbd15d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -44,7 +44,7 @@ public: virtual ~Prelock_error_handler() {} - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd); @@ -58,6 +58,7 @@ private: bool Prelock_error_handler::handle_error(uint sql_errno, + const char * /* message */, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { @@ -1054,6 +1055,29 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, } +/** + Mark all temporary tables which were used by the current statement or + substatement as free for reuse, but only if the query_id can be cleared. + + @param thd thread context + + @remark For temp tables associated with a open SQL HANDLER the query_id + is not reset until the HANDLER is closed. +*/ + +static void mark_temp_tables_as_free_for_reuse(THD *thd) +{ + for (TABLE *table= thd->temporary_tables ; table ; table= table->next) + { + if ((table->query_id == thd->query_id) && ! table->open_by_handler) + { + table->query_id= 0; + table->file->ha_reset(); + } + } +} + + /* Mark all tables in the list which were used by current substatement as free for reuse. @@ -1090,6 +1114,42 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) } +/** + Auxiliary function to close all tables in the open_tables list. + + @param thd Thread context. + + @remark It should not ordinarily be called directly. +*/ + +static void close_open_tables(THD *thd) +{ + bool found_old_table= 0; + + safe_mutex_assert_not_owner(&LOCK_open); + + VOID(pthread_mutex_lock(&LOCK_open)); + + DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); + + while (thd->open_tables) + found_old_table|= close_thread_table(thd, &thd->open_tables); + thd->some_tables_deleted= 0; + + /* Free tables to hold down open files */ + while (open_cache.records > table_cache_size && unused_tables) + VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */ + check_unused(); + if (found_old_table) + { + /* Tell threads waiting for refresh that something has happened */ + broadcast_refresh(); + } + + VOID(pthread_mutex_unlock(&LOCK_open)); +} + + /* Close all tables used by the current substatement, or all tables used by this thread if we are on the upper level. @@ -1097,26 +1157,19 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) SYNOPSIS close_thread_tables() thd Thread handler - lock_in_use Set to 1 (0 = default) if caller has a lock on - LOCK_open - skip_derived Set to 1 (0 = default) if we should not free derived - tables. - stopper When closing tables from thd->open_tables(->next)*, - don't close/remove tables starting from stopper. IMPLEMENTATION Unlocks tables and frees derived tables. Put all normal tables used by thread in free list. - When in prelocked mode it will only close/mark as free for reuse - tables opened by this substatement, it will also check if we are - closing tables after execution of complete query (i.e. we are on - upper level) and will leave prelocked mode if needed. + It will only close/mark as free for reuse tables opened by this + substatement, it will also check if we are closing tables after + execution of complete query (i.e. we are on upper level) and will + leave prelocked mode if needed. */ -void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) +void close_thread_tables(THD *thd) { - bool found_old_table; prelocked_mode_type prelocked_mode= thd->prelocked_mode; DBUG_ENTER("close_thread_tables"); @@ -1131,7 +1184,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) derived tables with (sub-)statement instead of thread and destroy them at the end of its execution. */ - if (thd->derived_tables && !skip_derived) + if (thd->derived_tables) { TABLE *table, *next; /* @@ -1146,13 +1199,10 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) thd->derived_tables= 0; } - if (prelocked_mode) - { - /* - Mark all temporary tables used by this substatement as free for reuse. - */ - mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables); - } + /* + Mark all temporary tables used by this statement as free for reuse. + */ + mark_temp_tables_as_free_for_reuse(thd); if (thd->locked_tables || prelocked_mode) { @@ -1216,28 +1266,8 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) if (!thd->active_transaction()) thd->transaction.xid_state.xid.null(); - if (!lock_in_use) - VOID(pthread_mutex_lock(&LOCK_open)); - - DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); - - found_old_table= 0; - while (thd->open_tables) - found_old_table|= close_thread_table(thd, &thd->open_tables); - thd->some_tables_deleted=0; - - /* Free tables to hold down open files */ - while (open_cache.records > table_cache_size && unused_tables) - VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */ - check_unused(); - if (found_old_table) - { - /* Tell threads waiting for refresh that something has happened */ - broadcast_refresh(); - } - if (!lock_in_use) - VOID(pthread_mutex_unlock(&LOCK_open)); - /* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */ + if (thd->open_tables) + close_open_tables(thd); if (prelocked_mode == PRELOCKED) { @@ -1674,6 +1704,7 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) Try to locate the table in the list of thd->temporary_tables. If the table is found: + - if the table is being used by some outer statement, fail. - if the table is in thd->locked_tables, unlock it and remove it from the list of locked tables. Currently only transactional temporary tables are present in the locked_tables list. @@ -1688,24 +1719,34 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) thd->temporary_tables list, it's impossible to tell here whether we're dealing with an internal or a user temporary table. - @retval TRUE the table was not found in the list of temporary tables - of this thread - @retval FALSE the table was found and dropped successfully. + @retval 0 the table was found and dropped successfully. + @retval 1 the table was not found in the list of temporary tables + of this thread + @retval -1 the table is in use by a outer query */ -bool close_temporary_table(THD *thd, TABLE_LIST *table_list) +int drop_temporary_table(THD *thd, TABLE_LIST *table_list) { TABLE *table; + DBUG_ENTER("drop_temporary_table"); if (!(table= find_temporary_table(thd, table_list))) - return 1; + DBUG_RETURN(1); + + /* Table might be in use by some outer statement. */ + if (table->query_id && table->query_id != thd->query_id) + { + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + DBUG_RETURN(-1); + } + /* If LOCK TABLES list is not empty and contains this table, unlock the table and remove the table from this list. */ mysql_lock_remove(thd, thd->locked_tables, table, FALSE); close_temporary_table(thd, table, 1, 1); - return 0; + DBUG_RETURN(0); } /* @@ -2284,8 +2325,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, is always represented by only one TABLE object in THD, and it can not be cloned. Emit an error for an unsupported behaviour. */ - if (table->query_id == thd->query_id || - thd->prelocked_mode && table->query_id) + if (table->query_id) { DBUG_PRINT("error", ("query_id: %lu server_id: %u pseudo_thread_id: %lu", @@ -2295,7 +2335,6 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_RETURN(0); } table->query_id= thd->query_id; - table->clear_query_id= 1; thd->thread_specific_used= TRUE; DBUG_PRINT("info",("Using temporary table")); goto reset; @@ -4305,7 +4344,6 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables) sp_remove_not_own_routines(thd->lex); for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global) tmp->table= 0; - mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables); close_thread_tables(thd); } @@ -6260,7 +6298,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, thd->lex->allow_sum_func= save_allow_sum_func; thd->mark_used_columns= save_mark_used_columns; DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns)); - DBUG_RETURN(test(thd->net.report_error)); + DBUG_RETURN(test(thd->is_error())); } @@ -6804,7 +6842,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, select_lex->conds_processed_with_permanent_arena= 1; } thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup; - DBUG_RETURN(test(thd->net.report_error)); + DBUG_RETURN(test(thd->is_error())); err_no_arena: select_lex->is_item_list_lookup= save_is_item_list_lookup; @@ -6886,7 +6924,7 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values, goto err; } } - DBUG_RETURN(thd->net.report_error); + DBUG_RETURN(thd->is_error()); err: if (table) table->auto_increment_field_not_null= FALSE; @@ -6971,7 +7009,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors) table= (*ptr)->table; table->auto_increment_field_not_null= FALSE; } - while ((field = *ptr++) && !thd->net.report_error) + while ((field = *ptr++) && ! thd->is_error()) { value=v++; table= field->table; @@ -6980,7 +7018,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors) if (value->save_in_field(field, 0) < 0) goto err; } - DBUG_RETURN(thd->net.report_error); + DBUG_RETURN(thd->is_error()); err: if (table) @@ -7390,7 +7428,7 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, else { /* only VIEWs are supported now */ - my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path, parser->type()->str); + my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path.str, parser->type()->str); goto err; } DBUG_RETURN(0); diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index a3a804db8f0..fa6aa8f5881 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -37,6 +37,9 @@ void mysql_client_binlog_statement(THD* thd) thd->lex->comment.length : 2048), thd->lex->comment.str)); + if (check_global_access(thd, SUPER_ACL)) + DBUG_VOID_RETURN; + /* Temporarily turn off send_ok, since different events handle this differently diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6b154f8317a..b3b909b4529 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -402,7 +402,7 @@ THD::THD() count_cuted_fields= CHECK_FIELD_IGNORE; killed= NOT_KILLED; col_access=0; - query_error= thread_specific_used= FALSE; + is_slave_error= thread_specific_used= FALSE; hash_clear(&handler_tables_hash); tmp_table=0; used_tables=0; @@ -508,12 +508,12 @@ void THD::push_internal_handler(Internal_error_handler *handler) } -bool THD::handle_error(uint sql_errno, +bool THD::handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level) { if (m_internal_handler) { - return m_internal_handler->handle_error(sql_errno, level, this); + return m_internal_handler->handle_error(sql_errno, message, level, this); } return FALSE; // 'FALSE', as per coding style @@ -1315,23 +1315,26 @@ bool select_send::send_fields(List<Item> &list, uint flags) { bool res; if (!(res= thd->protocol->send_fields(&list, flags))) - status= 1; + is_result_set_started= 1; return res; } void select_send::abort() { DBUG_ENTER("select_send::abort"); - if (status && thd->spcont && + if (is_result_set_started && thd->spcont && thd->spcont->find_handler(thd, thd->net.last_errno, MYSQL_ERROR::WARN_LEVEL_ERROR)) { /* - Executing stored procedure without a handler. - Here we should actually send an error to the client, - but as an error will break a multiple result set, the only thing we - can do for now is to nicely end the current data set and remembering - the error so that the calling routine will abort + We're executing a stored procedure, have an open result + set, an SQL exception conditiona and a handler for it. + In this situation we must abort the current statement, + silence the error and start executing the continue/exit + handler. + Before aborting the statement, let's end the open result set, as + otherwise the client will hang due to the violation of the + client/server protocol. */ thd->net.report_error= 0; send_eof(); @@ -1341,6 +1344,17 @@ void select_send::abort() } +/** + Cleanup an instance of this class for re-use + at next execution of a prepared statement/ + stored procedure statement. +*/ + +void select_send::cleanup() +{ + is_result_set_started= FALSE; +} + /* Send data to client. Returns 0 if ok */ bool select_send::send_data(List<Item> &items) @@ -1378,7 +1392,7 @@ bool select_send::send_data(List<Item> &items) thd->sent_row_count++; if (!thd->vio_ok()) DBUG_RETURN(0); - if (!thd->net.report_error) + if (! thd->is_error()) DBUG_RETURN(protocol->write()); protocol->remove_last_row(); DBUG_RETURN(1); @@ -1399,10 +1413,10 @@ bool select_send::send_eof() mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - if (!thd->net.report_error) + if (! thd->is_error()) { ::send_eof(thd); - status= 0; + is_result_set_started= 0; return 0; } else @@ -2414,6 +2428,7 @@ void Security_context::init() host= user= priv_user= ip= 0; host_or_ip= "connecting host"; priv_host[0]= '\0'; + master_access= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS db_access= NO_ACCESS; #endif diff --git a/sql/sql_class.h b/sql/sql_class.h index 7babb51ca06..9d5ef2f175b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -970,6 +970,7 @@ public: @return true if the error is handled */ virtual bool handle_error(uint sql_errno, + const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd) = 0; }; @@ -1474,7 +1475,14 @@ public: /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ bool substitute_null_with_insert_id; bool in_lock_tables; - bool query_error, bootstrap, cleanup_done; + /** + True if a slave error. Causes the slave to stop. Not the same + as the statement execution error (is_error()), since + a statement may be expected to return an error, e.g. because + it returned an error on master, and this is OK on the slave. + */ + bool is_slave_error; + bool bootstrap, cleanup_done; /** is set if some thread specific value(s) used in a statement. */ bool thread_specific_used; @@ -1703,7 +1711,7 @@ public: net.last_error[0]= 0; net.last_errno= 0; net.report_error= 0; - query_error= 0; + is_slave_error= 0; DBUG_VOID_RETURN; } inline bool vio_ok() const { return net.vio != 0; } @@ -1717,6 +1725,20 @@ public: net.report_error= 1; DBUG_PRINT("error",("Fatal error set")); } + /** + TRUE if there is an error in the error stack. + + Please use this method instead of direct access to + net.report_error. + + If TRUE, the current (sub)-statement should be aborted. + The main difference between this member and is_fatal_error + is that a fatal error can not be handled by a stored + procedure continue handler, whereas a normal error can. + + To raise this flag, use my_error(). + */ + inline bool is_error() const { return net.report_error; } inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); @@ -1910,7 +1932,7 @@ public: @param level the error level @return true if the error is handled */ - virtual bool handle_error(uint sql_errno, + virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level); /** @@ -2037,14 +2059,20 @@ public: class select_send :public select_result { - int status; + /** + True if we have sent result set metadata to the client. + In this case the client always expects us to end the result + set with an eof or error packet + */ + bool is_result_set_started; public: - select_send() :status(0) {} + select_send() :is_result_set_started(FALSE) {} bool send_fields(List<Item> &list, uint flags); bool send_data(List<Item> &items); bool send_eof(); virtual bool check_simple_select() const { return FALSE; } void abort(); + virtual void cleanup(); }; diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 094bef9324e..68872f85cd4 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -87,7 +87,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, my_malloc(sizeof(struct user_conn) + temp_len+1, MYF(MY_WME))))) { - net_send_error(thd, 0, NullS); // Out of memory + /* MY_WME ensures an error is set in THD. */ return_val= 1; goto end; } @@ -100,8 +100,8 @@ static int get_or_create_user_conn(THD *thd, const char *user, uc->reset_utime= thd->thr_create_utime; if (my_hash_insert(&hash_user_connections, (uchar*) uc)) { + /* The only possible error is out of memory, MY_WME sets an error. */ my_free((char*) uc,0); - net_send_error(thd, 0, NullS); // Out of memory return_val= 1; goto end; } @@ -132,6 +132,7 @@ end: 1 error */ +static int check_for_max_user_connections(THD *thd, USER_CONN *uc) { int error=0; @@ -141,7 +142,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) if (max_user_connections && !uc->user_resources.user_conn && max_user_connections < (uint) uc->connections) { - net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user); + my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); error=1; goto end; } @@ -149,24 +150,24 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) if (uc->user_resources.user_conn && uc->user_resources.user_conn < uc->connections) { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_user_connections", - (long) uc->user_resources.user_conn); + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, + "max_user_connections", + (long) uc->user_resources.user_conn); error= 1; goto end; } if (uc->user_resources.conn_per_hour && uc->user_resources.conn_per_hour <= uc->conn_per_hour) { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_connections_per_hour", - (long) uc->user_resources.conn_per_hour); + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, + "max_connections_per_hour", + (long) uc->user_resources.conn_per_hour); error=1; goto end; } uc->conn_per_hour++; - end: +end: if (error) uc->connections--; // no need for decrease_user_connections() here (void) pthread_mutex_unlock(&LOCK_user_conn); @@ -258,8 +259,8 @@ bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.questions && uc->questions++ >= uc->user_resources.questions) { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", - (long) uc->user_resources.questions); + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions", + (long) uc->user_resources.questions); error=1; goto end; } @@ -270,8 +271,8 @@ bool check_mqh(THD *thd, uint check_command) (sql_command_flags[check_command] & CF_CHANGES_DATA) && uc->updates++ >= uc->user_resources.updates) { - net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", - (long) uc->user_resources.updates); + my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates", + (long) uc->user_resources.updates); error=1; goto end; } @@ -284,55 +285,54 @@ end: #endif /* NO_EMBEDDED_ACCESS_CHECKS */ -/* - Check if user exist and password supplied is correct. - - SYNOPSIS - check_user() - thd thread handle, thd->security_ctx->{host,user,ip} are used - command originator of the check: now check_user is called - during connect and change user procedures; used for - logging. - passwd scrambled password received from client - passwd_len length of scrambled password - db database name to connect to, may be NULL - check_count dont know exactly - - Note, that host, user and passwd may point to communication buffer. - Current implementation does not depend on that, but future changes - should be done with this in mind; 'thd' is INOUT, all other params - are 'IN'. - - RETURN VALUE - 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and - thd->db are updated; OK is sent to client; - -1 access denied or handshake error; error is sent to client; - >0 error, not sent to client +/** + Check if user exist and password supplied is correct. + + @param thd thread handle, thd->security_ctx->{host,user,ip} are used + @param command originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + @param passwd scrambled password received from client + @param passwd_len length of scrambled password + @param db database name to connect to, may be NULL + @param check_count TRUE if establishing a new connection. In this case + check that we have not exceeded the global + max_connections limist + + @note Host, user and passwd may point to communication buffer. + Current implementation does not depend on that, but future changes + should be done with this in mind; 'thd' is INOUT, all other params + are 'IN'. + + @retval 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and + thd->db are updated; OK is sent to the client. + @retval 1 error, e.g. access denied or handshake error, not sent to + the client. A message is pushed into the error stack. */ -int check_user(THD *thd, enum enum_server_command command, +int +check_user(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count) { DBUG_ENTER("check_user"); LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 }; - + + /* + Clear thd->db as it points to something, that will be freed when + connection is closed. We don't want to accidentally free a wrong + pointer if connect failed. Also in case of 'CHANGE USER' failure, + current database will be switched to 'no database selected'. + */ + thd->reset_db(NULL, 0); + #ifdef NO_EMBEDDED_ACCESS_CHECKS thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ if (db && db[0]) { - /* - thd->db is saved in caller and needs to be freed by caller if this - function returns 0 - */ - thd->reset_db(NULL, 0); if (mysql_change_db(thd, &db_str, FALSE)) - { - /* Send the error to the client */ - net_send_error(thd); - DBUG_RETURN(-1); - } + DBUG_RETURN(1); } send_ok(thd); DBUG_RETURN(0); @@ -349,22 +349,17 @@ int check_user(THD *thd, enum enum_server_command command, */ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0)); general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); + DBUG_RETURN(1); } if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH && passwd_len != SCRAMBLE_LENGTH_323) - DBUG_RETURN(ER_HANDSHAKE_ERROR); - - /* - Clear thd->db as it points to something, that will be freed when - connection is closed. We don't want to accidentally free a wrong pointer - if connect failed. Also in case of 'CHANGE USER' failure, current - database will be switched to 'no database selected'. - */ - thd->reset_db(NULL, 0); + { + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + DBUG_RETURN(1); + } USER_RESOURCES ur; int res= acl_getroot(thd, &ur, passwd, passwd_len); @@ -380,20 +375,21 @@ int check_user(THD *thd, enum enum_server_command command, NET *net= &thd->net; if (opt_secure_auth_local) { - net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip); + my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), thd->main_security_ctx.user, thd->main_security_ctx.host_or_ip); - DBUG_RETURN(-1); + DBUG_RETURN(1); } /* We have to read very specific packet size */ if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) { inc_host_errors(&thd->remote.sin_addr); - DBUG_RETURN(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + DBUG_RETURN(1); } /* Final attempt to check the user based on reply */ /* So as passwd is short, errcode is always >= 0 */ @@ -427,8 +423,8 @@ int check_user(THD *thd, enum enum_server_command command, VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (!count_ok) { // too many connections - net_send_error(thd, ER_CON_COUNT_ERROR); - DBUG_RETURN(-1); + my_error(ER_CON_COUNT_ERROR, MYF(0)); + DBUG_RETURN(1); } } @@ -462,24 +458,29 @@ int check_user(THD *thd, enum enum_server_command command, (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : thd->main_security_ctx.priv_host), &ur)) - DBUG_RETURN(-1); + { + /* The error is set by get_or_create_user_conn(). */ + DBUG_RETURN(1); + } if (thd->user_connect && (thd->user_connect->user_resources.conn_per_hour || thd->user_connect->user_resources.user_conn || max_user_connections) && check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(-1); + { + /* The error is set in check_for_max_user_connections(). */ + DBUG_RETURN(1); + } /* Change database if necessary */ if (db && db[0]) { if (mysql_change_db(thd, &db_str, FALSE)) { - /* Send error to the client */ - net_send_error(thd); + /* mysql_change_db() has pushed the error message. */ if (thd->user_connect) decrease_user_connections(thd->user_connect); - DBUG_RETURN(-1); + DBUG_RETURN(1); } } send_ok(thd); @@ -490,19 +491,19 @@ int check_user(THD *thd, enum enum_server_command command, } else if (res == 2) // client gave short hash, server has long hash { - net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE); + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0)); general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); - DBUG_RETURN(-1); + DBUG_RETURN(1); } - net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - thd->main_security_ctx.user, - thd->main_security_ctx.host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); + my_error(ER_ACCESS_DENIED_ERROR, MYF(0), + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), thd->main_security_ctx.user, thd->main_security_ctx.host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); - DBUG_RETURN(-1); + DBUG_RETURN(1); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ } @@ -666,9 +667,12 @@ static int check_connection(THD *thd) char ip[30]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) - return (ER_BAD_HOST_ERROR); - if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) - return (ER_OUT_OF_RESOURCES); + { + my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; + } + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME)))) + return 1; /* The error is set by my_strdup(). */ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; vio_in_addr(net->vio,&thd->remote.sin_addr); if (!(specialflag & SPECIAL_NO_RESOLVE)) @@ -685,7 +689,10 @@ static int check_connection(THD *thd) thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; } if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); + { + my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; + } } DBUG_PRINT("info",("Host: %s ip: %s", (thd->main_security_ctx.host ? @@ -693,7 +700,11 @@ static int check_connection(THD *thd) (thd->main_security_ctx.ip ? thd->main_security_ctx.ip : "unknown ip"))); if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) - return(ER_HOST_NOT_PRIVILEGED); + { + my_error(ER_HOST_NOT_PRIVILEGED, MYF(0), + thd->main_security_ctx.host_or_ip); + return 1; + } } else /* Hostname given means that the connection was on a socket */ { @@ -753,7 +764,9 @@ static int check_connection(THD *thd) pkt_len < MIN_HANDSHAKE_SIZE) { inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), + thd->main_security_ctx.host_or_ip); + return 1; } } #ifdef _CUSTOMCONFIG_ @@ -762,7 +775,7 @@ static int check_connection(THD *thd) if (connect_errors) reset_host_errors(&thd->remote.sin_addr); if (thd->packet.alloc(thd->variables.net_buffer_length)) - return(ER_OUT_OF_RESOURCES); + return 1; /* The error is set by alloc(). */ thd->client_capabilities=uint2korr(net->read_pos); if (thd->client_capabilities & CLIENT_PROTOCOL_41) @@ -790,14 +803,16 @@ static int check_connection(THD *thd) if (!ssl_acceptor_fd) { inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; } DBUG_PRINT("info", ("IO layer change in progress...")); if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) { DBUG_PRINT("error", ("Failed to accept new SSL connection")); inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; } DBUG_PRINT("info", ("Reading user information over SSL layer")); if ((pkt_len= my_net_read(net)) == packet_error || @@ -806,7 +821,8 @@ static int check_connection(THD *thd) DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", pkt_len)); inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; } } #endif /* HAVE_OPENSSL */ @@ -814,7 +830,8 @@ static int check_connection(THD *thd) if (end >= (char*) net->read_pos+ pkt_len +2) { inc_host_errors(&thd->remote.sin_addr); - return(ER_HANDSHAKE_ERROR); + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; } if (thd->client_capabilities & CLIENT_INTERACTIVE) @@ -851,7 +868,8 @@ static int check_connection(THD *thd) if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len) { inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip); + return 1; } /* Since 4.1 all database names are stored in utf8 */ @@ -879,8 +897,8 @@ static int check_connection(THD *thd) if (thd->main_security_ctx.user) x_free(thd->main_security_ctx.user); - if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) - return (ER_OUT_OF_RESOURCES); + if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME)))) + return 1; /* The error is set by my_strdup(). */ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); } @@ -929,9 +947,7 @@ bool setup_connection_thread_globals(THD *thd) bool login_connection(THD *thd) { - int error; NET *net= &thd->net; - Security_context *sctx= thd->security_ctx; DBUG_ENTER("login_connection"); DBUG_PRINT("info", ("login_connection called by thread %lu", thd->thread_id)); @@ -942,10 +958,9 @@ bool login_connection(THD *thd) my_net_set_read_timeout(net, connect_timeout); my_net_set_write_timeout(net, connect_timeout); - if ((error=check_connection(thd))) + if (check_connection(thd)) { // Wrong permissions - if (error > 0) - net_printf_error(thd, error, sctx->host_or_ip); + net_send_error(thd); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) my_sleep(1000); /* must wait after eof() */ @@ -975,12 +990,12 @@ void end_connection(THD *thd) decrease_user_connections(thd->user_connect); if (thd->killed || - net->error && net->vio != 0 && net->report_error) + net->error && net->vio != 0 && thd->is_error()) { statistic_increment(aborted_threads,&LOCK_status); } - if (net->error && net->vio != 0 && net->report_error) + if (net->error && net->vio != 0 && thd->is_error()) { if (!thd->killed && thd->variables.log_warnings > 1) { @@ -1030,7 +1045,17 @@ static void prepare_new_connection_state(THD* thd) if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) { execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); - if (thd->query_error) + /* + execute_init_command calls net_send_error. + If there was an error during execution of the init statements, + the error at this moment is present in thd->net.last_error and also + thd->is_slave_error and thd->net.report_error are set. + net_send_error sends the contents of thd->net.last_error and + clears thd->net.report_error. It doesn't, however, clean + thd->is_slave_error or thd->net.last_error. Here we make use of this + fact. + */ + if (thd->is_slave_error) { thd->killed= THD::KILL_CONNECTION; sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e4b005e74f9..f7155341675 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, READ_RECORD info; bool using_limit=limit != HA_POS_ERROR; bool transactional_table, safe_update, const_cond; + bool const_cond_result; ha_rows deleted= 0; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; @@ -86,6 +87,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, select_lex->no_error= thd->lex->ignore; + const_cond_result= const_cond && (!conds || conds->val_int()); + if (thd->is_error()) + { + /* Error evaluating val_int(). */ + DBUG_RETURN(TRUE); + } /* Test if the user wants to delete all rows and deletion doesn't have any side-effects (because of triggers), so we can use optimized @@ -105,7 +112,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - We should not be binlogging this statement row-based, and - there should be no delete triggers associated with the table. */ - if (!using_limit && const_cond && (!conds || conds->val_int()) && + if (!using_limit && const_cond_result && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && (thd->lex->sql_command == SQLCOM_TRUNCATE || (!thd->current_stmt_binlog_row_based && @@ -252,10 +259,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->mark_columns_needed_for_delete(); while (!(error=info.read_record(&info)) && !thd->killed && - !thd->net.report_error) + ! thd->is_error()) { - // thd->net.report_error is tested to disallow delete row on error - if (!(select && select->skip_record())&& !thd->net.report_error ) + // thd->is_error() is tested to disallow delete row on error + if (!(select && select->skip_record())&& ! thd->is_error() ) { if (table->triggers && @@ -300,7 +307,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } - if (thd->killed && !error) + if (thd->killed || thd->is_error()) error= 1; // Aborted if (will_batch && (loc_error= table->file->end_bulk_delete())) { @@ -389,7 +396,7 @@ cleanup: send_ok(thd, (ha_rows) thd->row_count_func); DBUG_PRINT("info",("%ld records deleted",(long) deleted)); } - DBUG_RETURN(error >= 0 || thd->net.report_error); + DBUG_RETURN(error >= 0 || thd->is_error()); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 8bdb2e59ed5..89cff73d153 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -137,7 +137,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, level= MYSQL_ERROR::WARN_LEVEL_ERROR; } - if (thd->handle_error(code, level)) + if (thd->handle_error(code, msg, level)) DBUG_RETURN(NULL); if (thd->spcont && diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index ed7e30c1fef..19a99f9d12b 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -151,6 +151,14 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) } VOID(pthread_mutex_unlock(&LOCK_open)); } + else if (tables->table) + { + /* Must be a temporary table */ + TABLE *table= tables->table; + table->file->ha_index_or_rnd_end(); + table->query_id= thd->query_id; + table->open_by_handler= 0; + } } /* @@ -282,6 +290,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) goto err; } + /* + If it's a temp table, don't reset table->query_id as the table is + being used by this handler. Otherwise, no meaning at all. + */ + tables->table->open_by_handler= 1; + if (! reopen) send_ok(thd); DBUG_PRINT("exit",("OK")); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1ce96769061..4c51d3317ec 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -738,7 +738,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->triggers, TRG_EVENT_INSERT)) { - if (values_list.elements != 1 && !thd->net.report_error) + if (values_list.elements != 1 && ! thd->is_error()) { info.records++; continue; @@ -769,7 +769,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->triggers, TRG_EVENT_INSERT)) { - if (values_list.elements != 1 && ! thd->net.report_error) + if (values_list.elements != 1 && ! thd->is_error()) { info.records++; continue; @@ -1909,7 +1909,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) thd_proc_info(thd, "got old table"); if (di->thd.killed) { - if (di->thd.net.report_error) + if (di->thd.is_error()) { /* Copy the error message. Note that we don't treat fatal @@ -1940,7 +1940,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) pthread_mutex_unlock(&di->mutex); if (table_list->table) { - DBUG_ASSERT(thd->net.report_error == 0); + DBUG_ASSERT(! thd->is_error()); thd->di= di; } /* Unlock the delayed insert object after its last access. */ @@ -1949,7 +1949,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) end_create: pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(thd->net.report_error); + DBUG_RETURN(thd->is_error()); } @@ -3015,7 +3015,7 @@ bool select_insert::send_data(List<Item> &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); thd->count_cuted_fields= CHECK_FIELD_IGNORE; - if (thd->net.report_error) + if (thd->is_error()) DBUG_RETURN(1); if (table_list) // Not CREATE ... SELECT { @@ -3399,7 +3399,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, it preparable for open. But let us do close_temporary_table() here just in case. */ - close_temporary_table(thd, create_table); + drop_temporary_table(thd, create_table); } } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 978aec6ea07..a5727f7f70a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1623,7 +1623,7 @@ typedef struct st_lex : public Query_tables_list uint8 create_view_algorithm; uint8 create_view_check; bool drop_if_exists, drop_temporary, local_file, one_shot_set; - + bool autocommit; bool verbose, no_write_to_binlog; bool tx_chain, tx_release; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bfac7a4ffb3..53835cce7df 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -442,7 +442,7 @@ pthread_handler_t handle_bootstrap(void *arg) if (thd->is_fatal_error) break; - if (thd->net.report_error) + if (thd->is_error()) { /* The query failed, send error to log and abort bootstrap */ net_send_error(thd); @@ -934,15 +934,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Clear variables that are allocated */ thd->user_connect= 0; + thd->security_ctx->priv_user= thd->security_ctx->user; res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE); if (res) { - /* authentication failure, we shall restore old user */ - if (res > 0) - my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); - else - thd->clear_error(); // Error already sent to client x_free(thd->security_ctx->user); *thd->security_ctx= save_security_ctx; thd->user_connect= save_user_connect; @@ -956,8 +952,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (save_user_connect) decrease_user_connections(save_user_connect); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - x_free((uchar*) save_db); - x_free((uchar*) save_security_ctx.user); + x_free(save_db); + x_free(save_security_ctx.user); if (cs_number) { @@ -1016,16 +1012,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt); - while (!thd->killed && (end_of_stmt != NULL) && !thd->net.report_error) + while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error()) { char *beginning_of_next_stmt= (char*) end_of_stmt; net->no_send_error= 0; /* Multiple queries exits, execute them individually */ - if (thd->lock || thd->open_tables || thd->derived_tables || - thd->prelocked_mode) - close_thread_tables(thd); + close_thread_tables(thd); ulong length= (ulong)(packet_end - beginning_of_next_stmt); log_slow_statement(thd); @@ -1369,12 +1363,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - if (thd->lock || thd->open_tables || thd->derived_tables || - thd->prelocked_mode) - { - thd_proc_info(thd, "closing tables"); - close_thread_tables(thd); /* Free tables */ - } + + thd_proc_info(thd, "closing tables"); + /* Free tables */ + close_thread_tables(thd); + /* assume handlers auto-commit (if some doesn't - transaction handling in MySQL should be redesigned to support it; it's a big change, @@ -1388,9 +1381,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->transaction.xid_state.xid.null(); /* report error issued during command execution */ - if (thd->killed_errno() && !thd->net.report_error) + if (thd->killed_errno() && ! thd->is_error()) thd->send_kill_message(); - if (thd->net.report_error) + if (thd->is_error()) net_send_error(thd); log_slow_statement(thd); @@ -3110,6 +3103,10 @@ end_with_restore_list: case SQLCOM_SET_OPTION: { List<set_var_base> *lex_var_list= &lex->var_list; + + if (lex->autocommit && end_active_trans(thd)) + goto error; + if ((check_table_access(thd, SELECT_ACL, all_tables, 0) || open_and_lock_tables(thd, all_tables))) goto error; @@ -3987,7 +3984,7 @@ create_sp_error: thd->row_count_func)); else { - DBUG_ASSERT(thd->net.report_error == 1 || thd->killed); + DBUG_ASSERT(thd->is_error() || thd->killed); goto error; // Substatement should already have sent error } } @@ -4579,7 +4576,7 @@ finish: */ start_waiting_global_read_lock(thd); } - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(res || thd->is_error()); } @@ -5524,7 +5521,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, else #endif { - if (! thd->net.report_error) + if (! thd->is_error()) { /* Binlog logs a string starting from thd->query and having length @@ -5548,7 +5545,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, } else { - DBUG_ASSERT(thd->net.report_error); + DBUG_ASSERT(thd->is_error()); DBUG_PRINT("info",("Command aborted. Fatal_error: %d", thd->is_fatal_error)); @@ -6368,7 +6365,7 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, RETURN 0 ok - !=0 error. thd->killed or thd->net.report_error is set + !=0 error. thd->killed or thd->is_error() is set */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, @@ -7331,10 +7328,10 @@ bool parse_sql(THD *thd, bool mysql_parse_status= MYSQLparse(thd) != 0; - /* Check that if MYSQLparse() failed, thd->net.report_error is set. */ + /* Check that if MYSQLparse() failed, thd->is_error() is set. */ DBUG_ASSERT(!mysql_parse_status || - mysql_parse_status && thd->net.report_error); + mysql_parse_status && thd->is_error()); /* Reset Lex_input_stream. */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0d31dbe3a8b..46a063db67f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2867,7 +2867,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex_start(thd); error= parse_sql(thd, &lip, NULL) || - thd->net.report_error || + thd->is_error() || init_param_array(this); lex->set_trg_event_type_for_tables(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 196419e7013..612f5aba0f7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -122,7 +122,7 @@ static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, static enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, - int error, my_bool *report_error); + int error); static enum_nested_loop_state evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab); static enum_nested_loop_state @@ -263,8 +263,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, result, unit, select_lex); } DBUG_PRINT("info",("res: %d report_error: %d", res, - thd->net.report_error)); - res|= thd->net.report_error; + thd->is_error())); + res|= thd->is_error(); if (unlikely(res)) result->abort(); @@ -491,7 +491,7 @@ JOIN::prepare(Item ***rref_pointer_array, (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; - if (having_fix_rc || thd->net.report_error) + if (having_fix_rc || thd->is_error()) DBUG_RETURN(-1); /* purecov: inspected */ thd->lex->allow_sum_func= save_allow_sum_func; } @@ -818,7 +818,7 @@ JOIN::optimize() } conds= optimize_cond(this, conds, join_list, &cond_value); - if (thd->net.report_error) + if (thd->is_error()) { error= 1; DBUG_PRINT("error",("Error from optimize_cond")); @@ -827,7 +827,7 @@ JOIN::optimize() { having= optimize_cond(this, having, join_list, &having_value); - if (thd->net.report_error) + if (thd->is_error()) { error= 1; DBUG_PRINT("error",("Error from optimize_cond")); @@ -1039,7 +1039,7 @@ JOIN::optimize() { ORDER *org_order= order; order=remove_const(this, order,conds,1, &simple_order); - if (thd->net.report_error) + if (thd->is_error()) { error= 1; DBUG_PRINT("error",("Error from remove_const")); @@ -1170,7 +1170,7 @@ JOIN::optimize() group_list= remove_const(this, (old_group_list= group_list), conds, rollup.state == ROLLUP::STATE_NONE, &simple_group); - if (thd->net.report_error) + if (thd->is_error()) { error= 1; DBUG_PRINT("error",("Error from remove_const")); @@ -1193,7 +1193,7 @@ JOIN::optimize() { group_list= procedure->group= remove_const(this, procedure->group, conds, 1, &simple_group); - if (thd->net.report_error) + if (thd->is_error()) { error= 1; DBUG_PRINT("error",("Error from remove_const")); @@ -2116,10 +2116,10 @@ JOIN::exec() } } } - /* XXX: When can we have here thd->net.report_error not zero? */ - if (thd->net.report_error) + /* XXX: When can we have here thd->is_error() not zero? */ + if (thd->is_error()) { - error= thd->net.report_error; + error= thd->is_error(); DBUG_VOID_RETURN; } curr_join->having= curr_join->tmp_having; @@ -2325,7 +2325,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, join->having_history= (join->having?join->having:join->tmp_having); } - if (thd->net.report_error) + if (thd->is_error()) goto err; join->exec(); @@ -2351,8 +2351,7 @@ err: { thd_proc_info(thd, "end"); err|= select_lex->cleanup(); - thd_proc_info(thd, "end"); - DBUG_RETURN(err || thd->net.report_error); + DBUG_RETURN(err || thd->is_error()); } DBUG_RETURN(join->error); } @@ -6670,7 +6669,7 @@ void JOIN::cleanup(bool full) for (tab= join_tab, end= tab+tables; tab != end; tab++) { if (tab->table) - tab->table->file->ha_index_or_rnd_end(); + tab->table->file->ha_index_or_rnd_end(); } } } @@ -10729,7 +10728,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) DBUG_PRINT("error",("Error: do_select() failed")); } #endif - DBUG_RETURN(join->thd->net.report_error ? -1 : rc); + DBUG_RETURN(join->thd->is_error() ? -1 : rc); } @@ -10883,7 +10882,6 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) int error; enum_nested_loop_state rc; - my_bool *report_error= &(join->thd->net.report_error); READ_RECORD *info= &join_tab->read_record; if (join->resume_nested_loop) @@ -10915,13 +10913,13 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) join->thd->row_count= 0; error= (*join_tab->read_first_record)(join_tab); - rc= evaluate_join_record(join, join_tab, error, report_error); + rc= evaluate_join_record(join, join_tab, error); } while (rc == NESTED_LOOP_OK) { error= info->read_record(info); - rc= evaluate_join_record(join, join_tab, error, report_error); + rc= evaluate_join_record(join, join_tab, error); } if (rc == NESTED_LOOP_NO_MORE_ROWS && @@ -10945,13 +10943,13 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) static enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, - int error, my_bool *report_error) + int error) { bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; - if (error > 0 || (*report_error)) // Fatal error + if (error > 0 || (join->thd->is_error())) // Fatal error return NESTED_LOOP_ERROR; if (error < 0) return NESTED_LOOP_NO_MORE_ROWS; @@ -16062,7 +16060,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) first->options | thd->options | SELECT_DESCRIBE, result, unit, first); } - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(res || thd->is_error()); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e63c8a0d4ff..efd396dac72 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -434,7 +434,7 @@ static uint read_ddl_log_header() create_ddl_log_file_name(file_name); if ((global_ddl_log.file_id= my_open(file_name, - O_RDWR | O_BINARY, MYF(MY_WME))) >= 0) + O_RDWR | O_BINARY, MYF(0))) >= 0) { if (read_ddl_log_file_entry(0UL)) { @@ -1503,7 +1503,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, char path[FN_REFLEN], *alias; uint path_length; String wrong_tables; - int error; + int error= 0; int non_temp_tables_count= 0; bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0; String built_query; @@ -1563,10 +1563,27 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, enum legacy_db_type frm_db_type; mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, 1); - if (!close_temporary_table(thd, table)) - { - tmp_table_deleted=1; - continue; // removed temporary table + + error= drop_temporary_table(thd, table); + + switch (error) { + case 0: + // removed temporary table + tmp_table_deleted= 1; + continue; + case -1: + // table already in use + /* + XXX: This branch should never be taken outside of SF, trigger or + prelocked mode. + + DBUG_ASSERT(thd->in_sub_stmt); + */ + error= 1; + goto err_with_placeholders; + default: + // temporary table not found + error= 0; } /* @@ -1593,7 +1610,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, built_query.append("`,"); } - error=0; table_type= table->db_type; if (!drop_temporary) { @@ -2380,8 +2396,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->length= dup_field->char_length; sql_field->pack_length= dup_field->pack_length; sql_field->key_length= dup_field->key_length; - sql_field->create_length_to_internal_length(); sql_field->decimals= dup_field->decimals; + sql_field->create_length_to_internal_length(); sql_field->unireg_check= dup_field->unireg_check; /* We're making one field from two, the result field will have @@ -4985,6 +5001,7 @@ compare_tables(TABLE *table, create_info->used_fields & HA_CREATE_USED_ENGINE || create_info->used_fields & HA_CREATE_USED_CHARSET || create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET || + create_info->used_fields & HA_CREATE_USED_ROW_FORMAT || (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) || order_num || !table->s->mysql_version || @@ -5200,7 +5217,8 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, if (error == HA_ERR_WRONG_COMMAND) { push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->s->table_name); + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), + table->s->table_name.str); error= 0; } else if (error) table->file->print_error(error, MYF(0)); @@ -5392,7 +5410,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, { if (def->change && ! def->field) { - my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name); + my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str); goto err; } /* @@ -5427,7 +5445,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!find) { - my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name); + my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str); goto err; } find_it.after(def); // Put element after this @@ -5437,7 +5455,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (alter_info->alter_list.elements) { my_error(ER_BAD_FIELD_ERROR, MYF(0), - alter_info->alter_list.head()->name, table->s->table_name); + alter_info->alter_list.head()->name, table->s->table_name.str); goto err; } if (!new_create_list.elements) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5da4b97cc5d..a48cff82715 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -58,7 +58,7 @@ bool select_union::send_data(List<Item> &values) return 0; } fill_record(thd, table->field, values, 1); - if (thd->net.report_error) + if (thd->is_error()) return 1; if ((error= table->file->ha_write_row(table->record[0]))) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index fff12c74840..a17657a5e9c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -679,7 +679,7 @@ int mysql_update(THD *thd, */ if (will_batch && ((error= table->file->exec_bulk_update(&dup_key_found)) || - !dup_key_found)) + dup_key_found)) { if (error) { @@ -844,7 +844,7 @@ int mysql_update(THD *thd, } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ thd->abort_on_warning= 0; - DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0); + DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0); err: delete select; @@ -1193,8 +1193,8 @@ bool mysql_multi_update(THD *thd, OPTION_SETUP_TABLES_DONE, result, unit, select_lex); DBUG_PRINT("info",("res: %d report_error: %d", res, - thd->net.report_error)); - res|= thd->net.report_error; + (int) thd->is_error())); + res|= thd->is_error(); if (unlikely(res)) { /* If we had a another error reported earlier then this will be ignored */ diff --git a/sql/sql_view.cc b/sql/sql_view.cc index fe088f8a93d..af3995d75df 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -607,7 +607,7 @@ err: thd_proc_info(thd, "end"); lex->link_first_table_back(view, link_to_local); unit->cleanup(); - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(res || thd->is_error()); } @@ -823,7 +823,7 @@ loop_out: view_parameters + revision_number_position, 1, &file_parser_dummy_hook)) { - error= thd->net.report_error? -1 : 0; + error= thd->is_error() ? -1 : 0; goto err; } } @@ -886,7 +886,7 @@ loop_out: if (sql_create_definition_file(&dir, &file, view_file_type, (uchar*)view, view_parameters, num_view_backups)) { - error= thd->net.report_error? -1 : 1; + error= thd->is_error() ? -1 : 1; goto err; } DBUG_RETURN(0); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7ee79a58af1..eb3b1162dbc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9862,9 +9862,10 @@ literal: MYSQL_YYABORT; } } - | DATE_SYM text_literal { $$ = $2; } - | TIME_SYM text_literal { $$ = $2; } - | TIMESTAMP text_literal { $$ = $2; }; + | DATE_SYM text_literal { $$ = $2; } + | TIME_SYM text_literal { $$ = $2; } + | TIMESTAMP text_literal { $$ = $2; } + ; NUM_literal: NUM @@ -9882,7 +9883,7 @@ NUM_literal: | DECIMAL_NUM { $$= new Item_decimal($1.str, $1.length, YYTHD->charset()); - if (YYTHD->net.report_error) + if (YYTHD->is_error()) { MYSQL_YYABORT; } @@ -9890,7 +9891,7 @@ NUM_literal: | FLOAT_NUM { $$ = new Item_float($1.str, $1.length); - if (YYTHD->net.report_error) + if (YYTHD->is_error()) { MYSQL_YYABORT; } @@ -10605,6 +10606,7 @@ set: lex->option_type=OPT_SESSION; lex->var_list.empty(); lex->one_shot_set= 0; + lex->autocommit= 0; } option_value_list {} @@ -10647,6 +10649,7 @@ option_type_value: lex->option_type=OPT_SESSION; lex->var_list.empty(); lex->one_shot_set= 0; + lex->autocommit= 0; lex->sphead->m_tmp_query= lip->get_tok_start(); } } @@ -10888,10 +10891,16 @@ option_value: user->host=null_lex_str; user->user.str=thd->security_ctx->priv_user; thd->lex->var_list.push_back(new set_var_password(user, $3)); + thd->lex->autocommit= TRUE; + if (lex->sphead) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; } | PASSWORD FOR_SYM user equal text_or_password { Lex->var_list.push_back(new set_var_password($3,$5)); + Lex->autocommit= TRUE; + if (Lex->sphead) + Lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; } ; diff --git a/sql/table.h b/sql/table.h index e873fb1de58..f3cfd75e022 100644 --- a/sql/table.h +++ b/sql/table.h @@ -499,6 +499,24 @@ struct st_table { my_bitmap_map *bitmap_init_value; MY_BITMAP def_read_set, def_write_set, tmp_set; /* containers */ MY_BITMAP *read_set, *write_set; /* Active column sets */ + /* + The ID of the query that opened and is using this table. Has different + meanings depending on the table type. + + Temporary tables: + + table->query_id is set to thd->query_id for the duration of a statement + and is reset to 0 once it is closed by the same statement. A non-zero + table->query_id means that a statement is using the table even if it's + not the current statement (table is in use by some outer statement). + + Non-temporary tables: + + Under pre-locked or LOCK TABLES mode: query_id is set to thd->query_id + for the duration of a statement and is reset to 0 once it is closed by + the same statement. A non-zero query_id is used to control which tables + in the list of pre-opened and locked tables are actually being used. + */ query_id_t query_id; /* @@ -593,8 +611,8 @@ struct st_table { my_bool locked_by_name; my_bool fulltext_searched; my_bool no_cache; - /* To signal that we should reset query_id for tables and cols */ - my_bool clear_query_id; + /* To signal that the table is associated with a HANDLER statement */ + my_bool open_by_handler; /* To indicate that a non-null value of the auto_increment field was provided by the user or retrieved from the current record. diff --git a/sql/unireg.cc b/sql/unireg.cc index f9e8e54439a..f2238d69973 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -47,6 +47,35 @@ static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type, uint reclength, ulong data_offset, handler *handler); +/** + An interceptor to hijack ER_TOO_MANY_FIELDS error from + pack_screens and retry again without UNIREG screens. + + XXX: what is a UNIREG screen? +*/ + +struct Pack_header_error_handler: public Internal_error_handler +{ + virtual bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + bool is_handled; + Pack_header_error_handler() :is_handled(FALSE) {} +}; + + +bool +Pack_header_error_handler:: +handle_error(uint sql_errno, + const char * /* message */, + MYSQL_ERROR::enum_warning_level /* level */, + THD * /* thd */) +{ + is_handled= (sql_errno == ER_TOO_MANY_FIELDS); + return is_handled; +} + /* Create a frm (table definition) file @@ -86,6 +115,8 @@ bool mysql_create_frm(THD *thd, const char *file_name, #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *part_info= thd->work_part_info; #endif + Pack_header_error_handler pack_header_error_handler; + int error; DBUG_ENTER("mysql_create_frm"); DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension @@ -99,17 +130,22 @@ bool mysql_create_frm(THD *thd, const char *file_name, create_info->null_bits++; data_offset= (create_info->null_bits + 7) / 8; - if (pack_header(forminfo, ha_legacy_type(create_info->db_type), - create_fields,info_length, - screens, create_info->table_options, - data_offset, db_file)) + thd->push_internal_handler(&pack_header_error_handler); + + error= pack_header(forminfo, ha_legacy_type(create_info->db_type), + create_fields,info_length, + screens, create_info->table_options, + data_offset, db_file); + + thd->pop_internal_handler(); + + if (error) { my_free(screen_buff, MYF(0)); - if (thd->net.last_errno != ER_TOO_MANY_FIELDS) + if (! pack_header_error_handler.is_handled) DBUG_RETURN(1); // Try again without UNIREG screens (to get more columns) - thd->net.last_error[0]=0; if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1))) DBUG_RETURN(1); if (pack_header(forminfo, ha_legacy_type(create_info->db_type), diff --git a/storage/ndb/include/kernel/AttributeHeader.hpp b/storage/ndb/include/kernel/AttributeHeader.hpp index 613e3d19d1b..52f93b6cd05 100644 --- a/storage/ndb/include/kernel/AttributeHeader.hpp +++ b/storage/ndb/include/kernel/AttributeHeader.hpp @@ -52,8 +52,7 @@ public: // NOTE: in 5.1 ctors and init take size in bytes /** Initialize AttributeHeader at location aHeaderPtr */ - static AttributeHeader& init(void* aHeaderPtr, Uint32 anAttributeId, - Uint32 aByteSize); + static void init(Uint32* aHeaderPtr, Uint32 anAttributeId, Uint32 aByteSize); /** Returns size of AttributeHeader (usually one or two words) */ Uint32 getHeaderSize() const; // In 32-bit words @@ -113,10 +112,11 @@ public: */ inline -AttributeHeader& AttributeHeader::init(void* aHeaderPtr, Uint32 anAttributeId, - Uint32 aByteSize) +void AttributeHeader::init(Uint32* aHeaderPtr, Uint32 anAttributeId, + Uint32 aByteSize) { - return * new (aHeaderPtr) AttributeHeader(anAttributeId, aByteSize); + AttributeHeader ah(anAttributeId, aByteSize); + *aHeaderPtr = ah.m_value; } inline diff --git a/storage/ndb/include/kernel/GlobalSignalNumbers.h b/storage/ndb/include/kernel/GlobalSignalNumbers.h index aa0596f102a..9653c20260f 100644 --- a/storage/ndb/include/kernel/GlobalSignalNumbers.h +++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h @@ -195,9 +195,11 @@ extern const GlobalSignalNumber NO_OF_SIGNAL_NAMES; /* 132 not unused */ /* 133 not unused */ #define GSN_CM_HEARTBEAT 134 /* distr. */ -/* 135 unused */ -/* 136 unused */ -/* 137 unused */ + +#define GSN_PREPARE_COPY_FRAG_REQ 135 +#define GSN_PREPARE_COPY_FRAG_REF 136 +#define GSN_PREPARE_COPY_FRAG_CONF 137 + #define GSN_CM_NODEINFOCONF 138 /* distr. */ #define GSN_CM_NODEINFOREF 139 /* distr. */ #define GSN_CM_NODEINFOREQ 140 /* distr. */ diff --git a/storage/ndb/include/kernel/signaldata/AccScan.hpp b/storage/ndb/include/kernel/signaldata/AccScan.hpp index 73d69825069..a0aa38c8d8e 100644 --- a/storage/ndb/include/kernel/signaldata/AccScan.hpp +++ b/storage/ndb/include/kernel/signaldata/AccScan.hpp @@ -49,6 +49,7 @@ private: Uint32 savePointId; Uint32 gci; }; + Uint32 maxPage; /** * Previously there where also a scan type diff --git a/storage/ndb/include/kernel/signaldata/CopyFrag.hpp b/storage/ndb/include/kernel/signaldata/CopyFrag.hpp index 06dd4070264..d985358dce4 100644 --- a/storage/ndb/include/kernel/signaldata/CopyFrag.hpp +++ b/storage/ndb/include/kernel/signaldata/CopyFrag.hpp @@ -29,7 +29,7 @@ class CopyFragReq { */ friend class Dblqh; public: - STATIC_CONST( SignalLength = 9 ); + STATIC_CONST( SignalLength = 10 ); private: Uint32 userPtr; @@ -42,6 +42,7 @@ private: Uint32 gci; Uint32 nodeCount; Uint32 nodeList[1]; + //Uint32 maxPage; is stored in nodeList[nodeCount] }; class CopyFragConf { @@ -95,4 +96,42 @@ struct UpdateFragDistKeyOrd STATIC_CONST( SignalLength = 3 ); }; +struct PrepareCopyFragReq +{ + STATIC_CONST( SignalLength = 6 ); + + Uint32 senderRef; + Uint32 senderData; + Uint32 tableId; + Uint32 fragId; + Uint32 copyNodeId; + Uint32 startingNodeId; +}; + +struct PrepareCopyFragRef +{ + Uint32 senderRef; + Uint32 senderData; + Uint32 tableId; + Uint32 fragId; + Uint32 copyNodeId; + Uint32 startingNodeId; + Uint32 errorCode; + + STATIC_CONST( SignalLength = 7 ); +}; + +struct PrepareCopyFragConf +{ + STATIC_CONST( SignalLength = 7 ); + + Uint32 senderRef; + Uint32 senderData; + Uint32 tableId; + Uint32 fragId; + Uint32 copyNodeId; + Uint32 startingNodeId; + Uint32 maxPageNo; +}; + #endif diff --git a/storage/ndb/include/kernel/signaldata/ScanTab.hpp b/storage/ndb/include/kernel/signaldata/ScanTab.hpp index 0074078533f..3d2071ca019 100644 --- a/storage/ndb/include/kernel/signaldata/ScanTab.hpp +++ b/storage/ndb/include/kernel/signaldata/ScanTab.hpp @@ -46,6 +46,7 @@ public: * Length of signal */ STATIC_CONST( StaticLength = 11 ); + STATIC_CONST( MaxTotalAttrInfo = 0xFFFF ); private: diff --git a/storage/ndb/include/kernel/signaldata/TcKeyConf.hpp b/storage/ndb/include/kernel/signaldata/TcKeyConf.hpp index b8562875ef5..fd8932c3c87 100644 --- a/storage/ndb/include/kernel/signaldata/TcKeyConf.hpp +++ b/storage/ndb/include/kernel/signaldata/TcKeyConf.hpp @@ -46,7 +46,7 @@ public: */ STATIC_CONST( StaticLength = 5 ); STATIC_CONST( OperationLength = 2 ); - STATIC_CONST( SimpleReadBit = (((Uint32)1) << 31) ); + STATIC_CONST( DirtyReadBit = (((Uint32)1) << 31) ); private: diff --git a/storage/ndb/include/ndb_version.h.in b/storage/ndb/include/ndb_version.h.in index 5405ad4d7aa..6a479433b3b 100644 --- a/storage/ndb/include/ndb_version.h.in +++ b/storage/ndb/include/ndb_version.h.in @@ -88,5 +88,52 @@ Uint32 ndbGetOwnVersion(); #define NDBD_NODE_VERSION_REP NDB_MAKE_VERSION(6,1,1) +#define NDBD_PREPARE_COPY_FRAG_VERSION NDB_MAKE_VERSION(6,2,1) +#define NDBD_PREPARE_COPY_FRAG_V2_51 NDB_MAKE_VERSION(5,1,23) +#define NDBD_PREPARE_COPY_FRAG_V2_62 NDB_MAKE_VERSION(6,2,8) +#define NDBD_PREPARE_COPY_FRAG_V2_63 NDB_MAKE_VERSION(6,3,6) + +/** + * 0 = NO PREP COPY FRAG SUPPORT + * 1 = NO MAX PAGE SUPPORT + * 2 = LATEST VERSION + */ +static +inline +int +ndb_check_prep_copy_frag_version(Uint32 version) +{ + if (version == NDB_VERSION_D) + return 2; + + const Uint32 major = (version >> 16) & 0xFF; + const Uint32 minor = (version >> 8) & 0xFF; + if (major >= 6) + { + if (minor == 2) + { + if (version >= NDBD_PREPARE_COPY_FRAG_V2_62) + return 2; + if (version >= NDBD_PREPARE_COPY_FRAG_VERSION) + return 1; + return 0; + } + else if (minor == 3) + { + if (version >= NDBD_PREPARE_COPY_FRAG_V2_63) + return 2; + return 1; + } + return 2; + } + else if (major == 5 && minor == 1) + { + if (version >= NDBD_PREPARE_COPY_FRAG_V2_51) + return 2; + } + + return 0; +} + #endif diff --git a/storage/ndb/include/ndbapi/Ndb.hpp b/storage/ndb/include/ndbapi/Ndb.hpp index 995ce67e61d..dca19c2ead0 100644 --- a/storage/ndb/include/ndbapi/Ndb.hpp +++ b/storage/ndb/include/ndbapi/Ndb.hpp @@ -1056,6 +1056,7 @@ class Ndb friend class NdbBlob; friend class NdbImpl; friend class Ndb_internal; + friend class NdbScanFilterImpl; #endif public: diff --git a/storage/ndb/include/ndbapi/NdbOperation.hpp b/storage/ndb/include/ndbapi/NdbOperation.hpp index 06111941df4..78dbadfd7ab 100644 --- a/storage/ndb/include/ndbapi/NdbOperation.hpp +++ b/storage/ndb/include/ndbapi/NdbOperation.hpp @@ -93,8 +93,9 @@ public: ,LM_CommittedRead ///< Ignore locks, read last committed value #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL = 2, - LM_Dirty = 2 + LM_Dirty = 2, #endif + LM_SimpleRead = 3 ///< Read with shared lock, but release lock directly }; /** @@ -842,8 +843,10 @@ protected: virtual ~NdbOperation(); void next(NdbOperation*); // Set next pointer NdbOperation* next(); // Get next pointer + public: #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + NdbTransaction* getNdbTransaction(); const NdbOperation* next() const; const NdbRecAttr* getFirstRecAttr() const; #endif diff --git a/storage/ndb/include/ndbapi/NdbPool.hpp b/storage/ndb/include/ndbapi/NdbPool.hpp index 1963bf26448..44b6d7488f0 100644 --- a/storage/ndb/include/ndbapi/NdbPool.hpp +++ b/storage/ndb/include/ndbapi/NdbPool.hpp @@ -17,7 +17,8 @@ class Ndb; class NdbPool; bool -create_instance(Uint32 max_ndb_objects, +create_instance(Ndb_cluster_connection* cc, + Uint32 max_ndb_objects, Uint32 no_conn_obj, Uint32 init_no_ndb_objects); diff --git a/storage/ndb/include/ndbapi/NdbScanFilter.hpp b/storage/ndb/include/ndbapi/NdbScanFilter.hpp index 1ef62558560..4527012a6c4 100644 --- a/storage/ndb/include/ndbapi/NdbScanFilter.hpp +++ b/storage/ndb/include/ndbapi/NdbScanFilter.hpp @@ -17,6 +17,7 @@ #define NDB_SCAN_FILTER_HPP #include <ndb_types.h> +#include <ndbapi_limits.h> /** * @class NdbScanFilter @@ -31,8 +32,13 @@ public: /** * Constructor * @param op The NdbOperation that the filter belongs to (is applied to). + * @param abort_on_too_large abort transaction on filter too large + * default: true + * @param max_size Maximum size of generated filter in words */ - NdbScanFilter(class NdbOperation * op); + NdbScanFilter(class NdbOperation * op, + bool abort_on_too_large = true, + Uint32 max_size = NDB_MAX_SCANFILTER_SIZE_IN_WORDS); ~NdbScanFilter(); /** @@ -166,6 +172,27 @@ public: /** @} *********************************************************************/ #endif + enum Error { + FilterTooLarge = 4294 + }; + + /** + * Get filter level error. + * + * Most errors are set only on operation level, and they abort the + * transaction. The error FilterTooLarge is set on filter level and + * by default it propagates to operation level and also aborts the + * transaction. + * + * If option abort_on_too_large is set to false, then FilterTooLarge + * does not propagate. One can then either ignore this error (in + * which case no filtering is done) or try to define a new filter + * immediately. + */ + const class NdbError & getNdbError() const; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + NdbOperation * getNdbOperation(); +#endif private: #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL friend class NdbScanFilterImpl; diff --git a/storage/ndb/include/ndbapi/NdbTransaction.hpp b/storage/ndb/include/ndbapi/NdbTransaction.hpp index 20c9c709e51..6a057655398 100644 --- a/storage/ndb/include/ndbapi/NdbTransaction.hpp +++ b/storage/ndb/include/ndbapi/NdbTransaction.hpp @@ -170,6 +170,15 @@ public: #endif }; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * Convenience method to fetch this transaction's Ndb* object + */ + Ndb * getNdb() { + return theNdb; + } +#endif + #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED /** * Get an NdbOperation for a table. diff --git a/storage/ndb/include/ndbapi/ndbapi_limits.h b/storage/ndb/include/ndbapi/ndbapi_limits.h index 63399e4bd0a..e283913d059 100644 --- a/storage/ndb/include/ndbapi/ndbapi_limits.h +++ b/storage/ndb/include/ndbapi/ndbapi_limits.h @@ -26,4 +26,6 @@ #define NDB_MAX_TUPLE_SIZE (NDB_MAX_TUPLE_SIZE_IN_WORDS*4) #define NDB_MAX_ACTIVE_EVENTS 100 +#define NDB_MAX_SCANFILTER_SIZE_IN_WORDS 50000 + #endif diff --git a/storage/ndb/include/util/ndb_rand.h b/storage/ndb/include/util/ndb_rand.h new file mode 100644 index 00000000000..1521ca9c4ff --- /dev/null +++ b/storage/ndb/include/util/ndb_rand.h @@ -0,0 +1,33 @@ +/* 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; version 2 of the License. + + 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 NDB_RAND_H +#define NDB_RAND_H + +#define NDB_RAND_MAX 32767 + +#ifdef __cplusplus +extern "C" { +#endif + +int ndb_rand(void); + +void ndb_srand(unsigned seed); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/storage/ndb/src/common/debugger/EventLogger.cpp b/storage/ndb/src/common/debugger/EventLogger.cpp index 0964a54f906..068b0c6ac18 100644 --- a/storage/ndb/src/common/debugger/EventLogger.cpp +++ b/storage/ndb/src/common/debugger/EventLogger.cpp @@ -498,10 +498,10 @@ void getTextTransReportCounters(QQQQ) { // ------------------------------------------------------------------- BaseString::snprintf(m_text, m_text_len, "Trans. Count = %u, Commit Count = %u, " - "Read Count = %u, Simple Read Count = %u,\n" + "Read Count = %u, Simple Read Count = %u, " "Write Count = %u, AttrInfo Count = %u, " - "Concurrent Operations = %u, Abort Count = %u\n" - " Scans: %u Range scans: %u", + "Concurrent Operations = %u, Abort Count = %u" + " Scans = %u Range scans = %u", theData[1], theData[2], theData[3], @@ -797,9 +797,9 @@ void getTextBackupFailedToStart(QQQQ) { } void getTextBackupCompleted(QQQQ) { BaseString::snprintf(m_text, m_text_len, - "Backup %u started from node %u completed\n" - " StartGCP: %u StopGCP: %u\n" - " #Records: %u #LogRecords: %u\n" + "Backup %u started from node %u completed." + " StartGCP: %u StopGCP: %u" + " #Records: %u #LogRecords: %u" " Data: %u bytes Log: %u bytes", theData[2], refToNode(theData[1]), theData[3], theData[4], theData[6], theData[8], diff --git a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp index 0d31cd5de7f..b4221cbec8e 100644 --- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp +++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp @@ -640,5 +640,9 @@ const GsnName SignalNames [] = { ,{ GSN_ROUTE_ORD, "ROUTE_ORD" } ,{ GSN_NODE_VERSION_REP, "NODE_VERSION_REP" } + + ,{ GSN_PREPARE_COPY_FRAG_REQ, "PREPARE_COPY_FRAG_REQ" } + ,{ GSN_PREPARE_COPY_FRAG_REF, "PREPARE_COPY_FRAG_REF" } + ,{ GSN_PREPARE_COPY_FRAG_CONF, "PREPARE_COPY_FRAG_CONF" } }; const unsigned short NO_OF_SIGNAL_NAMES = sizeof(SignalNames)/sizeof(GsnName); diff --git a/storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp b/storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp index 65589f8cd6e..377863f9446 100644 --- a/storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp +++ b/storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp @@ -51,11 +51,11 @@ printTCKEYCONF(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receive (TcKeyConf::getMarkerFlag(confInfo) == 0)?"false":"true"); fprintf(output, "Operations:\n"); for(i = 0; i < noOfOp; i++) { - if(sig->operations[i].attrInfoLen > TcKeyConf::SimpleReadBit) + if(sig->operations[i].attrInfoLen > TcKeyConf::DirtyReadBit) fprintf(output, " apiOperationPtr: H'%.8x, simplereadnode: %u\n", sig->operations[i].apiOperationPtr, - sig->operations[i].attrInfoLen & (~TcKeyConf::SimpleReadBit)); + sig->operations[i].attrInfoLen & (~TcKeyConf::DirtyReadBit)); else fprintf(output, " apiOperationPtr: H'%.8x, attrInfoLen: %u\n", diff --git a/storage/ndb/src/common/util/Makefile.am b/storage/ndb/src/common/util/Makefile.am index d331cce7e5c..5379a425c49 100644 --- a/storage/ndb/src/common/util/Makefile.am +++ b/storage/ndb/src/common/util/Makefile.am @@ -24,7 +24,8 @@ libgeneral_la_SOURCES = \ uucode.c random.c version.c \ strdup.c \ ConfigValues.cpp ndb_init.c basestring_vsnprintf.c \ - Bitmask.cpp + Bitmask.cpp \ + ndb_rand.c EXTRA_PROGRAMS = testBitmask testBitmask_SOURCES = testBitmask.cpp diff --git a/storage/ndb/src/common/util/ndb_rand.c b/storage/ndb/src/common/util/ndb_rand.c new file mode 100644 index 00000000000..4fcc483cd49 --- /dev/null +++ b/storage/ndb/src/common/util/ndb_rand.c @@ -0,0 +1,40 @@ +/* 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; version 2 of the License. + + 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 <ndb_rand.h> + +static unsigned long next= 1; + +/** + * ndb_rand + * + * constant time, cheap, pseudo-random number generator. + * + * NDB_RAND_MAX assumed to be 32767 + * + * This is the POSIX example for "generating the same sequence on + * different machines". Although that is not one of our requirements. + */ +int ndb_rand(void) +{ + next= next * 1103515245 + 12345; + return((unsigned)(next/65536) % 32768); +} + +void ndb_srand(unsigned seed) +{ + next= seed; +} + diff --git a/storage/ndb/src/cw/cpcd/APIService.cpp b/storage/ndb/src/cw/cpcd/APIService.cpp index 1c1cfb94cd4..f60abc08817 100644 --- a/storage/ndb/src/cw/cpcd/APIService.cpp +++ b/storage/ndb/src/cw/cpcd/APIService.cpp @@ -145,7 +145,7 @@ CPCDAPISession::CPCDAPISession(NDB_SOCKET_TYPE sock, : SocketServer::Session(sock) , m_cpcd(cpcd) { - m_input = new SocketInputStream(sock); + m_input = new SocketInputStream(sock, 7*24*60*60000); m_output = new SocketOutputStream(sock); m_parser = new Parser<CPCDAPISession>(commands, *m_input, true, true, true); } diff --git a/storage/ndb/src/kernel/blocks/ERROR_codes.txt b/storage/ndb/src/kernel/blocks/ERROR_codes.txt index acfbf649522..4d4d4fcafc4 100644 --- a/storage/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/storage/ndb/src/kernel/blocks/ERROR_codes.txt @@ -3,15 +3,15 @@ Next NDBCNTR 1002 Next NDBFS 2000 Next DBACC 3002 Next DBTUP 4029 -Next DBLQH 5045 +Next DBLQH 5047 Next DBDICT 6008 -Next DBDIH 7186 -Next DBTC 8053 +Next DBDIH 7193 +Next DBTC 8054 Next CMVMI 9000 Next BACKUP 10038 Next DBUTIL 11002 Next DBTUX 12008 -Next SUMA 13001 +Next SUMA 13034 TESTING NODE FAILURE, ARBITRATION --------------------------------- @@ -157,6 +157,9 @@ And crash when all have "not" been sent 7027: Crash in master when changing state to LCP_TAB_SAVED 7018: Crash in master when changing state to LCP_TAB_SAVED +7191: Crash when receiving LCP_COMPLETE_REP +7192: Crash in setLcpActiveStatusStart - when dead node missed to LCP's + ERROR CODES FOR TESTING NODE FAILURE, FAILURE IN COPY FRAGMENT PROCESS: ----------------------------------------------------------------------- @@ -183,6 +186,8 @@ handling in DBTC to ensure that node failures are also well handled in time-out handling. They can also be used to test multiple node failure handling. +5045: Crash in PREPARE_COPY_FRAG_REQ +5046: Crash if LQHKEYREQ (NrCopy) comes when frag-state is incorrect ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBLQH ------------------------------------------------- @@ -248,6 +253,8 @@ Delay execution of ABORTCONF signal 2 seconds to generate time-out. 8050: Send ZABORT_TIMEOUT_BREAK delayed +8053: Crash in timeOutFoundLab, state CS_WAIT_COMMIT_CONF + ERROR CODES FOR TESTING TIME-OUT HANDLING IN DBTC ------------------------------------------------- diff --git a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp index 7a992587010..3406176d7a8 100644 --- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp +++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp @@ -1124,6 +1124,38 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal) } #endif #endif + + if (arg == 9999) + { + Uint32 delay = 1000; + switch(signal->getLength()){ + case 1: + break; + case 2: + delay = signal->theData[1]; + break; + default:{ + Uint32 dmin = signal->theData[1]; + Uint32 dmax = signal->theData[2]; + delay = dmin + (rand() % (dmax - dmin)); + break; + } + } + + signal->theData[0] = 9999; + if (delay == 0) + { + execNDB_TAMPER(signal); + } + else if (delay < 10) + { + sendSignal(reference(), GSN_NDB_TAMPER, signal, 1, JBB); + } + else + { + sendSignalWithDelay(reference(), GSN_NDB_TAMPER, signal, delay, 1); + } + } }//Cmvmi::execDUMP_STATE_ORD() void diff --git a/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp b/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp index 5bef13cd0b9..21826df28f9 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp +++ b/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp @@ -318,6 +318,7 @@ public: Uint8 noOfStartedChkpt; MasterLCPConf::State lcpStateAtTakeOver; + Uint32 m_remove_node_from_table_lcp_id; }; typedef Ptr<NodeRecord> NodeRecordPtr; /**********************************************************************/ @@ -544,7 +545,8 @@ public: TO_WAIT_ENDING = 21, ENDING = 22, - STARTING_LOCAL_FRAGMENTS = 24 + STARTING_LOCAL_FRAGMENTS = 24, + PREPARE_COPY = 25 }; enum ToSlaveStatus { TO_SLAVE_IDLE = 0, @@ -555,6 +557,7 @@ public: TO_SLAVE_COPY_COMPLETED = 5 }; Uint32 startGci; + Uint32 maxPage; Uint32 toCopyNode; Uint32 toCurrentFragid; Uint32 toCurrentReplica; @@ -671,6 +674,8 @@ private: void execNODE_FAILREP(Signal *); void execCOPY_FRAGCONF(Signal *); void execCOPY_FRAGREF(Signal *); + void execPREPARE_COPY_FRAG_REF(Signal*); + void execPREPARE_COPY_FRAG_CONF(Signal*); void execDIADDTABREQ(Signal *); void execDIGETNODESREQ(Signal *); void execDIRELEASEREQ(Signal *); @@ -1113,6 +1118,7 @@ private: void sendStartTo(Signal *, Uint32 takeOverPtr); void startNextCopyFragment(Signal *, Uint32 takeOverPtr); void toCopyFragLab(Signal *, Uint32 takeOverPtr); + void toStartCopyFrag(Signal *, TakeOverRecordPtr); void startHsAddFragConfLab(Signal *); void prepareSendCreateFragReq(Signal *, Uint32 takeOverPtr); void sendUpdateTo(Signal *, Uint32 takeOverPtr, Uint32 updateState); diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp index aff31d625f4..6ce281434c2 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp +++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp @@ -259,6 +259,11 @@ Dbdih::Dbdih(Block_context& ctx): addRecSignal(GSN_START_FRAGREF, &Dbdih::execSTART_FRAGREF); + + addRecSignal(GSN_PREPARE_COPY_FRAG_REF, + &Dbdih::execPREPARE_COPY_FRAG_REF); + addRecSignal(GSN_PREPARE_COPY_FRAG_CONF, + &Dbdih::execPREPARE_COPY_FRAG_CONF); apiConnectRecord = 0; connectRecord = 0; diff --git a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 762d4ea5141..5403ac5cc38 100644 --- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -3155,6 +3155,94 @@ void Dbdih::toCopyFragLab(Signal* signal, TakeOverRecordPtr takeOverPtr; RETURN_IF_TAKE_OVER_INTERRUPTED(takeOverPtrI, takeOverPtr); + /** + * Inform starting node that TakeOver is about to start + */ + Uint32 nodeId = takeOverPtr.p->toStartingNode; + + Uint32 version = getNodeInfo(nodeId).m_version; + if (ndb_check_prep_copy_frag_version(version)) + { + jam(); + TabRecordPtr tabPtr; + tabPtr.i = takeOverPtr.p->toCurrentTabref; + ptrCheckGuard(tabPtr, ctabFileSize, tabRecord); + + FragmentstorePtr fragPtr; + getFragstore(tabPtr.p, takeOverPtr.p->toCurrentFragid, fragPtr); + Uint32 nodes[MAX_REPLICAS]; + extractNodeInfo(fragPtr.p, nodes); + + PrepareCopyFragReq* req= (PrepareCopyFragReq*)signal->getDataPtrSend(); + req->senderRef = reference(); + req->senderData = takeOverPtrI; + req->tableId = takeOverPtr.p->toCurrentTabref; + req->fragId = takeOverPtr.p->toCurrentFragid; + req->copyNodeId = nodes[0]; // Src + req->startingNodeId = takeOverPtr.p->toStartingNode; // Dst + Uint32 ref = calcLqhBlockRef(takeOverPtr.p->toStartingNode); + + sendSignal(ref, GSN_PREPARE_COPY_FRAG_REQ, signal, + PrepareCopyFragReq::SignalLength, JBB); + + takeOverPtr.p->toMasterStatus = TakeOverRecord::PREPARE_COPY; + return; + } + + takeOverPtr.p->maxPage = RNIL; + toStartCopyFrag(signal, takeOverPtr); +} + +void +Dbdih::execPREPARE_COPY_FRAG_REF(Signal* signal) +{ + jamEntry(); + PrepareCopyFragRef ref = *(PrepareCopyFragRef*)signal->getDataPtr(); + + TakeOverRecordPtr takeOverPtr; + RETURN_IF_TAKE_OVER_INTERRUPTED(ref.senderData, takeOverPtr); + + ndbrequire(takeOverPtr.p->toMasterStatus == TakeOverRecord::PREPARE_COPY); + + /** + * Treat this as copy frag ref + */ + CopyFragRef * cfref = (CopyFragRef*)signal->getDataPtrSend(); + cfref->userPtr = ref.senderData; + cfref->startingNodeId = ref.startingNodeId; + cfref->errorCode = ref.errorCode; + cfref->tableId = ref.tableId; + cfref->fragId = ref.fragId; + cfref->sendingNodeId = ref.copyNodeId; + takeOverPtr.p->toMasterStatus = TakeOverRecord::COPY_FRAG; + execCOPY_FRAGREF(signal); +} + +void +Dbdih::execPREPARE_COPY_FRAG_CONF(Signal* signal) +{ + PrepareCopyFragConf conf = *(PrepareCopyFragConf*)signal->getDataPtr(); + + TakeOverRecordPtr takeOverPtr; + RETURN_IF_TAKE_OVER_INTERRUPTED(conf.senderData, takeOverPtr); + + Uint32 version = getNodeInfo(refToNode(conf.senderRef)).m_version; + if (ndb_check_prep_copy_frag_version(version) >= 2) + { + jam(); + takeOverPtr.p->maxPage = conf.maxPageNo; + } + else + { + jam(); + takeOverPtr.p->maxPage = RNIL; + } + toStartCopyFrag(signal, takeOverPtr); +} + +void +Dbdih::toStartCopyFrag(Signal* signal, TakeOverRecordPtr takeOverPtr) +{ CreateReplicaRecordPtr createReplicaPtr; createReplicaPtr.i = 0; ptrAss(createReplicaPtr, createReplicaRecord); @@ -3178,8 +3266,8 @@ void Dbdih::toCopyFragLab(Signal* signal, createReplicaPtr.p->hotSpareUse = true; createReplicaPtr.p->dataNodeId = takeOverPtr.p->toStartingNode; - prepareSendCreateFragReq(signal, takeOverPtrI); -}//Dbdih::toCopyFragLab() + prepareSendCreateFragReq(signal, takeOverPtr.i); +}//Dbdih::toStartCopy() void Dbdih::prepareSendCreateFragReq(Signal* signal, Uint32 takeOverPtrI) { @@ -3412,10 +3500,12 @@ void Dbdih::execCREATE_FRAGCONF(Signal* signal) copyFragReq->schemaVersion = tabPtr.p->schemaVersion; copyFragReq->distributionKey = fragPtr.p->distributionKey; copyFragReq->gci = gci; - copyFragReq->nodeCount = extractNodeInfo(fragPtr.p, - copyFragReq->nodeList); + Uint32 len = copyFragReq->nodeCount = + extractNodeInfo(fragPtr.p, + copyFragReq->nodeList); + copyFragReq->nodeList[len] = takeOverPtr.p->maxPage; sendSignal(ref, GSN_COPY_FRAGREQ, signal, - CopyFragReq::SignalLength + copyFragReq->nodeCount, JBB); + CopyFragReq::SignalLength + len, JBB); } else { ndbrequire(takeOverPtr.p->toMasterStatus == TakeOverRecord::COMMIT_CREATE); jam(); @@ -4576,13 +4666,22 @@ void Dbdih::checkTakeOverInMasterStartNodeFailure(Signal* signal, ok = true; jam(); //----------------------------------------------------------------------- - // The starting node will discover the problem. We will receive either + // The copying node will discover the problem. We will receive either // COPY_FRAGREQ or COPY_FRAGCONF and then we can release the take over // record and end the process. If the copying node should also die then // we will try to send prepare create fragment and will then discover // that the starting node has failed. //----------------------------------------------------------------------- break; + case TakeOverRecord::PREPARE_COPY: + ok = true; + jam(); + /** + * We're waiting for the starting node...which just died... + * endTakeOver + */ + endTakeOver(takeOverPtr.i); + break; case TakeOverRecord::COPY_ACTIVE: ok = true; jam(); @@ -5069,6 +5168,18 @@ void Dbdih::startRemoveFailedNode(Signal* signal, NodeRecordPtr failedNodePtr) return; } + /** + * If node has node complete LCP + * we need to remove it as undo might not be complete + * bug#31257 + */ + failedNodePtr.p->m_remove_node_from_table_lcp_id = RNIL; + if (c_lcpState.m_LCP_COMPLETE_REP_Counter_LQH.isWaitingFor(failedNodePtr.i)) + { + jam(); + failedNodePtr.p->m_remove_node_from_table_lcp_id = SYSFILE->latestLCP_ID; + } + jam(); signal->theData[0] = DihContinueB::ZREMOVE_NODE_FROM_TABLE; signal->theData[1] = failedNodePtr.i; @@ -5710,6 +5821,11 @@ void Dbdih::removeNodeFromTable(Signal* signal, return; }//if + NodeRecordPtr nodePtr; + nodePtr.i = nodeId; + ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRecord); + const Uint32 lcpId = nodePtr.p->m_remove_node_from_table_lcp_id; + /** * For each fragment */ @@ -5717,7 +5833,6 @@ void Dbdih::removeNodeFromTable(Signal* signal, Uint32 noOfRemovedLcpReplicas = 0; // No of replicas in LCP removed Uint32 noOfRemainingLcpReplicas = 0;// No of replicas in LCP remaining - //const Uint32 lcpId = SYSFILE->latestLCP_ID; const bool lcpOngoingFlag = (tabPtr.p->tabLcpStatus== TabRecord::TLS_ACTIVE); const bool unlogged = (tabPtr.p->tabStorage != TabRecord::ST_NORMAL); @@ -5752,6 +5867,23 @@ void Dbdih::removeNodeFromTable(Signal* signal, noOfRemovedLcpReplicas ++; replicaPtr.p->lcpOngoingFlag = false; } + + if (lcpId != RNIL) + { + jam(); + Uint32 lcpNo = prevLcpNo(replicaPtr.p->nextLcp); + if (replicaPtr.p->lcpStatus[lcpNo] == ZVALID && + replicaPtr.p->lcpId[lcpNo] == SYSFILE->latestLCP_ID) + { + jam(); + replicaPtr.p->lcpStatus[lcpNo] = ZINVALID; + replicaPtr.p->lcpId[lcpNo] = 0; + replicaPtr.p->nextLcp = lcpNo; + ndbout_c("REMOVING lcp: %u from table: %u frag: %u node: %u", + SYSFILE->latestLCP_ID, + tabPtr.i, fragNo, nodeId); + } + } } } if (!found) @@ -10898,6 +11030,8 @@ void Dbdih::execLCP_COMPLETE_REP(Signal* signal) { jamEntry(); + CRASH_INSERTION(7191); + #if 0 g_eventLogger.info("LCP_COMPLETE_REP"); printLCP_COMPLETE_REP(stdout, @@ -13657,6 +13791,7 @@ void Dbdih::setLcpActiveStatusStart(Signal* signal) // It must be taken over with the copy fragment process after a system // crash. We indicate this by setting the active status to TAKE_OVER. /*-------------------------------------------------------------------*/ + c_lcpState.m_participatingLQH.set(nodePtr.i); nodePtr.p->activeStatus = Sysfile::NS_TakeOver; //break; // Fall through case Sysfile::NS_TakeOver:{ @@ -13699,6 +13834,7 @@ void Dbdih::setLcpActiveStatusStart(Signal* signal) break; case Sysfile::NS_ActiveMissed_2: jam(); + CRASH_INSERTION(7192); if ((nodePtr.p->nodeStatus == NodeRecord::ALIVE) && (!nodePtr.p->copyCompleted)) { jam(); diff --git a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index 6f8e5569831..95cad98b81c 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -2025,7 +2025,6 @@ public: Uint8 reclenAiLqhkey; Uint8 m_offset_current_keybuf; Uint8 replicaType; - Uint8 simpleRead; Uint8 seqNoReplica; Uint8 tcNodeFailrec; Uint8 m_disk_table; @@ -2145,6 +2144,7 @@ private: void execSTORED_PROCCONF(Signal* signal); void execSTORED_PROCREF(Signal* signal); void execCOPY_FRAGREQ(Signal* signal); + void execPREPARE_COPY_FRAG_REQ(Signal* signal); void execUPDATE_FRAG_DIST_KEY_ORD(Signal*); void execCOPY_ACTIVEREQ(Signal* signal); void execCOPY_STATEREQ(Signal* signal); diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp index d6411ee1cb9..db6d201575f 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp @@ -310,6 +310,9 @@ Dblqh::Dblqh(Block_context& ctx): addRecSignal(GSN_UPDATE_FRAG_DIST_KEY_ORD, &Dblqh::execUPDATE_FRAG_DIST_KEY_ORD); + addRecSignal(GSN_PREPARE_COPY_FRAG_REQ, + &Dblqh::execPREPARE_COPY_FRAG_REQ); + initData(); #ifdef VM_TRACE diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index efb88bfccd2..e0449e08ddd 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -3496,7 +3496,6 @@ void Dblqh::execLQHKEYREQ(Signal* signal) regTcPtr->dirtyOp = LqhKeyReq::getDirtyFlag(Treqinfo); regTcPtr->opExec = LqhKeyReq::getInterpretedFlag(Treqinfo); regTcPtr->opSimple = LqhKeyReq::getSimpleFlag(Treqinfo); - regTcPtr->simpleRead = op == ZREAD && regTcPtr->opSimple; regTcPtr->seqNoReplica = LqhKeyReq::getSeqNoReplica(Treqinfo); UintR TreclenAiLqhkey = LqhKeyReq::getAIInLqhKeyReq(Treqinfo); regTcPtr->apiVersionNo = 0; @@ -3513,9 +3512,15 @@ void Dblqh::execLQHKEYREQ(Signal* signal) regTcPtr->lockType = op == ZREAD_EX ? ZUPDATE : (Operation_t) op == ZWRITE ? ZINSERT : (Operation_t) op; } + + if (regTcPtr->dirtyOp) + { + ndbrequire(regTcPtr->opSimple); + } - CRASH_INSERTION2(5041, regTcPtr->simpleRead && - refToNode(signal->senderBlockRef()) != cownNodeid); + CRASH_INSERTION2(5041, (op == ZREAD && + (regTcPtr->opSimple || regTcPtr->dirtyOp) && + refToNode(signal->senderBlockRef()) != cownNodeid)); regTcPtr->reclenAiLqhkey = TreclenAiLqhkey; regTcPtr->currReclenAi = TreclenAiLqhkey; @@ -3665,6 +3670,7 @@ void Dblqh::execLQHKEYREQ(Signal* signal) { ndbout_c("fragptr.p->fragStatus: %d", fragptr.p->fragStatus); + CRASH_INSERTION(5046); } ndbassert(fragptr.p->fragStatus == Fragrecord::ACTIVE_CREATION); fragptr.p->m_copy_started_state = Fragrecord::AC_NR_COPY; @@ -3687,8 +3693,8 @@ void Dblqh::execLQHKEYREQ(Signal* signal) Uint8 TdistKey = LqhKeyReq::getDistributionKey(TtotReclenAi); if ((tfragDistKey != TdistKey) && (regTcPtr->seqNoReplica == 0) && - (regTcPtr->dirtyOp == ZFALSE) && - (regTcPtr->simpleRead == ZFALSE)) { + (regTcPtr->dirtyOp == 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 @@ -4778,7 +4784,18 @@ void Dblqh::tupkeyConfLab(Signal* signal) TRACE_OP(regTcPtr, "TUPKEYCONF"); - if (regTcPtr->simpleRead) { + if (readLen != 0) + { + jam(); + + /* SET BIT 15 IN REQINFO */ + LqhKeyReq::setApplicationAddressFlag(regTcPtr->reqinfo, 1); + regTcPtr->readlenAi = readLen; + }//if + + if (regTcPtr->operation == ZREAD && + (regTcPtr->opSimple || regTcPtr->dirtyOp)) + { jam(); /* ---------------------------------------------------------------------- * THE OPERATION IS A SIMPLE READ. @@ -4792,14 +4809,6 @@ void Dblqh::tupkeyConfLab(Signal* signal) commitContinueAfterBlockedLab(signal); return; }//if - if (readLen != 0) - { - jam(); - - /* SET BIT 15 IN REQINFO */ - LqhKeyReq::setApplicationAddressFlag(regTcPtr->reqinfo, 1); - regTcPtr->readlenAi = readLen; - }//if regTcPtr->totSendlenAi = writeLen; ndbrequire(regTcPtr->totSendlenAi == regTcPtr->currTupAiLen); @@ -5178,12 +5187,15 @@ void Dblqh::packLqhkeyreqLab(Signal* signal) /* */ /* ------------------------------------------------------------------------- */ sendLqhkeyconfTc(signal, regTcPtr->tcBlockref); - if (regTcPtr->dirtyOp != ZTRUE) { + if (! (regTcPtr->dirtyOp || + (regTcPtr->operation == ZREAD && regTcPtr->opSimple))) + { jam(); regTcPtr->transactionState = TcConnectionrec::PREPARED; releaseOprec(signal); } else { jam(); + /*************************************************************>*/ /* DIRTY WRITES ARE USED IN TWO SITUATIONS. THE FIRST */ /* SITUATION IS WHEN THEY ARE USED TO UPDATE COUNTERS AND*/ @@ -6406,8 +6418,8 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) Ptr<TcConnectionrec> regTcPtr = tcConnectptr; Ptr<Fragrecord> regFragptr = fragptr; Uint32 operation = regTcPtr.p->operation; - Uint32 simpleRead = regTcPtr.p->simpleRead; Uint32 dirtyOp = regTcPtr.p->dirtyOp; + Uint32 opSimple = regTcPtr.p->opSimple; if (regTcPtr.p->activeCreat != Fragrecord::AC_IGNORED) { if (operation != ZREAD) { TupCommitReq * const tupCommitReq = @@ -6465,20 +6477,29 @@ void Dblqh::commitContinueAfterBlockedLab(Signal* signal) EXECUTE_DIRECT(acc, GSN_ACC_COMMITREQ, signal, 1); } - if (simpleRead) { + if (dirtyOp) + { jam(); -/* ------------------------------------------------------------------------- */ -/*THE OPERATION WAS A SIMPLE READ THUS THE COMMIT PHASE IS ONLY NEEDED TO */ -/*RELEASE THE LOCKS. AT THIS POINT IN THE CODE THE LOCKS ARE RELEASED AND WE */ -/*ARE IN A POSITION TO SEND LQHKEYCONF TO TC. WE WILL ALSO RELEASE ALL */ -/*RESOURCES BELONGING TO THIS OPERATION SINCE NO MORE WORK WILL BE */ -/*PERFORMED. */ -/* ------------------------------------------------------------------------- */ + /** + * The dirtyRead does not send anything but TRANSID_AI from LDM + */ fragptr = regFragptr; tcConnectptr = regTcPtr; cleanUp(signal); return; - }//if + } + + /** + * The simpleRead will send a LQHKEYCONF + * but have already released the locks + */ + if (opSimple) + { + fragptr = regFragptr; + tcConnectptr = regTcPtr; + packLqhkeyreqLab(signal); + return; + } } }//if jamEntry(); @@ -7088,7 +7109,7 @@ void Dblqh::abortStateHandlerLab(Signal* signal) /* ------------------------------------------------------------------------- */ return; }//if - if (regTcPtr->simpleRead) { + if (regTcPtr->opSimple) { jam(); /* ------------------------------------------------------------------------- */ /*A SIMPLE READ IS CURRENTLY RELEASING THE LOCKS OR WAITING FOR ACCESS TO */ @@ -7356,7 +7377,8 @@ void Dblqh::continueAbortLab(Signal* signal) void Dblqh::continueAfterLogAbortWriteLab(Signal* signal) { TcConnectionrec * const regTcPtr = tcConnectptr.p; - if (regTcPtr->simpleRead) { + if (regTcPtr->operation == ZREAD && regTcPtr->dirtyOp) + { jam(); TcKeyRef * const tcKeyRef = (TcKeyRef *) signal->getDataPtrSend(); @@ -10062,6 +10084,86 @@ Dblqh::calculateHash(Uint32 tableId, const Uint32* src) return md5_hash(Tmp, keyLen); }//Dblqh::calculateHash() +/** + * PREPARE COPY FRAG REQ + */ +void +Dblqh::execPREPARE_COPY_FRAG_REQ(Signal* signal) +{ + jamEntry(); + PrepareCopyFragReq req = *(PrepareCopyFragReq*)signal->getDataPtr(); + + CRASH_INSERTION(5045); + + tabptr.i = req.tableId; + ptrCheckGuard(tabptr, ctabrecFileSize, tablerec); + + Uint32 max_page = RNIL; + + if (getOwnNodeId() != req.startingNodeId) + { + jam(); + /** + * This is currently dead code... + * but is provided so we can impl. a better scan+delete on + * starting node wo/ having to change running node + */ + ndbrequire(getOwnNodeId() == req.copyNodeId); + c_tup->get_frag_info(req.tableId, req.fragId, &max_page); + + PrepareCopyFragConf* conf = (PrepareCopyFragConf*)signal->getDataPtrSend(); + conf->senderData = req.senderData; + conf->senderRef = reference(); + conf->tableId = req.tableId; + conf->fragId = req.fragId; + conf->copyNodeId = req.copyNodeId; + conf->startingNodeId = req.startingNodeId; + conf->maxPageNo = max_page; + sendSignal(req.senderRef, GSN_PREPARE_COPY_FRAG_CONF, + signal, PrepareCopyFragConf::SignalLength, JBB); + + return; + } + + if (! DictTabInfo::isOrderedIndex(tabptr.p->tableType)) + { + jam(); + ndbrequire(getFragmentrec(signal, req.fragId)); + + /** + * + */ + if (cstartType == NodeState::ST_SYSTEM_RESTART) + { + jam(); + signal->theData[0] = fragptr.p->tabRef; + signal->theData[1] = fragptr.p->fragId; + sendSignal(DBACC_REF, GSN_EXPANDCHECK2, signal, 2, JBB); + } + + + /** + * + */ + fragptr.p->m_copy_started_state = Fragrecord::AC_IGNORED; + fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION; + fragptr.p->logFlag = Fragrecord::STATE_FALSE; + + c_tup->get_frag_info(req.tableId, req.fragId, &max_page); + } + + PrepareCopyFragConf* conf = (PrepareCopyFragConf*)signal->getDataPtrSend(); + conf->senderData = req.senderData; + conf->senderRef = reference(); + conf->tableId = req.tableId; + conf->fragId = req.fragId; + conf->copyNodeId = req.copyNodeId; + conf->startingNodeId = req.startingNodeId; + conf->maxPageNo = max_page; + sendSignal(req.senderRef, GSN_PREPARE_COPY_FRAG_CONF, + signal, PrepareCopyFragConf::SignalLength, JBB); +} + /* *************************************** */ /* COPY_FRAGREQ: Start copying a fragment */ /* *************************************** */ @@ -10097,6 +10199,13 @@ void Dblqh::execCOPY_FRAGREQ(Signal* signal) for (i = 0; i<nodeCount; i++) nodemask.set(copyFragReq->nodeList[i]); } + Uint32 maxPage = copyFragReq->nodeList[nodeCount]; + Uint32 version = getNodeInfo(refToNode(userRef)).m_version; + if (ndb_check_prep_copy_frag_version(version) < 2) + { + jam(); + maxPage = RNIL; + } if (DictTabInfo::isOrderedIndex(tabptr.p->tableType)) { jam(); @@ -10172,14 +10281,15 @@ void Dblqh::execCOPY_FRAGREQ(Signal* signal) req->requestInfo = 0; AccScanReq::setLockMode(req->requestInfo, 0); AccScanReq::setReadCommittedFlag(req->requestInfo, 0); - AccScanReq::setNRScanFlag(req->requestInfo, gci ? 1 : 0); + AccScanReq::setNRScanFlag(req->requestInfo, 1); AccScanReq::setNoDiskScanFlag(req->requestInfo, 1); req->transId1 = tcConnectptr.p->transid[0]; req->transId2 = tcConnectptr.p->transid[1]; req->savePointId = tcConnectptr.p->savePointId; + req->maxPage = maxPage; sendSignal(scanptr.p->scanBlockref, GSN_ACC_SCANREQ, signal, - AccScanReq::SignalLength, JBB); + AccScanReq::SignalLength + 1, JBB); if (! nodemask.isclear()) { @@ -14084,11 +14194,16 @@ void Dblqh::execSTART_FRAGREQ(Signal* signal) fragptr.p->fragStatus = Fragrecord::ACTIVE_CREATION; } - c_tup->disk_restart_mark_no_lcp(tabptr.i, fragId); + c_tup->disk_restart_lcp_id(tabptr.i, fragId, RNIL); jamEntry(); - return; - }//if + } + else + { + jam(); + c_tup->disk_restart_lcp_id(tabptr.i, fragId, lcpId); + jamEntry(); + } c_lcpId = (c_lcpId == 0 ? lcpId : c_lcpId); c_lcpId = (c_lcpId < lcpId ? c_lcpId : lcpId); @@ -19022,7 +19137,6 @@ Dblqh::execDUMP_STATE_ORD(Signal* signal) ndbout << " operation = " << tcRec.p->operation<<endl; ndbout << " tcNodeFailrec = " << tcRec.p->tcNodeFailrec << " seqNoReplica = " << tcRec.p->seqNoReplica - << " simpleRead = " << tcRec.p->simpleRead << endl; ndbout << " replicaType = " << tcRec.p->replicaType << " reclenAiLqhkey = " << tcRec.p->reclenAiLqhkey diff --git a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index 75d79ba737f..3d5e52a525d 100644 --- a/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -786,6 +786,7 @@ public: UintR apiConnect; /* POINTER TO API CONNECT RECORD */ UintR nextTcConnect; /* NEXT TC RECORD*/ Uint8 dirtyOp; + Uint8 opSimple; Uint8 lastReplicaNo; /* NUMBER OF THE LAST REPLICA IN THE OPERATION */ Uint8 noOfNodes; /* TOTAL NUMBER OF NODES IN OPERATION */ Uint8 operation; /* OPERATION TYPE */ @@ -886,13 +887,8 @@ public: Uint8 opExec; Uint8 unused; + Uint8 unused1; - /** - * IS THE OPERATION A SIMPLE TRANSACTION - * 0 = NO, 1 = YES - */ - Uint8 opSimple; - //--------------------------------------------------- // Second 16 byte cache line in second 64 byte cache // line. Diverse use. @@ -1464,7 +1460,7 @@ private: void releaseAttrinfo(); void releaseGcp(Signal* signal); void releaseKeys(); - void releaseSimpleRead(Signal*, ApiConnectRecordPtr, TcConnectRecord*); + void releaseDirtyRead(Signal*, ApiConnectRecordPtr, TcConnectRecord*); void releaseDirtyWrite(Signal* signal); void releaseTcCon(); void releaseTcConnectFail(Signal* signal); @@ -1620,7 +1616,7 @@ private: void startphase1x010Lab(Signal* signal); void lqhKeyConf_checkTransactionState(Signal * signal, - ApiConnectRecord * const regApiPtr); + Ptr<ApiConnectRecord> regApiPtr); void checkDropTab(Signal* signal); diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 887e6f848b1..ce20059e663 100644 --- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -20,6 +20,7 @@ #include <RefConvert.hpp> #include <ndb_limits.h> #include <my_sys.h> +#include <ndb_rand.h> #include <signaldata/EventReport.hpp> #include <signaldata/TcKeyReq.hpp> @@ -2790,9 +2791,9 @@ void Dbtc::execTCKEYREQ(Signal* signal) Uint8 TNoDiskFlag = TcKeyReq::getNoDiskFlag(Treqinfo); Uint8 TexecuteFlag = TexecFlag; - regCachePtr->opSimple = TSimpleFlag; - regCachePtr->opExec = TInterpretedFlag; regTcPtr->dirtyOp = TDirtyFlag; + regTcPtr->opSimple = TSimpleFlag; + regCachePtr->opExec = TInterpretedFlag; regCachePtr->distributionKeyIndicator = TDistrKeyFlag; regCachePtr->m_no_disk_flag = TNoDiskFlag; @@ -3246,9 +3247,10 @@ void Dbtc::sendlqhkeyreq(Signal* signal, LqhKeyReq::setScanTakeOverFlag(tslrAttrLen, regCachePtr->scanTakeOverInd); Tdata10 = 0; - sig0 = regCachePtr->opSimple; + sig0 = regTcPtr->opSimple; sig1 = regTcPtr->operation; - bool simpleRead = (sig1 == ZREAD && sig0 == ZTRUE); + sig2 = regTcPtr->dirtyOp; + bool dirtyRead = (sig1 == ZREAD && sig2 == ZTRUE); LqhKeyReq::setKeyLen(Tdata10, regCachePtr->keylen); LqhKeyReq::setLastReplicaNo(Tdata10, regTcPtr->lastReplicaNo); if (unlikely(version < NDBD_ROWID_VERSION)) @@ -3261,7 +3263,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal, // Indicate Application Reference is present in bit 15 /* ---------------------------------------------------------------------- */ LqhKeyReq::setApplicationAddressFlag(Tdata10, 1); - LqhKeyReq::setDirtyFlag(Tdata10, regTcPtr->dirtyOp); + LqhKeyReq::setDirtyFlag(Tdata10, sig2); LqhKeyReq::setInterpretedFlag(Tdata10, regCachePtr->opExec); LqhKeyReq::setSimpleFlag(Tdata10, sig0); LqhKeyReq::setOperation(Tdata10, sig1); @@ -3322,7 +3324,7 @@ void Dbtc::sendlqhkeyreq(Signal* signal, sig5 = regTcPtr->clientData; sig6 = regCachePtr->scanInfo; - if (! simpleRead) + if (! dirtyRead) { regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[0]); regApiPtr->m_transaction_nodes.set(regTcPtr->tcNodedata[1]); @@ -3395,7 +3397,6 @@ void Dbtc::packLqhkeyreq040Lab(Signal* signal, BlockReference TBRef) { TcConnectRecord * const regTcPtr = tcConnectptr.p; - CacheRecord * const regCachePtr = cachePtr.p; #ifdef ERROR_INSERT ApiConnectRecord * const regApiPtr = apiConnectptr.p; if (ERROR_INSERTED(8009)) { @@ -3420,8 +3421,8 @@ void Dbtc::packLqhkeyreq040Lab(Signal* signal, if (anAttrBufIndex == RNIL) { UintR TtcTimer = ctcTimer; UintR Tread = (regTcPtr->operation == ZREAD); - UintR Tsimple = (regCachePtr->opSimple == ZTRUE); - UintR Tboth = Tread & Tsimple; + UintR Tdirty = (regTcPtr->dirtyOp == ZTRUE); + UintR Tboth = Tread & Tdirty; setApiConTimer(apiConnectptr.i, TtcTimer, __LINE__); jam(); /*-------------------------------------------------------------------- @@ -3430,7 +3431,7 @@ void Dbtc::packLqhkeyreq040Lab(Signal* signal, releaseAttrinfo(); if (Tboth) { jam(); - releaseSimpleRead(signal, apiConnectptr, tcConnectptr.p); + releaseDirtyRead(signal, apiConnectptr, tcConnectptr.p); return; }//if regTcPtr->tcConnectstate = OS_OPERATING; @@ -3490,11 +3491,11 @@ void Dbtc::releaseAttrinfo() }//Dbtc::releaseAttrinfo() /* ========================================================================= */ -/* ------- RELEASE ALL RECORDS CONNECTED TO A SIMPLE OPERATION ------- */ +/* ------- RELEASE ALL RECORDS CONNECTED TO A DIRTY OPERATION ------- */ /* ========================================================================= */ -void Dbtc::releaseSimpleRead(Signal* signal, - ApiConnectRecordPtr regApiPtr, - TcConnectRecord* regTcPtr) +void Dbtc::releaseDirtyRead(Signal* signal, + ApiConnectRecordPtr regApiPtr, + TcConnectRecord* regTcPtr) { Uint32 Ttckeyrec = regApiPtr.p->tckeyrec; Uint32 TclientData = regTcPtr->clientData; @@ -3504,7 +3505,7 @@ void Dbtc::releaseSimpleRead(Signal* signal, ConnectionState state = regApiPtr.p->apiConnectstate; regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; - regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::SimpleReadBit | Tnode; + regApiPtr.p->tcSendArray[Ttckeyrec + 1] = TcKeyConf::DirtyReadBit | Tnode; regApiPtr.p->tckeyrec = Ttckeyrec + 2; unlinkReadyTcCon(signal); @@ -3534,8 +3535,8 @@ void Dbtc::releaseSimpleRead(Signal* signal, /** * Emulate LQHKEYCONF */ - lqhKeyConf_checkTransactionState(signal, regApiPtr.p); -}//Dbtc::releaseSimpleRead() + lqhKeyConf_checkTransactionState(signal, regApiPtr); +}//Dbtc::releaseDirtyRead() /* ------------------------------------------------------------------------- */ /* ------- CHECK IF ALL TC CONNECTIONS ARE COMPLETED ------- */ @@ -3717,12 +3718,13 @@ void Dbtc::execLQHKEYCONF(Signal* signal) TCKEY_abort(signal, 29); return; }//if - ApiConnectRecord * const regApiPtr = - &localApiConnectRecord[TapiConnectptrIndex]; + Ptr<ApiConnectRecord> regApiPtr; + regApiPtr.i = TapiConnectptrIndex; + regApiPtr.p = &localApiConnectRecord[TapiConnectptrIndex]; apiConnectptr.i = TapiConnectptrIndex; - apiConnectptr.p = regApiPtr; - compare_transid1 = regApiPtr->transid[0] ^ Ttrans1; - compare_transid2 = regApiPtr->transid[1] ^ Ttrans2; + apiConnectptr.p = regApiPtr.p; + compare_transid1 = regApiPtr.p->transid[0] ^ Ttrans1; + compare_transid2 = regApiPtr.p->transid[1] ^ Ttrans2; compare_transid1 = compare_transid1 | compare_transid2; if (compare_transid1 != 0) { warningReport(signal, 24); @@ -3734,25 +3736,25 @@ void Dbtc::execLQHKEYCONF(Signal* signal) systemErrorLab(signal, __LINE__); }//if if (ERROR_INSERTED(8003)) { - if (regApiPtr->apiConnectstate == CS_STARTED) { + if (regApiPtr.p->apiConnectstate == CS_STARTED) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8004)) { - if (regApiPtr->apiConnectstate == CS_RECEIVING) { + if (regApiPtr.p->apiConnectstate == CS_RECEIVING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8005)) { - if (regApiPtr->apiConnectstate == CS_REC_COMMITTING) { + if (regApiPtr.p->apiConnectstate == CS_REC_COMMITTING) { CLEAR_ERROR_INSERT_VALUE; return; }//if }//if if (ERROR_INSERTED(8006)) { - if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { + if (regApiPtr.p->apiConnectstate == CS_START_COMMITTING) { CLEAR_ERROR_INSERT_VALUE; return; }//if @@ -3767,10 +3769,12 @@ void Dbtc::execLQHKEYCONF(Signal* signal) regTcPtr->lastLqhNodeId = refToNode(tlastLqhBlockref); regTcPtr->noFiredTriggers = noFired; - UintR Ttckeyrec = (UintR)regApiPtr->tckeyrec; + UintR Ttckeyrec = (UintR)regApiPtr.p->tckeyrec; UintR TclientData = regTcPtr->clientData; UintR TdirtyOp = regTcPtr->dirtyOp; - ConnectionState TapiConnectstate = regApiPtr->apiConnectstate; + Uint32 TopSimple = regTcPtr->opSimple; + Uint32 Toperation = regTcPtr->operation; + ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate; if (Ttckeyrec > (ZTCOPCONF_SIZE - 2)) { TCKEY_abort(signal, 30); return; @@ -3795,23 +3799,34 @@ void Dbtc::execLQHKEYCONF(Signal* signal) * since they will enter execLQHKEYCONF a second time * Skip counting internally generated TcKeyReq */ - regApiPtr->tcSendArray[Ttckeyrec] = TclientData; - regApiPtr->tcSendArray[Ttckeyrec + 1] = treadlenAi; - regApiPtr->tckeyrec = Ttckeyrec + 2; + regApiPtr.p->tcSendArray[Ttckeyrec] = TclientData; + regApiPtr.p->tcSendArray[Ttckeyrec + 1] = treadlenAi; + regApiPtr.p->tckeyrec = Ttckeyrec + 2; }//if }//if - if (TdirtyOp == ZTRUE) { - UintR Tlqhkeyreqrec = regApiPtr->lqhkeyreqrec; + if (TdirtyOp == ZTRUE) + { + UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; jam(); releaseDirtyWrite(signal); - regApiPtr->lqhkeyreqrec = Tlqhkeyreqrec - 1; - } else { + regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1; + } + else if (Toperation == ZREAD && TopSimple) + { + UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; + jam(); + unlinkReadyTcCon(signal); + releaseTcCon(); + regApiPtr.p->lqhkeyreqrec = Tlqhkeyreqrec - 1; + } + else + { jam(); if (noFired == 0) { jam(); // No triggers to execute - UintR Tlqhkeyconfrec = regApiPtr->lqhkeyconfrec; - regApiPtr->lqhkeyconfrec = Tlqhkeyconfrec + 1; + UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec; + regApiPtr.p->lqhkeyconfrec = Tlqhkeyconfrec + 1; regTcPtr->tcConnectstate = OS_PREPARED; } }//if @@ -3841,21 +3856,18 @@ void Dbtc::execLQHKEYCONF(Signal* signal) jam(); if (regTcPtr->isIndexOp) { jam(); - setupIndexOpReturn(regApiPtr, regTcPtr); + setupIndexOpReturn(regApiPtr.p, regTcPtr); } lqhKeyConf_checkTransactionState(signal, regApiPtr); } else { // We have fired triggers jam(); saveTriggeringOpState(signal, regTcPtr); - if (regTcPtr->noReceivedTriggers == noFired) { - ApiConnectRecordPtr transPtr; - + if (regTcPtr->noReceivedTriggers == noFired) + { // We have received all data jam(); - transPtr.i = TapiConnectptrIndex; - transPtr.p = regApiPtr; - executeTriggers(signal, &transPtr); + executeTriggers(signal, ®ApiPtr); } // else wait for more trigger data } @@ -3879,7 +3891,7 @@ void Dbtc::setupIndexOpReturn(ApiConnectRecord* regApiPtr, */ void Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, - ApiConnectRecord * const apiConnectPtrP) + Ptr<ApiConnectRecord> regApiPtr) { /*---------------------------------------------------------------*/ /* IF THE COMMIT FLAG IS SET IN SIGNAL TCKEYREQ THEN DBTC HAS TO */ @@ -3890,9 +3902,9 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, /* FOR ALL OPERATIONS, AND THEN WAIT FOR THE API TO CONCLUDE THE */ /* TRANSACTION */ /*---------------------------------------------------------------*/ - ConnectionState TapiConnectstate = apiConnectPtrP->apiConnectstate; - UintR Tlqhkeyconfrec = apiConnectPtrP->lqhkeyconfrec; - UintR Tlqhkeyreqrec = apiConnectPtrP->lqhkeyreqrec; + ConnectionState TapiConnectstate = regApiPtr.p->apiConnectstate; + UintR Tlqhkeyconfrec = regApiPtr.p->lqhkeyconfrec; + UintR Tlqhkeyreqrec = regApiPtr.p->lqhkeyreqrec; int TnoOfOutStanding = Tlqhkeyreqrec - Tlqhkeyconfrec; switch (TapiConnectstate) { @@ -3902,11 +3914,11 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, diverify010Lab(signal); return; } else if (TnoOfOutStanding > 0) { - if (apiConnectPtrP->tckeyrec == ZTCOPCONF_SIZE) { + if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; - } else if (apiConnectPtrP->indexOpReturn) { + } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; @@ -3925,11 +3937,11 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, sendtckeyconf(signal, 2); return; } else { - if (apiConnectPtrP->tckeyrec == ZTCOPCONF_SIZE) { + if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; - } else if (apiConnectPtrP->indexOpReturn) { + } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; @@ -3939,11 +3951,11 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, return; case CS_REC_COMMITTING: if (TnoOfOutStanding > 0) { - if (apiConnectPtrP->tckeyrec == ZTCOPCONF_SIZE) { + if (regApiPtr.p->tckeyrec == ZTCOPCONF_SIZE) { jam(); sendtckeyconf(signal, 0); return; - } else if (apiConnectPtrP->indexOpReturn) { + } else if (regApiPtr.p->indexOpReturn) { jam(); sendtckeyconf(signal, 0); return; @@ -3960,7 +3972,7 @@ Dbtc::lqhKeyConf_checkTransactionState(Signal * signal, /* CONSISTING OF DIRTY WRITES AND ALL OF THOSE WERE */ /* COMPLETED. ENSURE TCKEYREC IS ZERO TO PREVENT ERRORS. */ /*---------------------------------------------------------------*/ - apiConnectPtrP->tckeyrec = 0; + regApiPtr.p->tckeyrec = 0; return; default: TCKEY_abort(signal, 46); @@ -4218,34 +4230,46 @@ void Dbtc::diverify010Lab(Signal* signal) jam(); systemErrorLab(signal, __LINE__); }//if - if (TfirstfreeApiConnectCopy != RNIL) { - seizeApiConnectCopy(signal); - regApiPtr->apiConnectstate = CS_PREPARE_TO_COMMIT; - /*----------------------------------------------------------------------- - * WE COME HERE ONLY IF THE TRANSACTION IS PREPARED ON ALL TC CONNECTIONS. - * THUS WE CAN START THE COMMIT PHASE BY SENDING DIVERIFY ON ALL TC - * CONNECTIONS AND THEN WHEN ALL DIVERIFYCONF HAVE BEEN RECEIVED THE - * COMMIT MESSAGE CAN BE SENT TO ALL INVOLVED PARTS. - *-----------------------------------------------------------------------*/ - EXECUTE_DIRECT(DBDIH, GSN_DIVERIFYREQ, signal, 1); - if (signal->theData[2] == 0) { - execDIVERIFYCONF(signal); + + if (regApiPtr->lqhkeyreqrec) + { + if (TfirstfreeApiConnectCopy != RNIL) { + seizeApiConnectCopy(signal); + regApiPtr->apiConnectstate = CS_PREPARE_TO_COMMIT; + /*----------------------------------------------------------------------- + * WE COME HERE ONLY IF THE TRANSACTION IS PREPARED ON ALL TC CONNECTIONS + * THUS WE CAN START THE COMMIT PHASE BY SENDING DIVERIFY ON ALL TC + * CONNECTIONS AND THEN WHEN ALL DIVERIFYCONF HAVE BEEN RECEIVED THE + * COMMIT MESSAGE CAN BE SENT TO ALL INVOLVED PARTS. + *---------------------------------------------------------------------*/ + EXECUTE_DIRECT(DBDIH, GSN_DIVERIFYREQ, signal, 1); + if (signal->theData[2] == 0) { + execDIVERIFYCONF(signal); + } + return; + } else { + /*----------------------------------------------------------------------- + * There were no free copy connections available. We must abort the + * transaction since otherwise we will have a problem with the report + * to the application. + * This should more or less not happen but if it happens we do + * not want to crash and we do not want to create code to handle it + * properly since it is difficult to test it and will be complex to + * handle a problem more or less not occurring. + *---------------------------------------------------------------------*/ + terrorCode = ZSEIZE_API_COPY_ERROR; + abortErrorLab(signal); + return; } - return; - } else { - /*----------------------------------------------------------------------- - * There were no free copy connections available. We must abort the - * transaction since otherwise we will have a problem with the report - * to the application. - * This should more or less not happen but if it happens we do not want to - * crash and we do not want to create code to handle it properly since - * it is difficult to test it and will be complex to handle a problem - * more or less not occurring. - *-----------------------------------------------------------------------*/ - terrorCode = ZSEIZE_API_COPY_ERROR; - abortErrorLab(signal); - return; - }//if + } + else + { + jam(); + sendtckeyconf(signal, 1); + regApiPtr->apiConnectstate = CS_CONNECTED; + regApiPtr->m_transaction_nodes.clear(); + setApiConTimer(apiConnectptr.i, 0,__LINE__); + } }//Dbtc::diverify010Lab() /* ------------------------------------------------------------------------- */ @@ -5260,16 +5284,8 @@ void Dbtc::execLQHKEYREF(Signal* signal) regApiPtr->lqhkeyreqrec--; if (regApiPtr->lqhkeyconfrec == regApiPtr->lqhkeyreqrec) { if (regApiPtr->apiConnectstate == CS_START_COMMITTING) { - if(regApiPtr->lqhkeyconfrec) { - jam(); - diverify010Lab(signal); - } else { - jam(); - sendtckeyconf(signal, 1); - regApiPtr->apiConnectstate = CS_CONNECTED; - regApiPtr->m_transaction_nodes.clear(); - setApiConTimer(apiConnectptr.i, 0,__LINE__); - } + jam(); + diverify010Lab(signal); return; } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) { jam(); @@ -6278,7 +6294,7 @@ void Dbtc::timeOutLoopStartLab(Signal* signal, Uint32 api_con_ptr) jam(); if (api_timer != 0) { Uint32 error= ZTIME_OUT_ERROR; - time_out_value= time_out_param + (api_con_ptr & mask_value); + time_out_value= time_out_param + (ndb_rand() & mask_value); if (unlikely(old_mask_value)) // abort during single user mode { apiConnectptr.i = api_con_ptr; @@ -6481,6 +6497,7 @@ void Dbtc::timeOutFoundLab(Signal* signal, Uint32 TapiConPtr, Uint32 errCode) return; case CS_WAIT_COMMIT_CONF: jam(); + CRASH_INSERTION(8053); tcConnectptr.i = apiConnectptr.p->currentTcConnect; ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); arrGuard(apiConnectptr.p->currentReplicaNo, MAX_REPLICAS); diff --git a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index f28687dca0d..45d124b8d7d 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -518,6 +518,7 @@ typedef Ptr<Fragoperrec> FragoperrecPtr; Uint32 m_savePointId; Uint32 m_scanGCI; }; + Uint32 m_endPage; // lock waited for or obtained and not yet passed to LQH Uint32 m_accLockOp; @@ -641,6 +642,8 @@ typedef Ptr<Fragoperrec> FragoperrecPtr; */ Page_request_list::Head m_page_requests[MAX_FREE_LIST]; + DLList<Page>::Head m_unmap_pages; + /** * Current extent */ @@ -702,7 +705,8 @@ struct Fragrecord { DLList<ScanOp>::Head m_scanList; - enum { UC_LCP = 1, UC_CREATE = 2 }; + enum { UC_LCP = 1, UC_CREATE = 2, UC_SET_LCP = 3 }; + Uint32 m_restore_lcp_id; Uint32 m_undo_complete; Uint32 m_tablespace_id; Uint32 m_logfile_group_id; @@ -1573,6 +1577,8 @@ public: void nr_delete_page_callback(Signal*, Uint32 op, Uint32 page); void nr_delete_log_buffer_callback(Signal*, Uint32 op, Uint32 page); + + bool get_frag_info(Uint32 tableId, Uint32 fragId, Uint32* maxPage); private: BLOCK_DEFINES(Dbtup); @@ -2830,7 +2836,7 @@ private: public: int disk_page_load_hook(Uint32 page_id); - void disk_page_unmap_callback(Uint32 page_id, Uint32 dirty_count); + void disk_page_unmap_callback(Uint32 when, Uint32 page, Uint32 dirty_count); int disk_restart_alloc_extent(Uint32 tableId, Uint32 fragId, const Local_key* key, Uint32 pages); @@ -2851,11 +2857,11 @@ public: Local_key m_key; }; - void disk_restart_mark_no_lcp(Uint32 table, Uint32 frag); + void disk_restart_lcp_id(Uint32 table, Uint32 frag, Uint32 lcpId); private: void disk_restart_undo_next(Signal*); - void disk_restart_undo_lcp(Uint32, Uint32, Uint32 flag); + void disk_restart_undo_lcp(Uint32, Uint32, Uint32 flag, Uint32 lcpId); void disk_restart_undo_callback(Signal* signal, Uint32, Uint32); void disk_restart_undo_alloc(Apply_undo*); void disk_restart_undo_update(Apply_undo*); diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index 87705232de2..8420e7f2bde 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -903,8 +903,10 @@ Dbtup::disk_page_set_dirty(PagePtr pagePtr) } void -Dbtup::disk_page_unmap_callback(Uint32 page_id, Uint32 dirty_count) +Dbtup::disk_page_unmap_callback(Uint32 when, + Uint32 page_id, Uint32 dirty_count) { + jamEntry(); Ptr<GlobalPage> gpage; m_global_page_pool.getPtr(gpage, page_id); PagePtr pagePtr; @@ -918,17 +920,9 @@ Dbtup::disk_page_unmap_callback(Uint32 page_id, Uint32 dirty_count) { return ; } - - Local_key key; - key.m_page_no = pagePtr.p->m_page_no; - key.m_file_no = pagePtr.p->m_file_no; - Uint32 idx = pagePtr.p->list_index; - ndbassert((idx & 0x8000) == 0); + Uint32 idx = pagePtr.p->list_index; - if (DBG_DISK) - ndbout << "disk_page_unmap_callback " << key << endl; - Ptr<Tablerec> tabPtr; tabPtr.i= pagePtr.p->m_table_id; ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); @@ -938,26 +932,89 @@ Dbtup::disk_page_unmap_callback(Uint32 page_id, Uint32 dirty_count) Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; - if (dirty_count == 0) + if (when == 0) { - Uint32 free = pagePtr.p->free_space; - Uint32 used = pagePtr.p->uncommitted_used_space; - ddassert(free >= used); - ddassert(alloc.calc_page_free_bits(free - used) == idx); + /** + * Before pageout + */ + jam(); + + if (DBG_DISK) + { + Local_key key; + key.m_page_no = pagePtr.p->m_page_no; + key.m_file_no = pagePtr.p->m_file_no; + ndbout << "disk_page_unmap_callback(before) " << key + << " cnt: " << dirty_count << " " << (idx & ~0x8000) << endl; + } + + ndbassert((idx & 0x8000) == 0); + + ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; + LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]); + LocalDLList<Page> list2(*pool, alloc.m_unmap_pages); + list.remove(pagePtr); + list2.add(pagePtr); + + if (dirty_count == 0) + { + jam(); + pagePtr.p->list_index = idx | 0x8000; + + Local_key key; + key.m_page_no = pagePtr.p->m_page_no; + key.m_file_no = pagePtr.p->m_file_no; + + Uint32 free = pagePtr.p->free_space; + Uint32 used = pagePtr.p->uncommitted_used_space; + ddassert(free >= used); + ddassert(alloc.calc_page_free_bits(free - used) == idx); + + Tablespace_client tsman(0, c_tsman, + fragPtr.p->fragTableId, + fragPtr.p->fragmentId, + fragPtr.p->m_tablespace_id); + + tsman.unmap_page(&key, idx); + jamEntry(); + } + } + else if (when == 1) + { + /** + * After page out + */ + jam(); + + Local_key key; + key.m_page_no = pagePtr.p->m_page_no; + key.m_file_no = pagePtr.p->m_file_no; + Uint32 real_free = pagePtr.p->free_space; + if (DBG_DISK) + { + ndbout << "disk_page_unmap_callback(after) " << key + << " cnt: " << dirty_count << " " << (idx & ~0x8000) << endl; + } + + ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; + LocalDLList<Page> list(*pool, alloc.m_unmap_pages); + list.remove(pagePtr); + Tablespace_client tsman(0, c_tsman, fragPtr.p->fragTableId, fragPtr.p->fragmentId, fragPtr.p->m_tablespace_id); - tsman.unmap_page(&key, idx); - jamEntry(); - pagePtr.p->list_index = idx | 0x8000; + if (DBG_DISK && alloc.calc_page_free_bits(real_free) != (idx & ~0x8000)) + { + ndbout << key + << " calc: " << alloc.calc_page_free_bits(real_free) + << " idx: " << (idx & ~0x8000) + << endl; + } + tsman.update_page_free_bits(&key, alloc.calc_page_free_bits(real_free)); } - - ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; - LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]); - list.remove(pagePtr); } void @@ -969,8 +1026,6 @@ Dbtup::disk_page_alloc(Signal* signal, Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; Uint64 lsn; - Uint32 old_free = pagePtr.p->free_space; - Uint32 old_bits= alloc.calc_page_free_bits(old_free); if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0) { ddassert(pagePtr.p->uncommitted_used_space > 0); @@ -988,20 +1043,6 @@ Dbtup::disk_page_alloc(Signal* signal, lsn= disk_page_undo_alloc(pagePtr.p, key, sz, gci, logfile_group_id); } - - Uint32 new_free = pagePtr.p->free_space; - Uint32 new_bits= alloc.calc_page_free_bits(new_free); - - if (old_bits != new_bits) - { - Tablespace_client tsman(signal, c_tsman, - fragPtrP->fragTableId, - fragPtrP->fragmentId, - fragPtrP->m_tablespace_id); - - tsman.update_page_free_bits(key, new_bits, lsn); - jamEntry(); - } } void @@ -1016,7 +1057,6 @@ Dbtup::disk_page_free(Signal *signal, Uint32 logfile_group_id= fragPtrP->m_logfile_group_id; Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; Uint32 old_free= pagePtr.p->free_space; - Uint32 old_bits= alloc.calc_page_free_bits(old_free); Uint32 sz; Uint64 lsn; @@ -1043,19 +1083,7 @@ Dbtup::disk_page_free(Signal *signal, } Uint32 new_free = pagePtr.p->free_space; - Uint32 new_bits = alloc.calc_page_free_bits(new_free); - if (old_bits != new_bits) - { - Tablespace_client tsman(signal, c_tsman, - fragPtrP->fragTableId, - fragPtrP->fragmentId, - fragPtrP->m_tablespace_id); - - tsman.update_page_free_bits(key, new_bits, lsn); - jamEntry(); - } - Uint32 ext = pagePtr.p->m_extent_info_ptr; Uint32 used = pagePtr.p->uncommitted_used_space; Uint32 old_idx = pagePtr.p->list_index; @@ -1341,15 +1369,23 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, case File_formats::Undofile::UNDO_LCP_FIRST: case File_formats::Undofile::UNDO_LCP: { + jam(); ndbrequire(len == 3); + Uint32 lcp = ptr[0]; Uint32 tableId = ptr[1] >> 16; Uint32 fragId = ptr[1] & 0xFFFF; - disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_LCP); + disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_LCP, lcp); disk_restart_undo_next(signal); + + if (DBG_UNDO) + { + ndbout_c("UNDO LCP %u (%u, %u)", lcp, tableId, fragId); + } return; } case File_formats::Undofile::UNDO_TUP_ALLOC: { + jam(); Disk_undo::Alloc* rec= (Disk_undo::Alloc*)ptr; preq.m_page.m_page_no = rec->m_page_no; preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; @@ -1358,6 +1394,7 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, } case File_formats::Undofile::UNDO_TUP_UPDATE: { + jam(); Disk_undo::Update* rec= (Disk_undo::Update*)ptr; preq.m_page.m_page_no = rec->m_page_no; preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; @@ -1366,6 +1403,7 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, } case File_formats::Undofile::UNDO_TUP_FREE: { + jam(); Disk_undo::Free* rec= (Disk_undo::Free*)ptr; preq.m_page.m_page_no = rec->m_page_no; preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; @@ -1377,6 +1415,7 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, * */ { + jam(); Disk_undo::Create* rec= (Disk_undo::Create*)ptr; Ptr<Tablerec> tabPtr; tabPtr.i= rec->m_table; @@ -1384,12 +1423,34 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++) if (tabPtr.p->fragrec[i] != RNIL) disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i], - Fragrecord::UC_CREATE); + Fragrecord::UC_CREATE, 0); disk_restart_undo_next(signal); + + if (DBG_UNDO) + { + ndbout_c("UNDO CREATE (%u)", tabPtr.i); + } return; } case File_formats::Undofile::UNDO_TUP_DROP: + { jam(); + Disk_undo::Drop* rec = (Disk_undo::Drop*)ptr; + Ptr<Tablerec> tabPtr; + tabPtr.i= rec->m_table; + ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); + for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++) + if (tabPtr.p->fragrec[i] != RNIL) + disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i], + Fragrecord::UC_CREATE, 0); + disk_restart_undo_next(signal); + + if (DBG_UNDO) + { + ndbout_c("UNDO DROP (%u)", tabPtr.i); + } + return; + } case File_formats::Undofile::UNDO_TUP_ALLOC_EXTENT: jam(); case File_formats::Undofile::UNDO_TUP_FREE_EXTENT: @@ -1398,6 +1459,7 @@ Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, return; case File_formats::Undofile::UNDO_END: + jam(); f_undo_done = true; return; default: @@ -1431,14 +1493,32 @@ Dbtup::disk_restart_undo_next(Signal* signal) } void -Dbtup::disk_restart_mark_no_lcp(Uint32 tableId, Uint32 fragId) +Dbtup::disk_restart_lcp_id(Uint32 tableId, Uint32 fragId, Uint32 lcpId) { jamEntry(); - disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_CREATE); + + if (lcpId == RNIL) + { + disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_CREATE, 0); + if (DBG_UNDO) + { + ndbout_c("mark_no_lcp (%u, %u)", tableId, fragId); + } + } + else + { + disk_restart_undo_lcp(tableId, fragId, Fragrecord::UC_SET_LCP, lcpId); + if (DBG_UNDO) + { + ndbout_c("mark_no_lcp (%u, %u)", tableId, fragId); + } + + } } void -Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId, Uint32 flag) +Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId, Uint32 flag, + Uint32 lcpId) { Ptr<Tablerec> tabPtr; tabPtr.i= tableId; @@ -1446,11 +1526,43 @@ Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId, Uint32 flag) if (tabPtr.p->tableStatus == DEFINED) { + jam(); FragrecordPtr fragPtr; getFragmentrec(fragPtr, fragId, tabPtr.p); if (!fragPtr.isNull()) { - fragPtr.p->m_undo_complete |= flag; + jam(); + switch(flag){ + case Fragrecord::UC_CREATE: + jam(); + fragPtr.p->m_undo_complete |= flag; + return; + case Fragrecord::UC_LCP: + jam(); + if (fragPtr.p->m_undo_complete == 0 && + fragPtr.p->m_restore_lcp_id == lcpId) + { + jam(); + fragPtr.p->m_undo_complete |= flag; + if (DBG_UNDO) + ndbout_c("table: %u fragment: %u lcp: %u -> done", + tableId, fragId, lcpId); + } + return; + case Fragrecord::UC_SET_LCP: + { + jam(); + if (DBG_UNDO) + ndbout_c("table: %u fragment: %u restore to lcp: %u", + tableId, fragId, lcpId); + ndbrequire(fragPtr.p->m_undo_complete == 0); + ndbrequire(fragPtr.p->m_restore_lcp_id == RNIL); + fragPtr.p->m_restore_lcp_id = lcpId; + return; + } + } + jamLine(flag); + ndbrequire(false); } } } @@ -1474,6 +1586,7 @@ Dbtup::disk_restart_undo_callback(Signal* signal, pagePtr.p->nextList != RNIL || pagePtr.p->prevList != RNIL) { + jam(); update = true; pagePtr.p->list_index |= 0x8000; pagePtr.p->nextList = pagePtr.p->prevList = RNIL; @@ -1484,6 +1597,9 @@ Dbtup::disk_restart_undo_callback(Signal* signal, if (tableId >= cnoOfTablerec) { + jam(); + if (DBG_UNDO) + ndbout_c("UNDO table> %u", tableId); disk_restart_undo_next(signal); return; } @@ -1492,6 +1608,9 @@ Dbtup::disk_restart_undo_callback(Signal* signal, if (undo->m_table_ptr.p->tableStatus != DEFINED) { + jam(); + if (DBG_UNDO) + ndbout_c("UNDO !defined (%u) ", tableId); disk_restart_undo_next(signal); return; } @@ -1499,19 +1618,25 @@ Dbtup::disk_restart_undo_callback(Signal* signal, getFragmentrec(undo->m_fragment_ptr, fragId, undo->m_table_ptr.p); if(undo->m_fragment_ptr.isNull()) { + jam(); + if (DBG_UNDO) + ndbout_c("UNDO fragment null %u/%u", tableId, fragId); disk_restart_undo_next(signal); return; } if (undo->m_fragment_ptr.p->m_undo_complete) { + jam(); + if (DBG_UNDO) + ndbout_c("UNDO undo complete %u/%u", tableId, fragId); disk_restart_undo_next(signal); return; } - Local_key key; - key.m_page_no = pagePtr.p->m_page_no; - key.m_file_no = pagePtr.p->m_file_no; + Local_key key = undo->m_key; +// key.m_page_no = pagePtr.p->m_page_no; +// key.m_file_no = pagePtr.p->m_file_no; Uint64 lsn = 0; lsn += pagePtr.p->m_page_header.m_page_lsn_hi; lsn <<= 32; @@ -1521,6 +1646,7 @@ Dbtup::disk_restart_undo_callback(Signal* signal, if (undo->m_lsn <= lsn) { + jam(); if (DBG_UNDO) { ndbout << "apply: " << undo->m_lsn << "(" << lsn << " )" @@ -1535,12 +1661,15 @@ Dbtup::disk_restart_undo_callback(Signal* signal, */ switch(undo->m_type){ case File_formats::Undofile::UNDO_TUP_ALLOC: + jam(); disk_restart_undo_alloc(undo); break; case File_formats::Undofile::UNDO_TUP_UPDATE: + jam(); disk_restart_undo_update(undo); break; case File_formats::Undofile::UNDO_TUP_FREE: + jam(); disk_restart_undo_free(undo); break; default: @@ -1555,14 +1684,17 @@ Dbtup::disk_restart_undo_callback(Signal* signal, m_pgman.update_lsn(undo->m_key, lsn); jamEntry(); + + disk_restart_undo_page_bits(signal, undo); } else if (DBG_UNDO) { + jam(); ndbout << "ignore: " << undo->m_lsn << "(" << lsn << " )" - << key << " type: " << undo->m_type << endl; + << key << " type: " << undo->m_type + << " tab: " << tableId << endl; } - disk_restart_undo_page_bits(signal, undo); disk_restart_undo_next(signal); } @@ -1637,16 +1769,12 @@ Dbtup::disk_restart_undo_page_bits(Signal* signal, Apply_undo* undo) Uint32 new_bits = alloc.calc_page_free_bits(free); pageP->list_index = 0x8000 | new_bits; - Uint64 lsn = 0; - lsn += pageP->m_page_header.m_page_lsn_hi; lsn <<= 32; - lsn += pageP->m_page_header.m_page_lsn_lo; - Tablespace_client tsman(signal, c_tsman, fragPtrP->fragTableId, fragPtrP->fragmentId, fragPtrP->m_tablespace_id); - tsman.restart_undo_page_free_bits(&undo->m_key, new_bits, undo->m_lsn, lsn); + tsman.restart_undo_page_free_bits(&undo->m_key, new_bits); jamEntry(); } @@ -1683,6 +1811,7 @@ Dbtup::disk_restart_alloc_extent(Uint32 tableId, Uint32 fragId, if (alloc.m_curr_extent_info_ptr_i != RNIL) { + jam(); Ptr<Extent_info> old; c_extent_pool.getPtr(old, alloc.m_curr_extent_info_ptr_i); ndbassert(old.p->m_free_matrix_pos == RNIL); @@ -1709,6 +1838,7 @@ void Dbtup::disk_restart_page_bits(Uint32 tableId, Uint32 fragId, const Local_key*, Uint32 bits) { + jam(); TablerecPtr tabPtr; FragrecordPtr fragPtr; tabPtr.i = tableId; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 45766e5e9c4..a642d704eb9 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1957,9 +1957,8 @@ int Dbtup::interpreterNextLab(Signal* signal, Uint32 TdataForUpdate[3]; Uint32 Tlen; - AttributeHeader& ah= AttributeHeader::init(&TdataForUpdate[0], - TattrId, - TattrNoOfWords << 2); + AttributeHeader ah(TattrId, TattrNoOfWords << 2); + TdataForUpdate[0]= ah.m_value; TdataForUpdate[1]= TregMemBuffer[theRegister + 2]; TdataForUpdate[2]= TregMemBuffer[theRegister + 3]; Tlen= TattrNoOfWords + 1; @@ -1975,6 +1974,7 @@ int Dbtup::interpreterNextLab(Signal* signal, // Write a NULL value into the attribute /* --------------------------------------------------------- */ ah.setNULL(); + TdataForUpdate[0]= ah.m_value; Tlen= 1; } int TnoDataRW= updateAttributes(req_struct, diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp index 6866236f15e..176efac8058 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp @@ -143,6 +143,7 @@ void Dbtup::execTUPFRAGREQ(Signal* signal) regFragPtr.p->m_lcp_scan_op = RNIL; regFragPtr.p->m_lcp_keep_list = RNIL; regFragPtr.p->m_var_page_chunks = RNIL; + regFragPtr.p->m_restore_lcp_id = RNIL; if (ERROR_INSERTED(4007) && regTabPtr.p->fragid[0] == fragId || ERROR_INSERTED(4008) && regTabPtr.p->fragid[1] == fragId) { @@ -674,11 +675,11 @@ Dbtup::undo_createtable_callback(Signal* signal, Uint32 opPtrI, Uint32 unused) switch(ret){ case 0: return; + case -1: + warningEvent("Failed to sync log for create of table: %u", regTabPtr.i); default: - ndbout_c("ret: %d", ret); - ndbrequire(false); + execute(signal, req.m_callback, regFragPtr.p->m_logfile_group_id); } - } void @@ -959,8 +960,6 @@ void Dbtup::releaseFragment(Signal* signal, Uint32 tableId, return; } -#if NOT_YET_UNDO_DROP_TABLE -#error "This code is complete, but I prefer not to enable it until I need it" if (logfile_group_id != RNIL) { Callback cb; @@ -968,8 +967,15 @@ void Dbtup::releaseFragment(Signal* signal, Uint32 tableId, cb.m_callbackFunction = safe_cast(&Dbtup::drop_table_log_buffer_callback); Uint32 sz= sizeof(Disk_undo::Drop) >> 2; - (void) c_lgman->alloc_log_space(logfile_group_id, sz); - + int r0 = c_lgman->alloc_log_space(logfile_group_id, sz); + if (r0) + { + jam(); + warningEvent("Failed to alloc log space for drop table: %u", + tabPtr.i); + goto done; + } + Logfile_client lgman(this, c_lgman, logfile_group_id); int res= lgman.get_log_buffer(signal, sz, &cb); switch(res){ @@ -977,15 +983,18 @@ void Dbtup::releaseFragment(Signal* signal, Uint32 tableId, jam(); return; case -1: - ndbrequire("NOT YET IMPLEMENTED" == 0); + warningEvent("Failed to get log buffer for drop table: %u", + tabPtr.i); + c_lgman->free_log_space(logfile_group_id, sz); + goto done; break; default: execute(signal, cb, logfile_group_id); return; } } -#endif - + +done: drop_table_logsync_callback(signal, tabPtr.i, RNIL); } @@ -997,7 +1006,20 @@ Dbtup::drop_fragment_unmap_pages(Signal *signal, { if (tabPtr.p->m_no_of_disk_attributes) { + jam(); Disk_alloc_info& alloc_info= fragPtr.p->m_disk_alloc_info; + + if (!alloc_info.m_unmap_pages.isEmpty()) + { + jam(); + ndbout_c("waiting for unmape pages"); + signal->theData[0] = ZUNMAP_PAGES; + signal->theData[1] = tabPtr.i; + signal->theData[2] = fragPtr.i; + signal->theData[3] = pos; + sendSignal(cownref, GSN_CONTINUEB, signal, 4, JBB); + return; + } while(alloc_info.m_dirty_pages[pos].isEmpty() && pos < MAX_FREE_LIST) pos++; @@ -1164,9 +1186,10 @@ Dbtup::drop_table_log_buffer_callback(Signal* signal, Uint32 tablePtrI, switch(ret){ case 0: return; + case -1: + warningEvent("Failed to syn log for drop of table: %u", tablePtrI); default: - ndbout_c("ret: %d", ret); - ndbrequire(false); + execute(signal, req.m_callback, logfile_group_id); } } @@ -1441,3 +1464,22 @@ Dbtup::complete_restore_lcp(Uint32 tableId, Uint32 fragId) tabDesc += 2; } } + +bool +Dbtup::get_frag_info(Uint32 tableId, Uint32 fragId, Uint32* maxPage) +{ + jamEntry(); + TablerecPtr tabPtr; + tabPtr.i= tableId; + ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); + + FragrecordPtr fragPtr; + getFragmentrec(fragPtr, fragId, tabPtr.p); + + if (maxPage) + { + * maxPage = fragPtr.p->noOfPages; + } + + return true; +} diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index b0b0cec6b76..64f81dc11ab 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -818,9 +818,7 @@ Dbtup::checkUpdateOfPrimaryKey(KeyReqStruct* req_struct, Tablerec* const regTabPtr) { Uint32 keyReadBuffer[MAX_KEY_SIZE_IN_WORDS]; - Uint32 attributeHeader; TableDescriptor* attr_descr = req_struct->attr_descr; - AttributeHeader* ahOut = (AttributeHeader*)&attributeHeader; AttributeHeader ahIn(*updateBuffer); Uint32 attributeId = ahIn.getAttributeId(); Uint32 attrDescriptorIndex = attributeId << ZAD_LOG_SIZE; @@ -843,7 +841,7 @@ Dbtup::checkUpdateOfPrimaryKey(KeyReqStruct* req_struct, ReadFunction f = regTabPtr->readFunctionArray[attributeId]; - AttributeHeader::init(&attributeHeader, attributeId, 0); + AttributeHeader attributeHeader(attributeId, 0); req_struct->out_buf_index = 0; req_struct->max_read = MAX_KEY_SIZE_IN_WORDS; req_struct->attr_descriptor = attrDescriptor; @@ -852,12 +850,12 @@ Dbtup::checkUpdateOfPrimaryKey(KeyReqStruct* req_struct, req_struct->xfrm_flag = true; ndbrequire((this->*f)(&keyReadBuffer[0], req_struct, - ahOut, + &attributeHeader, attributeOffset)); req_struct->xfrm_flag = tmp; - ndbrequire(req_struct->out_buf_index == ahOut->getDataSize()); - if (ahIn.getDataSize() != ahOut->getDataSize()) { + ndbrequire(req_struct->out_buf_index == attributeHeader.getDataSize()); + if (ahIn.getDataSize() != attributeHeader.getDataSize()) { jam(); return true; } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp index 6e53531e118..5e9306909b4 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp @@ -95,7 +95,23 @@ Dbtup::execACC_SCANREQ(Signal* signal) } } - bits |= AccScanReq::getNRScanFlag(req->requestInfo) ? ScanOp::SCAN_NR : 0; + if (AccScanReq::getNRScanFlag(req->requestInfo)) + { + jam(); + bits |= ScanOp::SCAN_NR; + scanPtr.p->m_endPage = req->maxPage; + if (req->maxPage != RNIL && req->maxPage > frag.noOfPages) + { + ndbout_c("%u %u endPage: %u (noOfPages: %u)", + tablePtr.i, fragId, + req->maxPage, fragPtr.p->noOfPages); + } + } + else + { + jam(); + scanPtr.p->m_endPage = RNIL; + } // set up scan op new (scanPtr.p) ScanOp(); @@ -540,7 +556,7 @@ Dbtup::scanFirst(Signal*, ScanOpPtr scanPtr) ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); Fragrecord& frag = *fragPtr.p; // in the future should not pre-allocate pages - if (frag.noOfPages == 0) { + if (frag.noOfPages == 0 && ((bits & ScanOp::SCAN_NR) == 0)) { jam(); scan.m_state = ScanOp::Last; return; @@ -632,11 +648,23 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) key.m_page_no++; if (key.m_page_no >= frag.noOfPages) { jam(); + + if ((bits & ScanOp::SCAN_NR) && (scan.m_endPage != RNIL)) + { + jam(); + if (key.m_page_no < scan.m_endPage) + { + jam(); + ndbout_c("scanning page %u", key.m_page_no); + goto cont; + } + } // no more pages, scan ends pos.m_get = ScanPos::Get_undef; scan.m_state = ScanOp::Last; return true; } + cont: key.m_page_idx = 0; pos.m_get = ScanPos::Get_page_mm; // clear cached value @@ -649,7 +677,13 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) { if (pos.m_realpid_mm == RNIL) { jam(); - pos.m_realpid_mm = getRealpid(fragPtr.p, key.m_page_no); + if (key.m_page_no < frag.noOfPages) + pos.m_realpid_mm = getRealpid(fragPtr.p, key.m_page_no); + else + { + ndbassert(bits & ScanOp::SCAN_NR); + goto nopage; + } } PagePtr pagePtr; c_page_pool.getPtr(pagePtr, pos.m_realpid_mm); @@ -657,9 +691,18 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) if (pagePtr.p->page_state == ZEMPTY_MM) { // skip empty page jam(); - pos.m_get = ScanPos::Get_next_page_mm; - break; // incr loop count + if (! (bits & ScanOp::SCAN_NR)) + { + pos.m_get = ScanPos::Get_next_page_mm; + break; // incr loop count + } + else + { + jam(); + pos.m_realpid_mm = RNIL; + } } + nopage: pos.m_page = pagePtr.p; pos.m_get = ScanPos::Get_tuple; } @@ -772,7 +815,7 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) uncommitted = committed = ~(unsigned)0; int ret = tsman.get_page_free_bits(&key, &uncommitted, &committed); ndbrequire(ret == 0); - if (committed == 0) { + if (committed == 0 && uncommitted == 0) { // skip empty page jam(); pos.m_get = ScanPos::Get_next_page_dd; @@ -820,11 +863,11 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) { pos.m_get = ScanPos::Get_next_tuple_fs; th = (Tuple_header*)&page->m_data[key.m_page_idx]; - thbits = th->m_header_bits; if (likely(! (bits & ScanOp::SCAN_NR))) { jam(); + thbits = th->m_header_bits; if (! (thbits & Tuple_header::FREE)) { goto found_tuple; @@ -832,7 +875,15 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) } else { - if ((foundGCI = *th->get_mm_gci(tablePtr.p)) > scanGCI) + if (pos.m_realpid_mm == RNIL) + { + jam(); + foundGCI = 0; + goto found_deleted_rowid; + } + thbits = th->m_header_bits; + if ((foundGCI = *th->get_mm_gci(tablePtr.p)) > scanGCI || + foundGCI == 0) { if (! (thbits & Tuple_header::FREE)) { @@ -904,7 +955,8 @@ Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) Fix_page *mmpage = (Fix_page*)c_page_pool.getPtr(pos.m_realpid_mm); th = (Tuple_header*)(mmpage->m_data + key_mm.m_page_idx); - if ((foundGCI = *th->get_mm_gci(tablePtr.p)) > scanGCI) + if ((foundGCI = *th->get_mm_gci(tablePtr.p)) > scanGCI || + foundGCI == 0) { if (! (thbits & Tuple_header::FREE)) break; diff --git a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp index 550e255061f..f34bc41af06 100644 --- a/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp +++ b/storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp @@ -1169,9 +1169,7 @@ DbUtil::prepareOperation(Signal* signal, PreparePtr prepPtr) /************************************************************** * Attribute found - store in mapping (AttributeId, Position) **************************************************************/ - AttributeHeader & attrMap = - AttributeHeader::init(attrMappingIt.data, - attrDesc.AttributeId, // 1. Store AttrId + AttributeHeader attrMap(attrDesc.AttributeId, // 1. Store AttrId 0); if (attrDesc.AttributeKeyFlag) { @@ -1200,6 +1198,7 @@ DbUtil::prepareOperation(Signal* signal, PreparePtr prepPtr) return; } } + *(attrMappingIt.data) = attrMap.m_value; #if 0 ndbout << "BEFORE: attrLength: " << attrLength << endl; #endif diff --git a/storage/ndb/src/kernel/blocks/lgman.cpp b/storage/ndb/src/kernel/blocks/lgman.cpp index 23738717580..0481f7b399b 100644 --- a/storage/ndb/src/kernel/blocks/lgman.cpp +++ b/storage/ndb/src/kernel/blocks/lgman.cpp @@ -2701,8 +2701,16 @@ Lgman::execute_undo_record(Signal* signal) Uint32 lcp = * (ptr - len + 1); if(m_latest_lcp && lcp > m_latest_lcp) { - // Just ignore - break; + if (0) + { + const Uint32 * base = ptr - len + 1; + Uint32 lcp = base[0]; + Uint32 tableId = base[1] >> 16; + Uint32 fragId = base[1] & 0xFFFF; + + ndbout_c("NOT! ignoring lcp: %u tab: %u frag: %u", + lcp, tableId, fragId); + } } if(m_latest_lcp == 0 || diff --git a/storage/ndb/src/kernel/blocks/pgman.cpp b/storage/ndb/src/kernel/blocks/pgman.cpp index d8e0c053984..aa1f04c720c 100644 --- a/storage/ndb/src/kernel/blocks/pgman.cpp +++ b/storage/ndb/src/kernel/blocks/pgman.cpp @@ -238,6 +238,13 @@ Pgman::execCONTINUEB(Signal* signal) } else { + if (ERROR_INSERTED(11007)) + { + ndbout << "No more writes..." << endl; + SET_ERROR_INSERT_VALUE(11008); + signal->theData[0] = 9999; + sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 10000, 1); + } signal->theData[0] = m_end_lcp_req.senderData; sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB); } @@ -493,6 +500,11 @@ Pgman::release_page_entry(Ptr<Page_entry>& ptr) if (! (state & Page_entry::LOCKED)) ndbrequire(! (state & Page_entry::REQUEST)); + + if (ptr.p->m_copy_page_i != RNIL) + { + m_global_page_pool.release(ptr.p->m_copy_page_i); + } set_page_state(ptr, 0); m_page_hashlist.remove(ptr); @@ -1142,7 +1154,8 @@ Pgman::process_cleanup(Signal* signal) #ifdef VM_TRACE debugOut << "PGMAN: " << ptr << " : process_cleanup" << endl; #endif - c_tup->disk_page_unmap_callback(ptr.p->m_real_page_i, + c_tup->disk_page_unmap_callback(0, + ptr.p->m_real_page_i, ptr.p->m_dirty_count); pageout(signal, ptr); max_count--; @@ -1180,6 +1193,11 @@ Pgman::move_cleanup_ptr(Ptr<Page_entry> ptr) void Pgman::execLCP_FRAG_ORD(Signal* signal) { + if (ERROR_INSERTED(11008)) + { + ndbout_c("Ignore LCP_FRAG_ORD"); + return; + } LcpFragOrd* ord = (LcpFragOrd*)signal->getDataPtr(); ndbrequire(ord->lcpId >= m_last_lcp_complete + 1 || m_last_lcp_complete == 0); m_last_lcp = ord->lcpId; @@ -1196,6 +1214,12 @@ Pgman::execLCP_FRAG_ORD(Signal* signal) void Pgman::execEND_LCP_REQ(Signal* signal) { + if (ERROR_INSERTED(11008)) + { + ndbout_c("Ignore END_LCP"); + return; + } + EndLcpReq* req = (EndLcpReq*)signal->getDataPtr(); m_end_lcp_req = *req; @@ -1274,7 +1298,8 @@ Pgman::process_lcp(Signal* signal) { DBG_LCP(" pageout()" << endl); ptr.p->m_state |= Page_entry::LCP; - c_tup->disk_page_unmap_callback(ptr.p->m_real_page_i, + c_tup->disk_page_unmap_callback(0, + ptr.p->m_real_page_i, ptr.p->m_dirty_count); pageout(signal, ptr); } @@ -1301,6 +1326,13 @@ Pgman::process_lcp(Signal* signal) } else { + if (ERROR_INSERTED(11007)) + { + ndbout << "No more writes..." << endl; + signal->theData[0] = 9999; + sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 10000, 1); + SET_ERROR_INSERT_VALUE(11008); + } signal->theData[0] = m_end_lcp_req.senderData; sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB); } @@ -1489,6 +1521,10 @@ Pgman::fswriteconf(Signal* signal, Ptr<Page_entry> ptr) Page_state state = ptr.p->m_state; ndbrequire(state & Page_entry::PAGEOUT); + c_tup->disk_page_unmap_callback(1, + ptr.p->m_real_page_i, + ptr.p->m_dirty_count); + state &= ~ Page_entry::PAGEOUT; state &= ~ Page_entry::EMPTY; state &= ~ Page_entry::DIRTY; @@ -1588,8 +1624,11 @@ Pgman::fswritereq(Signal* signal, Ptr<Page_entry> ptr) } #endif - sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, - FsReadWriteReq::FixedLength + 1, JBA); + if (!ERROR_INSERTED(11008)) + { + sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, + FsReadWriteReq::FixedLength + 1, JBA); + } } void @@ -1739,7 +1778,7 @@ Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req) #endif state |= Page_entry::REQUEST; - if (only_request && req_flags & Page_request::EMPTY_PAGE) + if (only_request && (req_flags & Page_request::EMPTY_PAGE)) { state |= Page_entry::EMPTY; } @@ -2401,7 +2440,8 @@ Pgman::execDUMP_STATE_ORD(Signal* signal) if (pl_hash.find(ptr, key)) { ndbout << "pageout " << ptr << endl; - c_tup->disk_page_unmap_callback(ptr.p->m_real_page_i, + c_tup->disk_page_unmap_callback(0, + ptr.p->m_real_page_i, ptr.p->m_dirty_count); pageout(signal, ptr); } @@ -2452,6 +2492,16 @@ Pgman::execDUMP_STATE_ORD(Signal* signal) { SET_ERROR_INSERT_VALUE(11006); } + + if (signal->theData[0] == 11007) + { + SET_ERROR_INSERT_VALUE(11007); + } + + if (signal->theData[0] == 11008) + { + SET_ERROR_INSERT_VALUE(11008); + } } // page cache client diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp index b8cc438f514..7845b83693c 100644 --- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp @@ -3655,6 +3655,8 @@ Suma::execSUB_GCP_COMPLETE_REP(Signal* signal) if(m_gcp_complete_rep_count && !c_subscriber_nodes.isclear()) { + CRASH_INSERTION(13033); + NodeReceiverGroup rg(API_CLUSTERMGR, c_subscriber_nodes); sendSignal(rg, GSN_SUB_GCP_COMPLETE_REP, signal, SubGcpCompleteRep::SignalLength, JBB); @@ -3674,8 +3676,8 @@ Suma::execSUB_GCP_COMPLETE_REP(Signal* signal) { if(m_active_buckets.get(i)) continue; - - if(c_buckets[i].m_buffer_tail != RNIL) + + if (!c_subscriber_nodes.isclear()) { //Uint32* dst; get_buffer_ptr(signal, i, gci, 0); diff --git a/storage/ndb/src/kernel/blocks/tsman.cpp b/storage/ndb/src/kernel/blocks/tsman.cpp index 8f61ec0cf7b..3a7003d56c8 100644 --- a/storage/ndb/src/kernel/blocks/tsman.cpp +++ b/storage/ndb/src/kernel/blocks/tsman.cpp @@ -299,7 +299,7 @@ Tsman::execDUMP_STATE_ORD(Signal* signal){ Uint32 new_bits = curr_bits ^ rand(); Local_key key = chunks[chunk].start_page; key.m_page_no += page; - ndbrequire(update_page_free_bits(signal, &key, new_bits, 0) == 0); + ndbrequire(update_page_free_bits(signal, &key, new_bits) == 0); } } } @@ -366,6 +366,20 @@ Tsman::execCREATE_FILEGROUP_REQ(Signal* signal){ CreateFilegroupImplRef::SignalLength, JBB); } +NdbOut& +operator<<(NdbOut& out, const File_formats::Datafile::Extent_header & obj) +{ + out << "table: " << obj.m_table + << " fragment: " << obj.m_fragment_id << " "; + for(Uint32 i = 0; i<32; i++) + { + char t[2]; + BaseString::snprintf(t, sizeof(t), "%x", obj.get_free_bits(i)); + out << t; + } + return out; +} + void Tsman::execDROP_FILEGROUP_REQ(Signal* signal){ jamEntry(); @@ -1590,8 +1604,7 @@ Tsman::execFREE_EXTENT_REQ(Signal* signal) int Tsman::update_page_free_bits(Signal* signal, Local_key *key, - unsigned committed_bits, - Uint64 lsn) + unsigned committed_bits) { jamEntry(); @@ -1626,6 +1639,18 @@ Tsman::update_page_free_bits(Signal* signal, File_formats::Datafile::Extent_header* header = page->get_header(val.m_extent_no, val.m_extent_size); + if (header->m_table == RNIL) + { + ndbout << "update page free bits page: " << *key + << " " << *header << endl; + } + + if (0) + { + ndbout << "update page free bits page(" << committed_bits << ") " + << *key << " " << *header << endl; + } + ndbrequire(header->m_table != RNIL); Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val); @@ -1637,7 +1662,7 @@ Tsman::update_page_free_bits(Signal* signal, Uint32 src = header->get_free_bits(page_no_in_extent) & UNCOMMITTED_MASK; header->update_free_bits(page_no_in_extent, src | committed_bits); - m_page_cache_client.update_lsn(preq.m_page, lsn); + m_page_cache_client.update_lsn(preq.m_page, 0); return 0; } @@ -1725,6 +1750,11 @@ Tsman::unmap_page(Signal* signal, Local_key *key, Uint32 uncommitted_bits) File_formats::Datafile::Extent_header* header = page->get_header(val.m_extent_no, val.m_extent_size); + if (header->m_table == RNIL) + { + ndbout << "trying to unmap page: " << *key + << " " << *header << endl; + } ndbrequire(header->m_table != RNIL); Uint32 page_no_in_extent = calc_page_no_in_extent(key->m_page_no, &val); @@ -1746,9 +1776,7 @@ Tsman::restart_undo_page_free_bits(Signal* signal, Uint32 tableId, Uint32 fragId, Local_key *key, - unsigned bits, - Uint64 undo_lsn, - Uint64 page_lsn) + unsigned bits) { jamEntry(); @@ -1782,21 +1810,7 @@ Tsman::restart_undo_page_free_bits(Signal* signal, (File_formats::Datafile::Extent_page*)ptr_p; File_formats::Datafile::Extent_header* header = page->get_header(val.m_extent_no, val.m_extent_size); - - Uint64 lsn = 0; - lsn += page->m_page_header.m_page_lsn_hi; lsn <<= 32; - lsn += page->m_page_header.m_page_lsn_lo; - - if (undo_lsn > lsn && undo_lsn > page_lsn) - { - if (DBG_UNDO) - ndbout << "tsman: ignore " << undo_lsn << "(" << lsn << ", " - << page_lsn << ") " - << *key << " " - << " -> " << bits << endl; - return 0; - } - + if (header->m_table == RNIL) { if (DBG_UNDO) @@ -1815,7 +1829,7 @@ Tsman::restart_undo_page_free_bits(Signal* signal, */ if (DBG_UNDO) { - ndbout << "tsman: apply " << undo_lsn << "(" << lsn << ") " + ndbout << "tsman: apply " << *key << " " << (src & COMMITTED_MASK) << " -> " << bits << endl; } @@ -1863,7 +1877,7 @@ Tsman::execALLOC_PAGE_REQ(Signal* signal) /** * Handling of unmapped extent header pages is not implemented */ - int flags = 0; + int flags = Page_cache_client::DIRTY_REQ; int real_page_id; Uint32 page_no; Uint32 src_bits; diff --git a/storage/ndb/src/kernel/blocks/tsman.hpp b/storage/ndb/src/kernel/blocks/tsman.hpp index 1293cc54141..20019e6d4d1 100644 --- a/storage/ndb/src/kernel/blocks/tsman.hpp +++ b/storage/ndb/src/kernel/blocks/tsman.hpp @@ -209,12 +209,12 @@ private: void load_extent_page_callback(Signal*, Uint32, Uint32); void create_file_ref(Signal*, Ptr<Tablespace>, Ptr<Datafile>, Uint32,Uint32,Uint32); - int update_page_free_bits(Signal*, Local_key*, unsigned committed_bits, - Uint64 lsn); + int update_page_free_bits(Signal*, Local_key*, unsigned committed_bits); + int get_page_free_bits(Signal*, Local_key*, unsigned*, unsigned*); int unmap_page(Signal*, Local_key*, unsigned uncommitted_bits); int restart_undo_page_free_bits(Signal*, Uint32, Uint32, Local_key*, - unsigned committed_bits, Uint64, Uint64); + unsigned committed_bits); int alloc_extent(Signal* signal, Uint32 tablespace, Local_key* key); int alloc_page_from_extent(Signal*, Uint32, Local_key*, Uint32 bits); @@ -320,7 +320,7 @@ public: /** * Update page free bits */ - int update_page_free_bits(Local_key*, unsigned bits, Uint64 lsn); + int update_page_free_bits(Local_key*, unsigned bits); /** * Get page free bits @@ -336,8 +336,7 @@ public: /** * Undo handling of page bits */ - int restart_undo_page_free_bits(Local_key*, unsigned bits, - Uint64 lsn, Uint64 page_lsn); + int restart_undo_page_free_bits(Local_key*, unsigned bits); /** * Get tablespace info @@ -417,10 +416,9 @@ Tablespace_client::free_extent(Local_key* key, Uint64 lsn) inline int Tablespace_client::update_page_free_bits(Local_key *key, - unsigned committed_bits, - Uint64 lsn) + unsigned committed_bits) { - return m_tsman->update_page_free_bits(m_signal, key, committed_bits, lsn); + return m_tsman->update_page_free_bits(m_signal, key, committed_bits); } inline @@ -442,17 +440,13 @@ Tablespace_client::unmap_page(Local_key *key, unsigned uncommitted_bits) inline int Tablespace_client::restart_undo_page_free_bits(Local_key* key, - unsigned committed_bits, - Uint64 lsn, - Uint64 page_lsn) + unsigned committed_bits) { return m_tsman->restart_undo_page_free_bits(m_signal, m_table_id, m_fragment_id, key, - committed_bits, - lsn, - page_lsn); + committed_bits); } #endif diff --git a/storage/ndb/src/mgmclient/CommandInterpreter.cpp b/storage/ndb/src/mgmclient/CommandInterpreter.cpp index 875cc2771ae..9e8910c9649 100644 --- a/storage/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/storage/ndb/src/mgmclient/CommandInterpreter.cpp @@ -269,8 +269,8 @@ static const char* helpText = "CLUSTERLOG TOGGLE [<severity>] ... Toggle severity filter on/off\n" "CLUSTERLOG INFO Print cluster log information\n" "<id> START Start data node (started with -n)\n" -"<id> RESTART [-n] [-i] Restart data or management server node\n" -"<id> STOP Stop data or management server node\n" +"<id> RESTART [-n] [-i] [-a] Restart data or management server node\n" +"<id> STOP [-a] Stop data or management server node\n" "ENTER SINGLE USER MODE <id> Enter single user mode\n" "EXIT SINGLE USER MODE Exit single user mode\n" "<id> STATUS Print status\n" @@ -434,7 +434,7 @@ static const char* helpTextRestart = " NDB Cluster -- Management Client -- Help for RESTART command\n" "---------------------------------------------------------------------------\n" "RESTART Restart data or management server node\n\n" -"<id> RESTART [-n] [-i] \n" +"<id> RESTART [-n] [-i] [-a]\n" " Restart the data or management node <id>(or All data nodes).\n\n" " -n (--nostart) restarts the node but does not\n" " make it join the cluster. Use '<id> START' to\n" @@ -445,6 +445,7 @@ static const char* helpTextRestart = " in the same node group during start up.\n\n" " Consult the documentation before using -i.\n\n" " INCORRECT USE OF -i WILL CAUSE DATA LOSS!\n" +" -a Aborts the node, not syncing GCP.\n" ; static const char* helpTextStop = @@ -452,10 +453,11 @@ static const char* helpTextStop = " NDB Cluster -- Management Client -- Help for STOP command\n" "---------------------------------------------------------------------------\n" "STOP Stop data or management server node\n\n" -"<id> STOP Stop the data or management server node <id>.\n\n" +"<id> STOP [-a] Stop the data or management server node <id>.\n\n" " ALL STOP will just stop all data nodes.\n\n" " If you desire to also shut down management servers,\n" -" use SHUTDOWN instead.\n" +" use SHUTDOWN instead.\n" +" -a Aborts the node, not syncing GCP.\n" ; static const char* helpTextEnterSingleUserMode = diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp index af708664a69..ee5bb5103d8 100644 --- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -234,10 +234,10 @@ MgmtSrvr::startEventLog() } } -void -MgmtSrvr::stopEventLog() +void +MgmtSrvr::stopEventLog() { - // Nothing yet + g_eventLogger.close(); } bool diff --git a/storage/ndb/src/ndbapi/NdbBlob.cpp b/storage/ndb/src/ndbapi/NdbBlob.cpp index 0fc96add084..f3d1dbe3dd1 100644 --- a/storage/ndb/src/ndbapi/NdbBlob.cpp +++ b/storage/ndb/src/ndbapi/NdbBlob.cpp @@ -1141,7 +1141,7 @@ NdbBlob::readTableParts(char* buf, Uint32 part, Uint32 count) * table tuple does not fully protect blob parts since DBTUP * commits each tuple separately. */ - tOp->readTuple() == -1 || + tOp->readTuple(NdbOperation::LM_SimpleRead) == -1 || setPartKeyValue(tOp, part + n) == -1 || tOp->getValue((Uint32)3, buf) == NULL) { setErrorCode(tOp); diff --git a/storage/ndb/src/ndbapi/NdbIndexOperation.cpp b/storage/ndb/src/ndbapi/NdbIndexOperation.cpp index fc19bd251d4..921769f09e3 100644 --- a/storage/ndb/src/ndbapi/NdbIndexOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbIndexOperation.cpp @@ -85,6 +85,9 @@ int NdbIndexOperation::readTuple(NdbOperation::LockMode lm) case LM_CommittedRead: return readTuple(); break; + case LM_SimpleRead: + return readTuple(); + break; default: return -1; }; diff --git a/storage/ndb/src/ndbapi/NdbOperation.cpp b/storage/ndb/src/ndbapi/NdbOperation.cpp index 50531292e40..ddaf5d0b233 100644 --- a/storage/ndb/src/ndbapi/NdbOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbOperation.cpp @@ -429,3 +429,9 @@ NdbOperation::getTable() const { return m_currentTable; } + +NdbTransaction* +NdbOperation::getNdbTransaction() +{ + return theNdbCon; +} diff --git a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp index c9459ff911c..21a6185347e 100644 --- a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp +++ b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp @@ -131,6 +131,8 @@ NdbOperation::readTuple(NdbOperation::LockMode lm) case LM_CommittedRead: return committedRead(); break; + case LM_SimpleRead: + return simpleRead(); default: return -1; }; @@ -185,24 +187,22 @@ NdbOperation::readTupleExclusive() int NdbOperation::simpleRead() { - /** - * Currently/still disabled - */ - return readTuple(); -#if 0 + NdbTransaction* tNdbCon = theNdbCon; int tErrorLine = theErrorLine; if (theStatus == Init) { theStatus = OperationDefined; theOperationType = ReadRequest; theSimpleIndicator = 1; + theDirtyIndicator = 0; theErrorLine = tErrorLine++; - theLockMode = LM_Read; + theLockMode = LM_SimpleRead; + m_abortOption = AO_IgnoreError; + tNdbCon->theSimpleState = 0; return 0; } else { setErrorCode(4200); return -1; }//if -#endif }//NdbOperation::simpleRead() /***************************************************************************** @@ -338,28 +338,32 @@ NdbOperation::setReadLockMode(LockMode lockMode) { /* We only support changing lock mode for read operations at this time. */ assert(theOperationType == ReadRequest || theOperationType == ReadExclusive); - switch (lockMode) - { - case LM_CommittedRead: - theOperationType= ReadRequest; - theSimpleIndicator= 1; - theDirtyIndicator= 1; - break; - case LM_Read: - theNdbCon->theSimpleState= 0; - theOperationType= ReadRequest; - theSimpleIndicator= 0; - theDirtyIndicator= 0; - break; - case LM_Exclusive: - theNdbCon->theSimpleState= 0; - theOperationType= ReadExclusive; - theSimpleIndicator= 0; - theDirtyIndicator= 0; - break; - default: - /* Not supported / invalid. */ - assert(false); + switch (lockMode) { + case LM_CommittedRead: /* TODO, check theNdbCon->theSimpleState */ + theOperationType= ReadRequest; + theSimpleIndicator= 1; + theDirtyIndicator= 1; + break; + case LM_SimpleRead: /* TODO, check theNdbCon->theSimpleState */ + theOperationType= ReadRequest; + theSimpleIndicator= 1; + theDirtyIndicator= 0; + break; + case LM_Read: + theNdbCon->theSimpleState= 0; + theOperationType= ReadRequest; + theSimpleIndicator= 0; + theDirtyIndicator= 0; + break; + case LM_Exclusive: + theNdbCon->theSimpleState= 0; + theOperationType= ReadExclusive; + theSimpleIndicator= 0; + theDirtyIndicator= 0; + break; + default: + /* Not supported / invalid. */ + assert(false); } theLockMode= lockMode; } @@ -404,9 +408,8 @@ NdbOperation::getValue_impl(const NdbColumnImpl* tAttrInfo, char* aValue) return NULL; }//if }//if - Uint32 ah; - AttributeHeader::init(&ah, tAttrInfo->m_attrId, 0); - if (insertATTRINFO(ah) != -1) { + AttributeHeader ah(tAttrInfo->m_attrId, 0); + if (insertATTRINFO(ah.m_value) != -1) { // Insert Attribute Id into ATTRINFO part. /************************************************************************ @@ -532,12 +535,11 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, tAttrId = tAttrInfo->m_attrId; m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1); const char *aValue = aValuePassed; - Uint32 ahValue; if (aValue == NULL) { if (tAttrInfo->m_nullable) { - AttributeHeader& ah = AttributeHeader::init(&ahValue, tAttrId, 0); + AttributeHeader ah(tAttrId, 0); ah.setNULL(); - insertATTRINFO(ahValue); + insertATTRINFO(ah.m_value); // Insert Attribute Id with the value // NULL into ATTRINFO part. DBUG_RETURN(0); @@ -573,8 +575,8 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, // Excluding bits in last word const Uint32 sizeInWords = sizeInBytes / 4; - (void) AttributeHeader::init(&ahValue, tAttrId, sizeInBytes); - insertATTRINFO( ahValue ); + AttributeHeader ah(tAttrId, sizeInBytes); + insertATTRINFO( ah.m_value ); /*********************************************************************** * Check if the pointer of the value passed is aligned on a 4 byte boundary. diff --git a/storage/ndb/src/ndbapi/NdbOperationExec.cpp b/storage/ndb/src/ndbapi/NdbOperationExec.cpp index 9fe85265a0c..27672e0458c 100644 --- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp +++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp @@ -175,12 +175,11 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, Uint8 tInterpretIndicator = theInterpretIndicator; Uint8 tNoDisk = m_no_disk_flag; -//------------------------------------------------------------- -// Simple state is set if start and commit is set and it is -// a read request. Otherwise it is set to zero. -//------------------------------------------------------------- + /** + * A dirty read, can not abort the transaction + */ Uint8 tReadInd = (theOperationType == ReadRequest); - Uint8 tSimpleState = tReadInd & tSimpleIndicator; + Uint8 tDirtyState = tReadInd & tDirtyIndicator; tcKeyReq->transId1 = tTransId1; tcKeyReq->transId2 = tTransId2; @@ -206,8 +205,8 @@ NdbOperation::prepareSend(Uint32 aTC_ConnectPtr, tcKeyReq->setOperationType(tReqInfo, tOperationType); tcKeyReq->setKeyLength(tReqInfo, tTupKeyLen); - // A simple read is always ignore error - abortOption = tSimpleState ? (Uint8) AO_IgnoreError : (Uint8) abortOption; + // A dirty read is always ignore error + abortOption = tDirtyState ? (Uint8) AO_IgnoreError : (Uint8) abortOption; tcKeyReq->setAbortOption(tReqInfo, abortOption); m_abortOption = abortOption; @@ -549,8 +548,8 @@ NdbOperation::receiveTCKEYREF( NdbApiSignal* aSignal) theStatus = Finished; theReceiver.m_received_result_length = ~0; - // not simple read - if(! (theOperationType == ReadRequest && theSimpleIndicator)) + // not dirty read + if(! (theOperationType == ReadRequest && theDirtyIndicator)) { theNdbCon->OpCompleteFailure(this); return -1; diff --git a/storage/ndb/src/ndbapi/NdbReceiver.cpp b/storage/ndb/src/ndbapi/NdbReceiver.cpp index 34b3a14ac6e..5a311bcbefe 100644 --- a/storage/ndb/src/ndbapi/NdbReceiver.cpp +++ b/storage/ndb/src/ndbapi/NdbReceiver.cpp @@ -283,7 +283,7 @@ NdbReceiver::execTRANSID_AI(const Uint32* aDataPtr, Uint32 aLength) Uint32 tmp = m_received_result_length + aLength; m_received_result_length = tmp; - return (tmp == exp || (exp > TcKeyConf::SimpleReadBit) ? 1 : 0); + return (tmp == exp || (exp > TcKeyConf::DirtyReadBit) ? 1 : 0); } int diff --git a/storage/ndb/src/ndbapi/NdbScanFilter.cpp b/storage/ndb/src/ndbapi/NdbScanFilter.cpp index fb47772fdea..25f74ce71a4 100644 --- a/storage/ndb/src/ndbapi/NdbScanFilter.cpp +++ b/storage/ndb/src/ndbapi/NdbScanFilter.cpp @@ -14,11 +14,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <NdbScanFilter.hpp> +#include <Ndb.hpp> #include <NdbOperation.hpp> #include "NdbDictionaryImpl.hpp" #include <Vector.hpp> #include <NdbOut.hpp> #include <Interpreter.hpp> +#include <signaldata/AttrInfo.hpp> +#include "NdbApiSignal.hpp" +#include "NdbUtil.hpp" #ifdef VM_TRACE #include <NdbEnv.h> @@ -52,14 +56,37 @@ public: int cond_col_const(Interpreter::BinaryCondition, Uint32 attrId, const void * value, Uint32 len); + + bool m_abort_on_too_large; + + NdbOperation::OperationStatus m_initial_op_status; + Uint32 m_initial_AI_size; + Uint32 m_max_size; + + Uint32 get_size() { + assert(m_operation->theTotalCurrAI_Len >= m_initial_AI_size); + return m_operation->theTotalCurrAI_Len - m_initial_AI_size; + } + bool check_size() { + if (get_size() <= m_max_size) + return true; + handle_filter_too_large(); + return false; + } + void handle_filter_too_large(); + + NdbError m_error; }; const Uint32 LabelExit = ~0; -NdbScanFilter::NdbScanFilter(class NdbOperation * op) +NdbScanFilter::NdbScanFilter(class NdbOperation * op, + bool abort_on_too_large, + Uint32 max_size) : m_impl(* new NdbScanFilterImpl()) { + DBUG_ENTER("NdbScanFilter::NdbScanFilter"); m_impl.m_current.m_group = (NdbScanFilter::Group)0; m_impl.m_current.m_popCount = 0; m_impl.m_current.m_ownLabel = 0; @@ -69,6 +96,21 @@ NdbScanFilter::NdbScanFilter(class NdbOperation * op) m_impl.m_latestAttrib = ~0; m_impl.m_operation = op; m_impl.m_negative = 0; + + DBUG_PRINT("info", ("op status: %d tot AI: %u in curr: %u", + op->theStatus, + op->theTotalCurrAI_Len, op->theAI_LenInCurrAI)); + + m_impl.m_abort_on_too_large = abort_on_too_large; + + m_impl.m_initial_op_status = op->theStatus; + m_impl.m_initial_AI_size = op->theTotalCurrAI_Len; + if (max_size > NDB_MAX_SCANFILTER_SIZE_IN_WORDS) + max_size = NDB_MAX_SCANFILTER_SIZE_IN_WORDS; + m_impl.m_max_size = max_size; + + m_impl.m_error.code = 0; + DBUG_VOID_RETURN; } NdbScanFilter::~NdbScanFilter(){ @@ -200,30 +242,38 @@ NdbScanFilter::end(){ switch(tmp.m_group){ case NdbScanFilter::AND: if(tmp.m_trueLabel == (Uint32)~0){ - m_impl.m_operation->interpret_exit_ok(); + if (m_impl.m_operation->interpret_exit_ok() == -1) + return -1; } else { - m_impl.m_operation->branch_label(tmp.m_trueLabel); + if (m_impl.m_operation->branch_label(tmp.m_trueLabel) == -1) + return -1; } break; case NdbScanFilter::NAND: if(tmp.m_trueLabel == (Uint32)~0){ - m_impl.m_operation->interpret_exit_nok(); + if (m_impl.m_operation->interpret_exit_nok() == -1) + return -1; } else { - m_impl.m_operation->branch_label(tmp.m_falseLabel); + if (m_impl.m_operation->branch_label(tmp.m_falseLabel) == -1) + return -1; } break; case NdbScanFilter::OR: if(tmp.m_falseLabel == (Uint32)~0){ - m_impl.m_operation->interpret_exit_nok(); + if (m_impl.m_operation->interpret_exit_nok() == -1) + return -1; } else { - m_impl.m_operation->branch_label(tmp.m_falseLabel); + if (m_impl.m_operation->branch_label(tmp.m_falseLabel) == -1) + return -1; } break; case NdbScanFilter::NOR: if(tmp.m_falseLabel == (Uint32)~0){ - m_impl.m_operation->interpret_exit_ok(); + if (m_impl.m_operation->interpret_exit_ok() == -1) + return -1; } else { - m_impl.m_operation->branch_label(tmp.m_trueLabel); + if (m_impl.m_operation->branch_label(tmp.m_trueLabel) == -1) + return -1; } break; default: @@ -231,24 +281,29 @@ NdbScanFilter::end(){ return -1; } - m_impl.m_operation->def_label(tmp.m_ownLabel); + if (m_impl.m_operation->def_label(tmp.m_ownLabel) == -1) + return -1; if(m_impl.m_stack.size() == 0){ switch(tmp.m_group){ case NdbScanFilter::AND: case NdbScanFilter::NOR: - m_impl.m_operation->interpret_exit_nok(); + if (m_impl.m_operation->interpret_exit_nok() == -1) + return -1; break; case NdbScanFilter::OR: case NdbScanFilter::NAND: - m_impl.m_operation->interpret_exit_ok(); + if (m_impl.m_operation->interpret_exit_ok() == -1) + return -1; break; default: m_impl.m_operation->setErrorCodeAbort(4260); return -1; } } - + + if (!m_impl.check_size()) + return -1; return 0; } @@ -261,10 +316,16 @@ NdbScanFilter::istrue(){ } if(m_impl.m_current.m_trueLabel == (Uint32)~0){ - return m_impl.m_operation->interpret_exit_ok(); + if (m_impl.m_operation->interpret_exit_ok() == -1) + return -1; } else { - return m_impl.m_operation->branch_label(m_impl.m_current.m_trueLabel); + if (m_impl.m_operation->branch_label(m_impl.m_current.m_trueLabel) == -1) + return -1; } + + if (!m_impl.check_size()) + return -1; + return 0; } int @@ -276,12 +337,22 @@ NdbScanFilter::isfalse(){ } if(m_impl.m_current.m_falseLabel == (Uint32)~0){ - return m_impl.m_operation->interpret_exit_nok(); + if (m_impl.m_operation->interpret_exit_nok() == -1) + return -1; } else { - return m_impl.m_operation->branch_label(m_impl.m_current.m_falseLabel); + if (m_impl.m_operation->branch_label(m_impl.m_current.m_falseLabel) == -1) + return -1; } + + if (!m_impl.check_size()) + return -1; + return 0; } +NdbOperation * +NdbScanFilter::getNdbOperation(){ + return m_impl.m_operation; +} #define action(x, y, z) @@ -330,7 +401,11 @@ NdbScanFilterImpl::cond_col(Interpreter::UnaryCondition op, Uint32 AttrId){ } Branch1 branch = table2[op].m_branches[m_current.m_group]; - (m_operation->* branch)(AttrId, m_current.m_ownLabel); + if ((m_operation->* branch)(AttrId, m_current.m_ownLabel) == -1) + return -1; + + if (!check_size()) + return -1; return 0; } @@ -463,8 +538,12 @@ NdbScanFilterImpl::cond_col_const(Interpreter::BinaryCondition op, return -1; } - int ret = (m_operation->* branch)(AttrId, value, len, false, m_current.m_ownLabel); - return ret; + if ((m_operation->* branch)(AttrId, value, len, false, m_current.m_ownLabel) == -1) + return -1; + + if (!check_size()) + return -1; + return 0; } int @@ -490,7 +569,130 @@ NdbScanFilter::cmp(BinaryCondition cond, int ColId, return m_impl.cond_col_const(Interpreter::NOT_LIKE, ColId, val, len); } return -1; -} +} + +void +NdbScanFilterImpl::handle_filter_too_large() +{ + DBUG_ENTER("NdbScanFilterImpl::handle_filter_too_large"); + + NdbOperation* const op = m_operation; + m_error.code = NdbScanFilter::FilterTooLarge; + if (m_abort_on_too_large) + op->setErrorCodeAbort(m_error.code); + + /* + * Possible interpreted parts at this point are: + * + * 1. initial read + * 2. interpreted program + * + * It is assumed that NdbScanFilter has created all of 2 + * so that we don't have to save interpreter state. + */ + + const Uint32 size = get_size(); + assert(size != 0); + + // new ATTRINFO size + const Uint32 new_size = m_initial_AI_size; + + // find last signal for new size + assert(op->theFirstATTRINFO != NULL); + NdbApiSignal* lastSignal = op->theFirstATTRINFO; + Uint32 n = 0; + while (n + AttrInfo::DataLength < new_size) { + lastSignal = lastSignal->next(); + assert(lastSignal != NULL); + n += AttrInfo::DataLength; + } + assert(n < size); + + // release remaining signals + NdbApiSignal* tSignal = lastSignal->next(); + op->theNdb->releaseSignalsInList(&tSignal); + lastSignal->next(NULL); + + // length of lastSignal + const Uint32 new_curr = AttrInfo::HeaderLength + new_size - n; + assert(new_curr <= 25); + + DBUG_PRINT("info", ("op status: %d->%d tot AI: %u->%u in curr: %u->%u", + op->theStatus, m_initial_op_status, + op->theTotalCurrAI_Len, new_size, + op->theAI_LenInCurrAI, new_curr)); + + // reset op state + op->theStatus = m_initial_op_status; + + // reset interpreter state to initial + + NdbBranch* tBranch = op->theFirstBranch; + while (tBranch != NULL) { + NdbBranch* tmp = tBranch; + tBranch = tBranch->theNext; + op->theNdb->releaseNdbBranch(tmp); + } + op->theFirstBranch = NULL; + op->theLastBranch = NULL; + + NdbLabel* tLabel = op->theFirstLabel; + while (tLabel != NULL) { + NdbLabel* tmp = tLabel; + tLabel = tLabel->theNext; + op->theNdb->releaseNdbLabel(tmp); + } + op->theFirstLabel = NULL; + op->theLastLabel = NULL; + + NdbCall* tCall = op->theFirstCall; + while (tCall != NULL) { + NdbCall* tmp = tCall; + tCall = tCall->theNext; + op->theNdb->releaseNdbCall(tmp); + } + op->theFirstCall = NULL; + op->theLastCall = NULL; + + NdbSubroutine* tSubroutine = op->theFirstSubroutine; + while (tSubroutine != NULL) { + NdbSubroutine* tmp = tSubroutine; + tSubroutine = tSubroutine->theNext; + op->theNdb->releaseNdbSubroutine(tmp); + } + op->theFirstSubroutine = NULL; + op->theLastSubroutine = NULL; + + op->theNoOfLabels = 0; + op->theNoOfSubroutines = 0; + + // reset AI size + op->theTotalCurrAI_Len = new_size; + op->theAI_LenInCurrAI = new_curr; + + // reset signal pointers + op->theCurrentATTRINFO = lastSignal; + op->theATTRINFOptr = &lastSignal->getDataPtrSend()[new_curr]; + + // interpreter sizes are set later somewhere + + DBUG_VOID_RETURN; +} + +static void +update(const NdbError & _err){ + NdbError & error = (NdbError &) _err; + ndberror_struct ndberror = (ndberror_struct)error; + ndberror_update(&ndberror); + error = NdbError(ndberror); +} + +const NdbError & +NdbScanFilter::getNdbError() const +{ + update(m_impl.m_error); + return m_impl.m_error; +} #if 0 diff --git a/storage/ndb/src/ndbapi/NdbScanOperation.cpp b/storage/ndb/src/ndbapi/NdbScanOperation.cpp index 89782453a72..afbec070ac8 100644 --- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp @@ -237,6 +237,7 @@ NdbScanOperation::setReadLockMode(LockMode lockMode) lockHoldMode= false; readCommitted= true; break; + case LM_SimpleRead: case LM_Read: lockExcl= false; lockHoldMode= true; @@ -872,6 +873,10 @@ NdbScanOperation::doSendScan(int aProcessorId) // 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()); + if (unlikely(theTotalCurrAI_Len > ScanTabReq::MaxTotalAttrInfo)) { + setErrorCode(4257); + return -1; + } req->attrLenKeyLen = (tupKeyLen << 16) | theTotalCurrAI_Len; Uint32 tmp = req->requestInfo; ScanTabReq::setDistributionKeyFlag(tmp, theDistrKeyIndicator_); diff --git a/storage/ndb/src/ndbapi/NdbTransaction.cpp b/storage/ndb/src/ndbapi/NdbTransaction.cpp index 55c6f0f4b99..bc59df722aa 100644 --- a/storage/ndb/src/ndbapi/NdbTransaction.cpp +++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp @@ -1787,8 +1787,8 @@ from other transactions. const Uint32 tAttrInfoLen = *tPtr++; if (tOp && tOp->checkMagicNumber()) { Uint32 done = tOp->execTCOPCONF(tAttrInfoLen); - if(tAttrInfoLen > TcKeyConf::SimpleReadBit){ - Uint32 node = tAttrInfoLen & (~TcKeyConf::SimpleReadBit); + if(tAttrInfoLen > TcKeyConf::DirtyReadBit){ + Uint32 node = tAttrInfoLen & (~TcKeyConf::DirtyReadBit); NdbNodeBitmask::set(m_db_nodes, node); if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done) { @@ -2182,7 +2182,7 @@ NdbTransaction::report_node_failure(Uint32 id){ * 4) X X */ NdbOperation* tmp = theFirstExecOpInList; - const Uint32 len = TcKeyConf::SimpleReadBit | id; + const Uint32 len = TcKeyConf::DirtyReadBit | id; Uint32 tNoComp = theNoOfOpCompleted; Uint32 tNoSent = theNoOfOpSent; Uint32 count = 0; diff --git a/storage/ndb/src/ndbapi/ndberror.c b/storage/ndb/src/ndbapi/ndberror.c index a0417e5b118..0ad2faff76a 100644 --- a/storage/ndb/src/ndbapi/ndberror.c +++ b/storage/ndb/src/ndbapi/ndberror.c @@ -624,6 +624,7 @@ ErrorBundle ErrorCodes[] = { { 4273, DMEC, IE, "No blob table in dict cache" }, { 4274, DMEC, IE, "Corrupted main table PK in blob operation" }, { 4275, DMEC, AE, "The blob method is incompatible with operation type or lock mode" }, + { 4294, DMEC, AE, "Scan filter is too large, discarded" }, { NO_CONTACT_WITH_PROCESS, DMEC, AE, "No contact with the process (dead ?)."}, diff --git a/storage/ndb/test/include/HugoTransactions.hpp b/storage/ndb/test/include/HugoTransactions.hpp index e2b12f261a8..e8f7b33e0ed 100644 --- a/storage/ndb/test/include/HugoTransactions.hpp +++ b/storage/ndb/test/include/HugoTransactions.hpp @@ -36,6 +36,16 @@ public: int updateValue = 0, bool abort = false); + int loadTableStartFrom(Ndb*, + int startFrom, + int records, + int batch = 512, + bool allowConstraintViolation = true, + int doSleep = 0, + bool oneTrans = false, + int updateValue = 0, + bool abort = false); + int scanReadRecords(Ndb*, int records, int abort = 0, @@ -56,6 +66,11 @@ public: int batchsize = 1, NdbOperation::LockMode = NdbOperation::LM_Read); + int scanUpdateRecords(Ndb*, NdbScanOperation::ScanFlag, + int records, + int abort = 0, + int parallelism = 0); + int scanUpdateRecords(Ndb*, int records, int abort = 0, @@ -90,9 +105,12 @@ public: int records, int percentToLock = 1, int lockTime = 1000); + int fillTable(Ndb*, int batch=512); + int fillTableStartFrom(Ndb*, int startFrom, int batch=512); + /** * Reading using UniqHashIndex with key = pk */ diff --git a/storage/ndb/test/include/UtilTransactions.hpp b/storage/ndb/test/include/UtilTransactions.hpp index 75bbcd9c776..193398c3da2 100644 --- a/storage/ndb/test/include/UtilTransactions.hpp +++ b/storage/ndb/test/include/UtilTransactions.hpp @@ -30,6 +30,11 @@ public: int closeTransaction(Ndb*); int clearTable(Ndb*, + NdbScanOperation::ScanFlag, + int records = 0, + int parallelism = 0); + + int clearTable(Ndb*, int records = 0, int parallelism = 0); diff --git a/storage/ndb/test/include/dbutil.hpp b/storage/ndb/test/include/dbutil.hpp new file mode 100755 index 00000000000..2b36965715f --- /dev/null +++ b/storage/ndb/test/include/dbutil.hpp @@ -0,0 +1,97 @@ +// dbutil.h: interface for the database utilities class. +////////////////////////////////////////////////////////////////////// +// Supplies a database to the test application +////////////////////////////////////////////////////////////////////// + +#ifndef DBUTIL_HPP +#define DBUTIL_HPP + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include <time.h> +#include <stdio.h> +#include <string.h> +#include <mysql.h> +//include "rand.h" +#include <stdlib.h> + +//#define DEBUG +#define DIE_UNLESS(expr) \ + ((void) ((expr) ? 0 : (Die(__FILE__, __LINE__, #expr), 0))) +#define DIE(expr) \ + Die(__FILE__, __LINE__, #expr) +#define myerror(msg) PrintError(msg) +#define mysterror(stmt, msg) PrintStError(stmt, msg) +#define CheckStmt(stmt) \ +{ \ +if ( stmt == 0) \ + myerror(NULL); \ +DIE_UNLESS(stmt != 0); \ +} + +#define check_execute(stmt, r) \ +{ \ +if (r) \ + mysterror(stmt, NULL); \ +DIE_UNLESS(r == 0);\ +} + +#define TRUE 1 +#define FALSE 0 + + +class dbutil +{ +public: + + dbutil(const char * databaseName); + ~dbutil(); + + void DatabaseLogin(const char * system, + const char * usr, + const char * password, + unsigned int portIn, + const char * sockIn, + bool transactional); + char * GetDbName(){return dbs;}; + char * GetUser(){return user;}; + char * GetPassword(){return pass;}; + char * GetHost(){return host;}; + char * GetSocket(){return socket;}; + const char * GetServerType(){return mysql_get_server_info(myDbHandel);}; + MYSQL* GetDbHandel(){return myDbHandel;}; + MYSQL_STMT *STDCALL MysqlSimplePrepare(const char *query); + int Select_DB(); + int Do_Query(char * stm); + const char * GetError(); + int GetErrorNumber(); + unsigned long SelectCountTable(const char * table); + +private: + + //Connect variables + char * databaseName; //hold results file name + char host[256]; // Computer to connect to + char user[256]; // MySQL User + char pass[256]; // MySQL User Password + char dbs[256]; // Database to use (TPCB) + unsigned int port; // MySQL Server port + char socket[256]; // MySQL Server Unix Socket + MYSQL *myDbHandel; + + void DatabaseLogout(); + + void SetDbName(const char * name){strcpy((char *)dbs, name);}; + void SetUser(const char * userName){strcpy((char *)user, userName);}; + void SetPassword(const char * password){strcpy((char *)pass,password);}; + void SetHost(const char * system){strcpy((char*)host, system);}; + void SetPort(unsigned int portIn){port=portIn;}; + void SetSocket(const char * sockIn){strcpy((char *)socket, sockIn);}; + void PrintError(const char *msg); + void PrintStError(MYSQL_STMT *stmt, const char *msg); + void Die(const char *file, int line, const char *expr); // stop program + +}; +#endif + diff --git a/storage/ndb/test/ndbapi/testBasic.cpp b/storage/ndb/test/ndbapi/testBasic.cpp index 952b5a50dc5..ac23ceaad18 100644 --- a/storage/ndb/test/ndbapi/testBasic.cpp +++ b/storage/ndb/test/ndbapi/testBasic.cpp @@ -136,31 +136,13 @@ int runPkRead(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int batchSize = ctx->getProperty("BatchSize", 1); + int lm = ctx->getProperty("LockMode", NdbOperation::LM_Read); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (i<loops) { g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize) != NDBT_OK){ - g_info << endl; - return NDBT_FAILED; - } - i++; - } - g_info << endl; - return NDBT_OK; -} - -int runPkDirtyRead(NDBT_Context* ctx, NDBT_Step* step){ - int loops = ctx->getNumLoops(); - int records = ctx->getNumRecords(); - int batchSize = ctx->getProperty("BatchSize", 1); - int i = 0; - bool dirty = true; - HugoTransactions hugoTrans(*ctx->getTab()); - while (i<loops) { - g_info << i << ": "; - if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize, - NdbOperation::LM_CommittedRead) != NDBT_OK){ + if (hugoTrans.pkReadRecords(GETNDB(step), records, batchSize, + (NdbOperation::LockMode)lm) != NDBT_OK){ g_info << endl; return NDBT_FAILED; } @@ -1552,14 +1534,23 @@ TESTCASE("PkInsert", } TESTCASE("PkRead", "Verify that we can insert, read and delete from this table using PK"){ + TC_PROPERTY("LockMode", NdbOperation::LM_Read); INITIALIZER(runLoadTable); STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("PkDirtyRead", "Verify that we can insert, dirty read and delete from this table using PK"){ + TC_PROPERTY("LockMode", NdbOperation::LM_Dirty); INITIALIZER(runLoadTable); - STEP(runPkDirtyRead); + STEP(runPkRead); + FINALIZER(runClearTable); +} +TESTCASE("PkSimpleRead", + "Verify that we can insert, simple read and delete from this table using PK"){ + TC_PROPERTY("LockMode", NdbOperation::LM_SimpleRead); + INITIALIZER(runLoadTable); + STEP(runPkRead); FINALIZER(runClearTable); } TESTCASE("PkUpdate", diff --git a/storage/ndb/test/ndbapi/testDict.cpp b/storage/ndb/test/ndbapi/testDict.cpp index 13c071f968e..16b6e129605 100644 --- a/storage/ndb/test/ndbapi/testDict.cpp +++ b/storage/ndb/test/ndbapi/testDict.cpp @@ -684,7 +684,7 @@ int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){ CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0); CHECK(count == records); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0); CHECK(count == (records/2)); @@ -862,7 +862,7 @@ int runPkSizes(NDBT_Context* ctx, NDBT_Step* step){ CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0); CHECK(count == records); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0); CHECK(count == (records/2)); CHECK(utilTrans.clearTable(pNdb, records) == 0); @@ -2706,7 +2706,262 @@ runDictRestart(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug29501(NDBT_Context* ctx, NDBT_Step* step) { + NdbRestarter res; + NdbDictionary::LogfileGroup lg; + lg.setName("DEFAULT-LG"); + lg.setUndoBufferSize(8*1024*1024); + + if (res.getNumDbNodes() < 2) + return NDBT_OK; + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + + int node = res.getRandomNotMasterNodeId(rand()); + res.restartOneDbNode(node, true, true, false); + + if(pDict->createLogfileGroup(lg) != 0){ + g_err << "Failed to create logfilegroup:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + NdbDictionary::Undofile uf; + uf.setPath("undofile01.dat"); + uf.setSize(5*1024*1024); + uf.setLogfileGroup("DEFAULT-LG"); + + if(pDict->createUndofile(uf) != 0){ + g_err << "Failed to create undofile:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + res.waitNodesNoStart(&node, 1); + res.startNodes(&node, 1); + + if (res.waitClusterStarted()){ + g_err << "Node restart failed" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lg.getName())) != 0){ + g_err << "Drop of LFG Failed" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + return NDBT_OK; +} + +int +runDropDDObjects(NDBT_Context* ctx, NDBT_Step* step){ + //Purpose is to drop all tables, data files, Table spaces and LFG's + Uint32 i = 0; + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + + NdbDictionary::Dictionary::List list; + if (pDict->listObjects(list) == -1) + return NDBT_FAILED; + + //Search the list and drop all tables found + const char * tableFound = 0; + for (i = 0; i < list.count; i++){ + switch(list.elements[i].type){ + case NdbDictionary::Object::UserTable: + tableFound = list.elements[i].name; + if(tableFound != 0){ + if(pDict->dropTable(tableFound) != 0){ + g_err << "Failed to drop table: " << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + } + tableFound = 0; + break; + default: + break; + } + } + + //Search the list and drop all data file found + const char * dfFound = 0; + for (i = 0; i < list.count; i++){ + switch(list.elements[i].type){ + case NdbDictionary::Object::Datafile: + dfFound = list.elements[i].name; + if(dfFound != 0){ + if(pDict->dropDatafile(pDict->getDatafile(0, dfFound)) != 0){ + g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + } + dfFound = 0; + break; + default: + break; + } + } + + //Search the list and drop all Table Spaces Found + const char * tsFound = 0; + for (i = 0; i <list.count; i++){ + switch(list.elements[i].type){ + case NdbDictionary::Object::Tablespace: + tsFound = list.elements[i].name; + if(tsFound != 0){ + if(pDict->dropTablespace(pDict->getTablespace(tsFound)) != 0){ + g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + } + tsFound = 0; + break; + default: + break; + } + } + + //Search the list and drop all LFG Found + //Currently only 1 LGF is supported, but written for future + //when more then one is supported. + const char * lgFound = 0; + for (i = 0; i < list.count; i++){ + switch(list.elements[i].type){ + case NdbDictionary::Object::LogfileGroup: + lgFound = list.elements[i].name; + if(lgFound != 0){ + if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgFound)) != 0){ + g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + } + lgFound = 0; + break; + default: + break; + } + } + + return NDBT_OK; +} + +int +runWaitStarted(NDBT_Context* ctx, NDBT_Step* step){ + + NdbRestarter restarter; + restarter.waitClusterStarted(300); + + NdbSleep_SecSleep(3); + return NDBT_OK; +} + +int +testDropDDObjectsSetup(NDBT_Context* ctx, NDBT_Step* step){ + //Purpose is to setup to test DropDDObjects + char tsname[256]; + char dfname[256]; + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + + NdbDictionary::LogfileGroup lg; + lg.setName("DEFAULT-LG"); + lg.setUndoBufferSize(8*1024*1024); + + + if(pDict->createLogfileGroup(lg) != 0){ + g_err << "Failed to create logfilegroup:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + NdbDictionary::Undofile uf; + uf.setPath("undofile01.dat"); + uf.setSize(5*1024*1024); + uf.setLogfileGroup("DEFAULT-LG"); + + if(pDict->createUndofile(uf) != 0){ + g_err << "Failed to create undofile:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand()); + BaseString::snprintf(dfname, sizeof(dfname), "%s-%u.dat", tsname, rand()); + + if (create_tablespace(pDict, lg.getName(), tsname, dfname)){ + g_err << "Failed to create undofile:" + << endl << pDict->getNdbError() << endl; + return NDBT_FAILED; + } + + return NDBT_OK; +} + +int +DropDDObjectsVerify(NDBT_Context* ctx, NDBT_Step* step){ + //Purpose is to verify test DropDDObjects worked + Uint32 i = 0; + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + + NdbDictionary::Dictionary::List list; + if (pDict->listObjects(list) == -1) + return NDBT_FAILED; + + bool ddFound = false; + for (i = 0; i <list.count; i++){ + switch(list.elements[i].type){ + case NdbDictionary::Object::Tablespace: + ddFound = true; + break; + case NdbDictionary::Object::LogfileGroup: + ddFound = true; + break; + default: + break; + } + if(ddFound == true){ + g_err << "DropDDObjects Failed: DD found:" + << endl; + return NDBT_FAILED; + } + } + return NDBT_OK; +} + NDBT_TESTSUITE(testDict); +TESTCASE("testDropDDObjects", + "* 1. start cluster\n" + "* 2. Create LFG\n" + "* 3. create TS\n" + "* 4. run DropDDObjects\n" + "* 5. Verify DropDDObjectsRestart worked\n"){ +INITIALIZER(runWaitStarted); +INITIALIZER(runDropDDObjects); +INITIALIZER(testDropDDObjectsSetup); +STEP(runDropDDObjects); +FINALIZER(DropDDObjectsVerify); +} + +TESTCASE("Bug29501", + "* 1. start cluster\n" + "* 2. Restart 1 node -abort -nostart\n" + "* 3. create LFG\n" + "* 4. Restart data node\n" + "* 5. Restart 1 node -nostart\n" + "* 6. Drop LFG\n"){ +INITIALIZER(runWaitStarted); +INITIALIZER(runDropDDObjects); +STEP(runBug29501); +FINALIZER(runDropDDObjects); +} TESTCASE("CreateAndDrop", "Try to create and drop the table loop number of times\n"){ INITIALIZER(runCreateAndDrop); diff --git a/storage/ndb/test/ndbapi/testIndex.cpp b/storage/ndb/test/ndbapi/testIndex.cpp index 00e559c7a0f..bd9ff7ac607 100644 --- a/storage/ndb/test/ndbapi/testIndex.cpp +++ b/storage/ndb/test/ndbapi/testIndex.cpp @@ -809,7 +809,7 @@ int runSystemRestart1(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0); CHECK(utilTrans.verifyIndex(pNdb, idxName, 16, false) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.verifyIndex(pNdb, idxName, 16, false) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records, 1) == 0); @@ -834,7 +834,7 @@ int runSystemRestart1(NDBT_Context* ctx, NDBT_Step* step){ CHECK(utilTrans.verifyIndex(pNdb, idxName, 16, false) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); CHECK(utilTrans.verifyIndex(pNdb, idxName, 16, false) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.verifyIndex(pNdb, idxName, 16, false) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records, 1) == 0); diff --git a/storage/ndb/test/ndbapi/testNodeRestart.cpp b/storage/ndb/test/ndbapi/testNodeRestart.cpp index 99b72699762..419196e00eb 100644 --- a/storage/ndb/test/ndbapi/testNodeRestart.cpp +++ b/storage/ndb/test/ndbapi/testNodeRestart.cpp @@ -1762,6 +1762,80 @@ runBug28717(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug31525(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int loops = ctx->getNumLoops(); + int records = ctx->getNumRecords(); + Ndb* pNdb = GETNDB(step); + NdbRestarter res; + + if (res.getNumDbNodes() < 2) + { + return NDBT_OK; + } + + int nodes[2]; + nodes[0] = res.getMasterNodeId(); + nodes[1] = res.getNextMasterNodeId(nodes[0]); + + while (res.getNodeGroup(nodes[0]) != res.getNodeGroup(nodes[1])) + { + ndbout_c("Restarting %u as it not in same node group as %u", + nodes[1], nodes[0]); + if (res.restartOneDbNode(nodes[1], false, true, true)) + return NDBT_FAILED; + + if (res.waitNodesNoStart(nodes+1, 1)) + return NDBT_FAILED; + + if (res.startNodes(nodes+1, 1)) + return NDBT_FAILED; + + if (res.waitClusterStarted()) + return NDBT_FAILED; + + nodes[1] = res.getNextMasterNodeId(nodes[0]); + } + + ndbout_c("nodes[0]: %u nodes[1]: %u", nodes[0], nodes[1]); + + int val = DumpStateOrd::DihMinTimeBetweenLCP; + if (res.dumpStateAllNodes(&val, 1)) + return NDBT_FAILED; + + int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; + if (res.dumpStateAllNodes(val2, 2)) + return NDBT_FAILED; + + if (res.insertErrorInAllNodes(932)) + return NDBT_FAILED; + + if (res.insertErrorInNode(nodes[1], 7192)) + return NDBT_FAILED; + + if (res.insertErrorInNode(nodes[0], 7191)) + return NDBT_FAILED; + + if (res.waitClusterNoStart()) + return NDBT_FAILED; + + if (res.startAll()) + return NDBT_FAILED; + + if (res.waitClusterStarted()) + return NDBT_FAILED; + + if (res.restartOneDbNode(nodes[1], false, false, true)) + return NDBT_FAILED; + + if (res.waitClusterStarted()) + return NDBT_FAILED; + + return NDBT_OK; +} + NDBT_TESTSUITE(testNodeRestart); TESTCASE("NoLoad", "Test that one node at a time can be stopped and then restarted "\ @@ -2085,6 +2159,9 @@ TESTCASE("Bug21271", STEP(runPkUpdateUntilStopped); FINALIZER(runClearTable); } +TESTCASE("Bug31525", ""){ + INITIALIZER(runBug31525); +} TESTCASE("Bug24717", ""){ INITIALIZER(runBug24717); } diff --git a/storage/ndb/test/ndbapi/testScan.cpp b/storage/ndb/test/ndbapi/testScan.cpp index 2561869fa5f..df6dbe2e550 100644 --- a/storage/ndb/test/ndbapi/testScan.cpp +++ b/storage/ndb/test/ndbapi/testScan.cpp @@ -579,7 +579,7 @@ int runScanUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ para = myRandom48(239)+1; g_info << i << ": "; - if (hugoTrans.scanUpdateRecords(GETNDB(step), records, 0, para) == NDBT_FAILED){ + if (hugoTrans.scanUpdateRecords(GETNDB(step), 0, 0, para) == NDBT_FAILED){ return NDBT_FAILED; } i++; diff --git a/storage/ndb/test/ndbapi/testSystemRestart.cpp b/storage/ndb/test/ndbapi/testSystemRestart.cpp index 901c0e35568..89580c0cef8 100644 --- a/storage/ndb/test/ndbapi/testSystemRestart.cpp +++ b/storage/ndb/test/ndbapi/testSystemRestart.cpp @@ -20,6 +20,7 @@ #include <NdbRestarter.hpp> #include <Vector.hpp> #include <signaldata/DumpStateOrd.hpp> +#include <NdbBackup.hpp> int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ @@ -121,7 +122,7 @@ int runSystemRestart1(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); @@ -142,7 +143,7 @@ int runSystemRestart1(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); @@ -265,7 +266,7 @@ int runSystemRestart2(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); @@ -329,7 +330,7 @@ int runSystemRestartTestUndoLog(NDBT_Context* ctx, NDBT_Step* step){ CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0); CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0); - CHECK(hugoTrans.scanUpdateRecords(pNdb, records) == 0); + CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); CHECK(hugoTrans.loadTable(pNdb, records) == 0); CHECK(utilTrans.clearTable(pNdb, records) == 0); @@ -1293,6 +1294,260 @@ runBug28770(NDBT_Context* ctx, NDBT_Step* step) { return result; } +int +runStopper(NDBT_Context* ctx, NDBT_Step* step) +{ + NdbRestarter restarter; + Uint32 stop = 0; +loop: + while (!ctx->isTestStopped() && + ((stop = ctx->getProperty("StopAbort", Uint32(0))) == 0)) + { + NdbSleep_MilliSleep(30); + } + + if (ctx->isTestStopped()) + { + return NDBT_OK; + } + + ndbout << "Killing in " << stop << "ms..." << flush; + NdbSleep_MilliSleep(stop); + restarter.restartAll(false, true, true); + ctx->setProperty("StopAbort", Uint32(0)); + goto loop; +} + +int runSR_DD_1(NDBT_Context* ctx, NDBT_Step* step) +{ + Ndb* pNdb = GETNDB(step); + int result = NDBT_OK; + Uint32 loops = ctx->getNumLoops(); + int count; + NdbRestarter restarter; + NdbBackup backup(GETNDB(step)->getNodeId()+1); + bool lcploop = ctx->getProperty("LCP", (unsigned)0); + bool all = ctx->getProperty("ALL", (unsigned)0); + + Uint32 i = 1; + Uint32 backupId; + + int val[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; + int lcp = DumpStateOrd::DihMinTimeBetweenLCP; + + int startFrom = 0; + + HugoTransactions hugoTrans(*ctx->getTab()); + while(i<=loops && result != NDBT_FAILED) + { + + if (lcploop) + { + CHECK(restarter.dumpStateAllNodes(&lcp, 1) == 0); + } + + int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes()); + //CHECK(restarter.dumpStateAllNodes(&val, 1) == 0); + + ndbout << "Loop " << i << "/"<< loops <<" started" << endl; + ndbout << "Loading records..." << startFrom << endl; + CHECK(hugoTrans.loadTable(pNdb, startFrom) == 0); + + if (!all) + { + ndbout << "Making " << nodeId << " crash" << endl; + int kill[] = { 9999, 1000, 3000 }; + CHECK(restarter.dumpStateOneNode(nodeId, val, 2) == 0); + CHECK(restarter.dumpStateOneNode(nodeId, kill, 3) == 0); + } + else + { + ndbout << "Crashing cluster" << endl; + ctx->setProperty("StopAbort", 1000 + rand() % (3000 - 1000)); + } + Uint64 end = NdbTick_CurrentMillisecond() + 4000; + Uint32 row = startFrom; + do { + ndbout << "Loading from " << row << " to " << row + 1000 << endl; + if (hugoTrans.loadTableStartFrom(pNdb, row, 1000) != 0) + break; + row += 1000; + } while (NdbTick_CurrentMillisecond() < end); + + if (!all) + { + ndbout << "Waiting for " << nodeId << " to restart" << endl; + CHECK(restarter.waitNodesNoStart(&nodeId, 1) == 0); + ndbout << "Restarting cluster" << endl; + CHECK(restarter.restartAll(false, true, true) == 0); + } + else + { + ndbout << "Waiting for cluster to restart" << endl; + } + CHECK(restarter.waitClusterNoStart() == 0); + CHECK(restarter.startAll() == 0); + CHECK(restarter.waitClusterStarted() == 0); + + ndbout << "Starting backup..." << flush; + CHECK(backup.start(backupId) == 0); + ndbout << "done" << endl; + + int cnt = 0; + CHECK(hugoTrans.selectCount(pNdb, 0, &cnt) == 0); + ndbout << "Found " << cnt << " records..." << endl; + ndbout << "Clearing..." << endl; + CHECK(hugoTrans.clearTable(pNdb, + NdbScanOperation::SF_TupScan, cnt) == 0); + + if (cnt > startFrom) + { + startFrom = cnt; + } + startFrom += 1000; + i++; + } + + ndbout << "runSR_DD_1 finished" << endl; + ctx->stopTest(); + return result; +} + +int runSR_DD_2(NDBT_Context* ctx, NDBT_Step* step) +{ + Ndb* pNdb = GETNDB(step); + int result = NDBT_OK; + Uint32 loops = ctx->getNumLoops(); + Uint32 rows = ctx->getNumRecords(); + int count; + NdbRestarter restarter; + NdbBackup backup(GETNDB(step)->getNodeId()+1); + bool lcploop = ctx->getProperty("LCP", (unsigned)0); + bool all = ctx->getProperty("ALL", (unsigned)0); + + Uint32 i = 1; + Uint32 backupId; + + int val[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; + int lcp = DumpStateOrd::DihMinTimeBetweenLCP; + + int startFrom = 0; + + HugoTransactions hugoTrans(*ctx->getTab()); + while(i<=loops && result != NDBT_FAILED) + { + + if (lcploop) + { + CHECK(restarter.dumpStateAllNodes(&lcp, 1) == 0); + } + + int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes()); + + if (!all) + { + ndbout << "Making " << nodeId << " crash" << endl; + int kill[] = { 9999, 3000, 10000 }; + CHECK(restarter.dumpStateOneNode(nodeId, val, 2) == 0); + CHECK(restarter.dumpStateOneNode(nodeId, kill, 3) == 0); + } + else + { + ndbout << "Crashing cluster" << endl; + ctx->setProperty("StopAbort", 1000 + rand() % (3000 - 1000)); + } + + Uint64 end = NdbTick_CurrentMillisecond() + 11000; + Uint32 row = startFrom; + do { + if (hugoTrans.loadTable(pNdb, rows) != 0) + break; + + if (hugoTrans.clearTable(pNdb, NdbScanOperation::SF_TupScan, rows) != 0) + break; + } while (NdbTick_CurrentMillisecond() < end); + + if (!all) + { + ndbout << "Waiting for " << nodeId << " to restart" << endl; + CHECK(restarter.waitNodesNoStart(&nodeId, 1) == 0); + ndbout << "Restarting cluster" << endl; + CHECK(restarter.restartAll(false, true, true) == 0); + } + else + { + ndbout << "Waiting for cluster to restart" << endl; + } + + CHECK(restarter.waitClusterNoStart() == 0); + CHECK(restarter.startAll() == 0); + CHECK(restarter.waitClusterStarted() == 0); + + ndbout << "Starting backup..." << flush; + CHECK(backup.start(backupId) == 0); + ndbout << "done" << endl; + + int cnt = 0; + CHECK(hugoTrans.selectCount(pNdb, 0, &cnt) == 0); + ndbout << "Found " << cnt << " records..." << endl; + ndbout << "Clearing..." << endl; + CHECK(hugoTrans.clearTable(pNdb, + NdbScanOperation::SF_TupScan, cnt) == 0); + i++; + } + + ndbout << "runSR_DD_2 finished" << endl; + ctx->stopTest(); + return result; +} + +int +runBug27434(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + NdbRestarter restarter; + Ndb* pNdb = GETNDB(step); + const Uint32 nodeCount = restarter.getNumDbNodes(); + + if (nodeCount < 2) + return NDBT_OK; + + int args[] = { DumpStateOrd::DihMaxTimeBetweenLCP }; + int dump[] = { DumpStateOrd::DihStartLcpImmediately }; + + int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_CHECKPOINT, 0 }; + NdbLogEventHandle handle = + ndb_mgm_create_logevent_handle(restarter.handle, filter); + + struct ndb_logevent event; + + do { + int node1 = restarter.getDbNodeId(rand() % nodeCount); + CHECK(restarter.restartOneDbNode(node1, false, true, true) == 0); + NdbSleep_SecSleep(3); + CHECK(restarter.waitNodesNoStart(&node1, 1) == 0); + + CHECK(restarter.dumpStateAllNodes(args, 1) == 0); + + for (Uint32 i = 0; i<3; i++) + { + CHECK(restarter.dumpStateAllNodes(dump, 1) == 0); + while(ndb_logevent_get_next(handle, &event, 0) >= 0 && + event.type != NDB_LE_LocalCheckpointStarted); + while(ndb_logevent_get_next(handle, &event, 0) >= 0 && + event.type != NDB_LE_LocalCheckpointCompleted); + } + + restarter.restartAll(false, true, true); + NdbSleep_SecSleep(3); + CHECK(restarter.waitClusterNoStart() == 0); + restarter.insertErrorInNode(node1, 5046); + restarter.startAll(); + CHECK(restarter.waitClusterStarted() == 0); + } while(false); + + return result; +} NDBT_TESTSUITE(testSystemRestart); TESTCASE("SR1", @@ -1474,6 +1729,72 @@ TESTCASE("Bug24664", STEP(runBug24664); FINALIZER(runClearTable); } +TESTCASE("Bug27434", + "") +{ + INITIALIZER(runWaitStarted); + STEP(runBug27434); +} +TESTCASE("SR_DD_1", "") +{ + TC_PROPERTY("ALL", 1); + INITIALIZER(runWaitStarted); + STEP(runStopper); + STEP(runSR_DD_1); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_1b", "") +{ + INITIALIZER(runWaitStarted); + STEP(runSR_DD_1); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_1_LCP", "") +{ + TC_PROPERTY("ALL", 1); + TC_PROPERTY("LCP", 1); + INITIALIZER(runWaitStarted); + STEP(runStopper); + STEP(runSR_DD_1); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_1b_LCP", "") +{ + TC_PROPERTY("LCP", 1); + INITIALIZER(runWaitStarted); + STEP(runSR_DD_1); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_2", "") +{ + TC_PROPERTY("ALL", 1); + INITIALIZER(runWaitStarted); + STEP(runStopper); + STEP(runSR_DD_2); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_2b", "") +{ + INITIALIZER(runWaitStarted); + STEP(runSR_DD_2); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_2_LCP", "") +{ + TC_PROPERTY("ALL", 1); + TC_PROPERTY("LCP", 1); + INITIALIZER(runWaitStarted); + STEP(runStopper); + STEP(runSR_DD_2); + FINALIZER(runClearTable); +} +TESTCASE("SR_DD_2b_LCP", "") +{ + TC_PROPERTY("LCP", 1); + INITIALIZER(runWaitStarted); + STEP(runSR_DD_2); + FINALIZER(runClearTable); +} TESTCASE("Bug29167", "") { INITIALIZER(runWaitStarted); diff --git a/storage/ndb/test/ndbapi/test_event.cpp b/storage/ndb/test/ndbapi/test_event.cpp index e1e0012d0d8..18825d734a4 100644 --- a/storage/ndb/test/ndbapi/test_event.cpp +++ b/storage/ndb/test/ndbapi/test_event.cpp @@ -21,6 +21,7 @@ #include <NdbAutoPtr.hpp> #include <NdbRestarter.hpp> #include <NdbRestarts.hpp> +#include <signaldata/DumpStateOrd.hpp> #define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb() @@ -1730,7 +1731,7 @@ runScanUpdateUntilStopped(NDBT_Context* ctx, NDBT_Step* step){ HugoTransactions hugoTrans(*ctx->getTab()); while (ctx->isTestStopped() == false) { - if (hugoTrans.scanUpdateRecords(GETNDB(step), records, abort, + if (hugoTrans.scanUpdateRecords(GETNDB(step), 0, abort, parallelism) == NDBT_FAILED){ return NDBT_FAILED; } @@ -1758,6 +1759,85 @@ runInsertDeleteUntilStopped(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug31701(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + + NdbRestarter restarter; + + if (restarter.getNumDbNodes() < 2){ + ctx->stopTest(); + return NDBT_OK; + } + // This should really wait for applier to start...10s is likely enough + NdbSleep_SecSleep(10); + + int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes()); + + int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 }; + if (restarter.dumpStateOneNode(nodeId, val2, 2)) + return NDBT_FAILED; + + restarter.insertErrorInNode(nodeId, 13033); + if (restarter.waitNodesNoStart(&nodeId, 1)) + return NDBT_FAILED; + + if (restarter.startNodes(&nodeId, 1)) + return NDBT_FAILED; + + if (restarter.waitClusterStarted()) + return NDBT_FAILED; + + + int records = ctx->getNumRecords(); + HugoTransactions hugoTrans(*ctx->getTab()); + + if(ctx->getPropertyWait("LastGCI", ~(Uint32)0)) + { + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + + hugoTrans.clearTable(GETNDB(step), 0); + + if (hugoTrans.loadTable(GETNDB(step), 3*records, 1, true, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + + if (hugoTrans.pkDelRecords(GETNDB(step), 3*records, 1, true, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + if (hugoTrans.loadTable(GETNDB(step), records, 1, true, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + if (hugoTrans.pkUpdateRecords(GETNDB(step), records, 1, 1) != 0){ + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + + ctx->setProperty("LastGCI", hugoTrans.m_latest_gci); + if(ctx->getPropertyWait("LastGCI", ~(Uint32)0)) + { + g_err << "FAIL " << __LINE__ << endl; + return NDBT_FAILED; + } + + ctx->stopTest(); + return NDBT_OK; +} + NDBT_TESTSUITE(test_event); TESTCASE("BasicEventOperation", "Verify that we can listen to Events" @@ -1887,6 +1967,14 @@ TESTCASE("Bug27169", ""){ STEP(runRestarterLoop); FINALIZER(runDropEvent); } +TESTCASE("Bug31701", ""){ + INITIALIZER(runCreateEvent); + INITIALIZER(runCreateShadowTable); + STEP(runEventApplier); + STEP(runBug31701); + FINALIZER(runDropEvent); + FINALIZER(runDropShadowTable); +} NDBT_TESTSUITE_END(test_event); int main(int argc, const char** argv){ diff --git a/storage/ndb/test/run-test/daily-basic-tests.txt b/storage/ndb/test/run-test/daily-basic-tests.txt index b7a3a15dae7..103675d8e35 100644 --- a/storage/ndb/test/run-test/daily-basic-tests.txt +++ b/storage/ndb/test/run-test/daily-basic-tests.txt @@ -65,6 +65,14 @@ args: -n PkRead max-time: 500 cmd: testBasic +args: -n PkSimpleRead + +max-time: 500 +cmd: testBasic +args: -n PkDirtyRead + +max-time: 500 +cmd: testBasic args: -n PkUpdate max-time: 500 @@ -555,7 +563,7 @@ args: -n Bug25554 T1 max-time: 3000 cmd: testNodeRestart -args: -n Bug25984 +args: -n Bug25984 T1 max-time: 1000 cmd: testNodeRestart @@ -575,6 +583,14 @@ args: -n Bug29364 T1 # # DICT TESTS +max-time: 500 +cmd: testDict +args: -n Bug29501 T1 + +max-time: 500 +cmd: testDict +args: -n testDropDDObjects T1 + max-time: 1500 cmd: testDict args: -n CreateAndDrop @@ -864,6 +880,10 @@ max-time: 1000 cmd: testNodeRestart args: -n Bug27466 T1 +max-time: 1500 +cmd: testSystemRestart +args: -n Bug27434 T1 + max-time: 1000 cmd: test_event args: -l 10 -n Bug27169 T1 @@ -945,3 +965,77 @@ args: -n Bug28804 T1 T3 max-time: 180 cmd: testIndex args: -n Bug28804_ATTRINFO T1 T3 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1 D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1b D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1 D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1b D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1_LCP D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1b_LCP D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1_LCP D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_1b_LCP D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2 D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2b D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2 D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2b D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2_LCP D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2b_LCP D1 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2_LCP D2 + +max-time: 1500 +cmd: testSystemRestart +args: -n SR_DD_2b_LCP D2 + +max-time: 600 +cmd: testNodeRestart +args: -n Bug31525 T1 + +max-time: 300 +cmd: test_event +args: -n Bug31701 T1 + + diff --git a/storage/ndb/test/src/HugoOperations.cpp b/storage/ndb/test/src/HugoOperations.cpp index 1a2e5180f1f..93a9eaf435a 100644 --- a/storage/ndb/test/src/HugoOperations.cpp +++ b/storage/ndb/test/src/HugoOperations.cpp @@ -93,6 +93,7 @@ rand_lock_mode: case NdbOperation::LM_Read: case NdbOperation::LM_Exclusive: case NdbOperation::LM_CommittedRead: + case NdbOperation::LM_SimpleRead: if(idx && idx->getType() == NdbDictionary::Index::OrderedIndex && pIndexScanOp == 0) { diff --git a/storage/ndb/test/src/HugoTransactions.cpp b/storage/ndb/test/src/HugoTransactions.cpp index 3a1600815e0..0e5f7cd8115 100644 --- a/storage/ndb/test/src/HugoTransactions.cpp +++ b/storage/ndb/test/src/HugoTransactions.cpp @@ -341,50 +341,14 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, int HugoTransactions::scanUpdateRecords(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - if(m_defaultScanUpdateMethod == 1){ - return scanUpdateRecords1(pNdb, records, abortPercent, parallelism); - } else if(m_defaultScanUpdateMethod == 2){ - return scanUpdateRecords2(pNdb, records, abortPercent, parallelism); - } else { - return scanUpdateRecords3(pNdb, records, abortPercent, parallelism); - } -} - -// Scan all records exclusive and update -// them one by one -int -HugoTransactions::scanUpdateRecords1(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - return scanUpdateRecords3(pNdb, records, abortPercent, 1); -} - -// Scan all records exclusive and update -// them batched by asking nextScanResult to -// give us all cached records before fetching new -// records from db -int -HugoTransactions::scanUpdateRecords2(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - return scanUpdateRecords3(pNdb, records, abortPercent, parallelism); -} - -int -HugoTransactions::scanUpdateRecords3(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - int retryAttempt = 0; + NdbScanOperation::ScanFlag flags, + int records, + int abortPercent, + int parallelism){ + int retryAttempt = 0; int check, a; NdbScanOperation *pOp; - while (true){ restart: if (retryAttempt++ >= m_retryMax){ @@ -411,8 +375,9 @@ restart: return NDBT_FAILED; } - if( pOp->readTuplesExclusive(parallelism) ) { - ERR(pTrans->getNdbError()); + if( pOp->readTuples(NdbOperation::LM_Exclusive, flags, + parallelism)) + { closeTransaction(pNdb); return NDBT_FAILED; } @@ -429,15 +394,18 @@ restart: check = pTrans->execute(NoCommit, AbortOnError); if( check == -1 ) { const NdbError err = pTrans->getNdbError(); - ERR(err); - closeTransaction(pNdb); if (err.status == NdbError::TemporaryError){ + ERR(err); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); + retryAttempt++; continue; } + ERR(err); + closeTransaction(pNdb); return NDBT_FAILED; } - + // Abort after 1-100 or 1-records rows int ranVal = rand(); int abortCount = ranVal % (records == 0 ? 100 : records); @@ -448,75 +416,114 @@ restart: abortTrans = true; } + int eof; int rows = 0; - while((check = pOp->nextResult(true)) == 0){ - do { - rows++; - NdbOperation* pUp = pOp->updateCurrentTuple(); - if(pUp == 0){ + while((eof = pOp->nextResult(true)) == 0){ + rows++; + if (calc.verifyRowValues(&row) != 0){ + closeTransaction(pNdb); + return NDBT_FAILED; + } + + if (abortCount == rows && abortTrans == true){ + ndbout << "Scan is aborted" << endl; + g_info << "Scan is aborted" << endl; + pOp->close(); + if( check == -1 ) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); return NDBT_FAILED; } - const int updates = calc.getUpdatesValue(&row) + 1; - const int r = calc.getIdValue(&row); - for(a = 0; a<tab.getNoOfColumns(); a++){ - if (tab.getColumn(a)->getPrimaryKey() == false){ - if(setValueForAttr(pUp, a, r, updates ) != 0){ - ERR(pTrans->getNdbError()); - closeTransaction(pNdb); - return NDBT_FAILED; - } - } - } - - if (rows == abortCount && abortTrans == true){ - g_info << "Scan is aborted" << endl; - // This scan should be aborted - closeTransaction(pNdb); - return NDBT_OK; - } - } while((check = pOp->nextResult(false)) == 0); - - if(check != -1){ - check = pTrans->execute(Commit, AbortOnError); - if(check != -1) - m_latest_gci = pTrans->getGCI(); - pTrans->restart(); - } - - const NdbError err = pTrans->getNdbError(); - if( check == -1 ) { + closeTransaction(pNdb); - ERR(err); - if (err.status == NdbError::TemporaryError){ - NdbSleep_MilliSleep(50); - goto restart; - } - return NDBT_FAILED; + return NDBT_OK; } } - - const NdbError err = pTrans->getNdbError(); - if( check == -1 ) { - closeTransaction(pNdb); - ERR(err); + if (eof == -1) { + const NdbError err = pTrans->getNdbError(); + if (err.status == NdbError::TemporaryError){ + ERR_INFO(err); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); - goto restart; + switch (err.code){ + case 488: + case 245: + case 490: + // Too many active scans, no limit on number of retry attempts + break; + default: + retryAttempt++; + } + continue; } + ERR(err); + closeTransaction(pNdb); return NDBT_FAILED; } - + closeTransaction(pNdb); + + g_info << rows << " rows have been read" << endl; + if (records != 0 && rows != records){ + g_err << "Check expected number of records failed" << endl + << " expected=" << records <<", " << endl + << " read=" << rows << endl; + return NDBT_FAILED; + } - g_info << rows << " rows have been updated" << endl; return NDBT_OK; } return NDBT_FAILED; } int +HugoTransactions::scanUpdateRecords(Ndb* pNdb, + int records, + int abortPercent, + int parallelism){ + + return scanUpdateRecords(pNdb, + (NdbScanOperation::ScanFlag)0, + records, abortPercent, parallelism); +} + +// Scan all records exclusive and update +// them one by one +int +HugoTransactions::scanUpdateRecords1(Ndb* pNdb, + int records, + int abortPercent, + int parallelism){ + return scanUpdateRecords(pNdb, + (NdbScanOperation::ScanFlag)0, + records, abortPercent, 1); +} + +// Scan all records exclusive and update +// them batched by asking nextScanResult to +// give us all cached records before fetching new +// records from db +int +HugoTransactions::scanUpdateRecords2(Ndb* pNdb, + int records, + int abortPercent, + int parallelism){ + return scanUpdateRecords(pNdb, (NdbScanOperation::ScanFlag)0, + records, abortPercent, parallelism); +} + +int +HugoTransactions::scanUpdateRecords3(Ndb* pNdb, + int records, + int abortPercent, + int parallelism) +{ + return scanUpdateRecords(pNdb, (NdbScanOperation::ScanFlag)0, + records, abortPercent, parallelism); +} + +int HugoTransactions::loadTable(Ndb* pNdb, int records, int batch, @@ -524,7 +531,22 @@ HugoTransactions::loadTable(Ndb* pNdb, int doSleep, bool oneTrans, int value, - bool abort){ + bool abort) +{ + return loadTableStartFrom(pNdb, 0, records, batch, allowConstraintViolation, + doSleep, oneTrans, value, abort); +} + +int +HugoTransactions::loadTableStartFrom(Ndb* pNdb, + int startFrom, + int records, + int batch, + bool allowConstraintViolation, + int doSleep, + bool oneTrans, + int value, + bool abort){ int check; int retryAttempt = 0; int retryMax = 5; @@ -543,8 +565,9 @@ HugoTransactions::loadTable(Ndb* pNdb, << " -> rows/commit = " << batch << endl; } + Uint32 orgbatch = batch; g_info << "|- Inserting records..." << endl; - for (int c=0 ; c<records ; ){ + for (int c=0 ; c<records; ){ bool closeTrans = true; if(c + batch > records) @@ -578,7 +601,7 @@ HugoTransactions::loadTable(Ndb* pNdb, } } - if(pkInsertRecord(pNdb, c, batch, value) != NDBT_OK) + if(pkInsertRecord(pNdb, c + startFrom, batch, value) != NDBT_OK) { ERR(pTrans->getNdbError()); closeTransaction(pNdb); @@ -625,6 +648,7 @@ HugoTransactions::loadTable(Ndb* pNdb, ERR(err); NdbSleep_MilliSleep(50); retryAttempt++; + batch = 1; continue; break; @@ -670,7 +694,14 @@ HugoTransactions::loadTable(Ndb* pNdb, int HugoTransactions::fillTable(Ndb* pNdb, - int batch){ + int batch){ + return fillTableStartFrom(pNdb, 0, batch); +} + +int +HugoTransactions::fillTableStartFrom(Ndb* pNdb, + int startFrom, + int batch){ int check; int retryAttempt = 0; int retryMax = 5; @@ -688,7 +719,7 @@ HugoTransactions::fillTable(Ndb* pNdb, << " -> rows/commit = " << batch << endl; } - for (int c=0 ; ; ){ + for (int c=startFrom ; ; ){ if (retryAttempt >= retryMax){ g_info << "Record " << c << " could not be inserted, has retried " diff --git a/storage/ndb/test/src/Makefile.am b/storage/ndb/test/src/Makefile.am index a025579cb72..aa486108235 100644 --- a/storage/ndb/test/src/Makefile.am +++ b/storage/ndb/test/src/Makefile.am @@ -24,7 +24,7 @@ libNDBT_a_SOURCES = \ NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \ NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \ NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \ - CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp + CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp dbutil.cpp INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi diff --git a/storage/ndb/test/src/NDBT_Thread.cpp b/storage/ndb/test/src/NDBT_Thread.cpp index 56cf2f6815b..ff6785724ba 100644 --- a/storage/ndb/test/src/NDBT_Thread.cpp +++ b/storage/ndb/test/src/NDBT_Thread.cpp @@ -131,7 +131,7 @@ NDBT_Thread::exit() m_state = Exit; signal(); unlock(); -}; +} void NDBT_Thread::join() diff --git a/storage/ndb/test/src/NdbRestarts.cpp b/storage/ndb/test/src/NdbRestarts.cpp index 6ec520887b5..86e71f4b3fc 100644 --- a/storage/ndb/test/src/NdbRestarts.cpp +++ b/storage/ndb/test/src/NdbRestarts.cpp @@ -607,6 +607,7 @@ NFDuringNR_codes[] = { 5026, 7139, 7132, + 5045, //LCP 8000, diff --git a/storage/ndb/test/src/UtilTransactions.cpp b/storage/ndb/test/src/UtilTransactions.cpp index 5a408140c8e..776ffd176b3 100644 --- a/storage/ndb/test/src/UtilTransactions.cpp +++ b/storage/ndb/test/src/UtilTransactions.cpp @@ -42,38 +42,9 @@ UtilTransactions::UtilTransactions(Ndb* ndb, int UtilTransactions::clearTable(Ndb* pNdb, - int records, - int parallelism){ - if(m_defaultClearMethod == 1){ - return clearTable1(pNdb, records, parallelism); - } else if(m_defaultClearMethod == 2){ - return clearTable2(pNdb, records, parallelism); - } else { - return clearTable3(pNdb, records, parallelism); - } -} - - -int -UtilTransactions::clearTable1(Ndb* pNdb, - int records, - int parallelism) -{ - return clearTable3(pNdb, records, 1); -} - -int -UtilTransactions::clearTable2(Ndb* pNdb, - int records, - int parallelism) -{ - return clearTable3(pNdb, records, parallelism); -} - -int -UtilTransactions::clearTable3(Ndb* pNdb, - int records, - int parallelism){ + NdbScanOperation::ScanFlag flags, + int records, + int parallelism){ // Scan all records exclusive and delete // them one by one int retryAttempt = 0; @@ -116,7 +87,7 @@ UtilTransactions::clearTable3(Ndb* pNdb, goto failed; } - if( pOp->readTuplesExclusive(par) ) { + if( pOp->readTuples(NdbOperation::LM_Exclusive, flags, par) ) { err = pTrans->getNdbError(); goto failed; } @@ -180,6 +151,43 @@ UtilTransactions::clearTable3(Ndb* pNdb, } int +UtilTransactions::clearTable(Ndb* pNdb, + int records, + int parallelism){ + + return clearTable(pNdb, (NdbScanOperation::ScanFlag)0, + records, parallelism); +} + + +int +UtilTransactions::clearTable1(Ndb* pNdb, + int records, + int parallelism) +{ + return clearTable(pNdb, (NdbScanOperation::ScanFlag)0, + records, 1); +} + +int +UtilTransactions::clearTable2(Ndb* pNdb, + int records, + int parallelism) +{ + return clearTable(pNdb, (NdbScanOperation::ScanFlag)0, + records, parallelism); +} + +int +UtilTransactions::clearTable3(Ndb* pNdb, + int records, + int parallelism) +{ + return clearTable(pNdb, (NdbScanOperation::ScanFlag)0, + records, parallelism); +} + +int UtilTransactions::copyTableData(Ndb* pNdb, const char* destName){ // Scan all records and copy diff --git a/storage/ndb/test/src/dbutil.cpp b/storage/ndb/test/src/dbutil.cpp new file mode 100755 index 00000000000..0c936f53182 --- /dev/null +++ b/storage/ndb/test/src/dbutil.cpp @@ -0,0 +1,176 @@ +// dbutil.cpp: implementation of the database utilities class. +// +////////////////////////////////////////////////////////////////////// + +#include "dbutil.hpp" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +dbutil::dbutil(const char * dbname) +{ + memset(host,' ',sizeof(host)); + memset(user,' ',sizeof(pass)); + memset(dbs,' ',sizeof(dbs)); + port = 0; + memset(socket,' ',sizeof(socket)); + this->SetDbName(dbname); +} + +dbutil::~dbutil() +{ + this->DatabaseLogout(); +} + +////////////////////////////////////////////////////////////////////// +// Database Login +////////////////////////////////////////////////////////////////////// +void dbutil::DatabaseLogin(const char* system, + const char* usr, + const char* password, + unsigned int portIn, + const char* sockIn, + bool transactional + ){ + if (!(myDbHandel = mysql_init(NULL))){ + myerror("mysql_init() failed"); + exit(1); + } + this->SetUser(usr); + this->SetHost(system); + this->SetPassword(password); + this->SetPort(portIn); + this->SetSocket(sockIn); + + if (!(mysql_real_connect(myDbHandel, host, user, pass, "test", port, socket, 0))){ + myerror("connection failed"); + mysql_close(myDbHandel); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + + myDbHandel->reconnect= 1; + + /* set AUTOCOMMIT */ + if(!transactional){ + mysql_autocommit(myDbHandel, TRUE); + } + else{ + mysql_autocommit(myDbHandel, FALSE); + } + + fprintf(stdout, "\n\tConnected to MySQL server version: %s (%lu)\n\n", + mysql_get_server_info(myDbHandel), + (unsigned long) mysql_get_server_version(myDbHandel)); +} + +////////////////////////////////////////////////////////////////////// +// Database Logout +////////////////////////////////////////////////////////////////////// +void dbutil::DatabaseLogout(){ + if (myDbHandel){ + fprintf(stdout, "\n\tClosing the MySQL database connection ...\n\n"); + mysql_close(myDbHandel); + } +} + +////////////////////////////////////////////////////////////////////// +// Prepare MySQL Statements Cont +////////////////////////////////////////////////////////////////////// +MYSQL_STMT *STDCALL dbutil::MysqlSimplePrepare(const char *query){ +#ifdef DEBUG +printf("Inside dbutil::MysqlSimplePrepare\n"); +#endif +int result = 0; + MYSQL_STMT *my_stmt= mysql_stmt_init(this->GetDbHandel()); + if (my_stmt && (result = mysql_stmt_prepare(my_stmt, query, strlen(query)))){ + printf("res = %s\n",mysql_stmt_error(my_stmt)); + mysql_stmt_close(my_stmt); + return 0; + } + return my_stmt; +} +////////////////////////////////////////////////////////////////////// +// Error Printing +////////////////////////////////////////////////////////////////////// +void dbutil::PrintError(const char *msg){ + if (this->GetDbHandel() + && mysql_errno(this->GetDbHandel())){ + if (this->GetDbHandel()->server_version){ + fprintf(stdout, "\n [MySQL-%s]", + this->GetDbHandel()->server_version); + } + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", + mysql_errno(this->GetDbHandel()), + mysql_error(this->GetDbHandel())); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); +} + +void dbutil::PrintStError(MYSQL_STMT *stmt, const char *msg) +{ + if (stmt && mysql_stmt_errno(stmt)) + { + if (this->GetDbHandel() + && this->GetDbHandel()->server_version) + fprintf(stdout, "\n [MySQL-%s]", + this->GetDbHandel()->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); +} +///////////////////////////////////////////////////// +int dbutil::Select_DB() +{ + return mysql_select_db(this->GetDbHandel(), + this->GetDbName()); +} +//////////////////////////////////////////////////// +int dbutil::Do_Query(char * stm) +{ + return mysql_query(this->GetDbHandel(), stm); +} +//////////////////////////////////////////////////// +const char * dbutil::GetError() +{ + return mysql_error(this->GetDbHandel()); +} +//////////////////////////////////////////////////// +int dbutil::GetErrorNumber() +{ + return mysql_errno(this->GetDbHandel()); +} +//////////////////////////////////////////////////// +unsigned long dbutil::SelectCountTable(const char * table) +{ + unsigned long count = 0; + MYSQL_RES *result; + char query[1024]; + MYSQL_ROW row; + + sprintf(query,"select count(*) from `%s`", table); + if (mysql_query(this->GetDbHandel(),query) || !(result=mysql_store_result(this->GetDbHandel()))) + { + printf("error\n"); + return 1; + } + row= mysql_fetch_row(result); + count= (ulong) strtoull(row[0], (char**) 0, 10); + mysql_free_result(result); + + return count; +} +void dbutil::Die(const char *file, int line, const char *expr){ + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + abort(); +} + + diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index d3ba0660198..0cb9ff49128 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -17100,6 +17100,99 @@ static void test_bug31418() } + +/** + Bug#31669 Buffer overflow in mysql_change_user() +*/ + +#define LARGE_BUFFER_SIZE 2048 + +static void test_bug31669() +{ + int rc; + static char buff[LARGE_BUFFER_SIZE+1]; +#ifndef EMBEDDED_LIBRARY + static char user[USERNAME_CHAR_LENGTH+1]; + static char db[NAME_CHAR_LEN+1]; + static char query[LARGE_BUFFER_SIZE*2]; +#endif + + DBUG_ENTER("test_bug31669"); + myheader("test_bug31669"); + + rc= mysql_change_user(mysql, NULL, NULL, NULL); + DIE_UNLESS(rc); + + rc= mysql_change_user(mysql, "", "", ""); + DIE_UNLESS(rc); + + memset(buff, 'a', sizeof(buff)); + + rc= mysql_change_user(mysql, buff, buff, buff); + DIE_UNLESS(rc); + + rc = mysql_change_user(mysql, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + +#ifndef EMBEDDED_LIBRARY + memset(db, 'a', sizeof(db)); + db[NAME_CHAR_LEN]= 0; + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + memset(user, 'b', sizeof(user)); + user[USERNAME_CHAR_LENGTH]= 0; + memset(buff, 'c', sizeof(buff)); + buff[LARGE_BUFFER_SIZE]= 0; + strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY " + "'", buff, "' WITH GRANT OPTION", NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + rc= mysql_query(mysql, "FLUSH PRIVILEGES"); + myquery(rc); + + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(!rc); + + user[USERNAME_CHAR_LENGTH-1]= 'a'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + user[USERNAME_CHAR_LENGTH-1]= 'b'; + buff[LARGE_BUFFER_SIZE-1]= 'd'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + buff[LARGE_BUFFER_SIZE-1]= 'c'; + db[NAME_CHAR_LEN-1]= 'e'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(rc); + + db[NAME_CHAR_LEN-1]= 'a'; + rc= mysql_change_user(mysql, user, buff, db); + DIE_UNLESS(!rc); + + rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1); + DIE_UNLESS(rc); + + rc = mysql_change_user(mysql, opt_user, opt_password, current_db); + DIE_UNLESS(!rc); + + strxmov(query, "DROP DATABASE ", db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "DELETE FROM mysql.user WHERE User='", user, "'", NullS); + rc= mysql_query(mysql, query); + myquery(rc); + DIE_UNLESS(mysql_affected_rows(mysql) == 1); +#endif + + DBUG_VOID_RETURN; +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -17403,6 +17496,7 @@ static struct my_tests_st my_tests[]= { { "test_bug30472", test_bug30472 }, { "test_bug20023", test_bug20023 }, { "test_bug31418", test_bug31418 }, + { "test_bug31669", test_bug31669 }, { 0, 0 } }; |