From f75ac7fb82d426b7392781b6292dc9780aae3b8d Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Thu, 1 Sep 2005 00:13:02 +0200 Subject: [PATCH 001/154] fix for bug#12913 (Simple SQL can crash server or connection) (not initialized member leads to server crash) --- mysql-test/r/create.result | 5 +++++ mysql-test/t/create.test | 7 +++++++ sql/sql_table.cc | 1 + 3 files changed, 13 insertions(+) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 95757fbd7dc..4de428868a0 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -587,6 +587,11 @@ DESC t2; Field Type Null Key Default Extra f2 varchar(86) YES NULL DROP TABLE t1,t2; +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +f1 +a +DROP TABLE t12913; create database mysqltest; use mysqltest; drop database mysqltest; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 55321a81f5e..5c69d8f7edf 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -501,6 +501,13 @@ AS f2 FROM t1; DESC t2; DROP TABLE t1,t2; +# +# Bug#12913 Simple SQL can crash server or connection +# +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +DROP TABLE t12913; + # # Bug#11028: Crash on create table like # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 92db0143980..b8ef6ed342a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -649,6 +649,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->decimals= dup_field->decimals; sql_field->flags= dup_field->flags; sql_field->unireg_check= dup_field->unireg_check; + sql_field->interval= dup_field->interval; it2.remove(); // Remove first (create) definition select_field_pos--; break; From d54a54c7abf2315d937205265ba165c3ae4a4940 Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Thu, 27 Oct 2005 16:41:55 +0200 Subject: [PATCH 002/154] bug#13078 - ndb memleak when doing ordered index scan on index with column larger than 32 bytes --- ndb/src/ndbapi/NdbImpl.hpp | 10 ++++++---- ndb/src/ndbapi/NdbRecAttr.cpp | 4 ++++ ndb/src/ndbapi/ndb_cluster_connection.cpp | 13 +++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp index 33aaca8de96..aa918a6f9f8 100644 --- a/ndb/src/ndbapi/NdbImpl.hpp +++ b/ndb/src/ndbapi/NdbImpl.hpp @@ -78,11 +78,9 @@ public: /** * NOTE free lists must be _after_ theNdbObjectIdMap take * assure that destructors are run in correct order + * NOTE these has to be in this specific order to make destructor run in + * correct order */ - Ndb_free_list_t theConIdleList; - Ndb_free_list_t theOpIdleList; - Ndb_free_list_t theScanOpIdleList; - Ndb_free_list_t theIndexOpIdleList; Ndb_free_list_t theRecAttrIdleList; Ndb_free_list_t theSignalIdleList; Ndb_free_list_t theLabelList; @@ -91,6 +89,10 @@ public: Ndb_free_list_t theCallList; Ndb_free_list_t theNdbBlobIdleList; Ndb_free_list_t theScanList; + Ndb_free_list_t theScanOpIdleList; + Ndb_free_list_t theOpIdleList; + Ndb_free_list_t theIndexOpIdleList; + Ndb_free_list_t theConIdleList; }; #ifdef VM_TRACE diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp index f993c652bf9..26039fb7867 100644 --- a/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/ndb/src/ndbapi/NdbRecAttr.cpp @@ -35,6 +35,7 @@ Adjust: 971206 UABRONM First version NdbRecAttr::NdbRecAttr(Ndb*) { + theStorageX = 0; init(); } @@ -64,6 +65,9 @@ NdbRecAttr::setup(const NdbColumnImpl* anAttrInfo, char* aValue) theNULLind = 0; m_nullable = anAttrInfo->m_nullable; + if (theStorageX) + delete[] theStorageX; + // check alignment to signal data // a future version could check alignment per data type as well diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 4fcf4d08396..a313a973a42 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -308,6 +308,19 @@ Ndb_cluster_connection_impl::~Ndb_cluster_connection_impl() // fragmentToNodeMap.release(); + if (ndb_global_event_buffer_mutex != NULL) + { + NdbMutex_Destroy(ndb_global_event_buffer_mutex); + ndb_global_event_buffer_mutex= NULL; + } +#ifdef VM_TRACE + if (ndb_print_state_mutex != NULL) + { + NdbMutex_Destroy(ndb_print_state_mutex); + ndb_print_state_mutex= NULL; + } +#endif + DBUG_VOID_RETURN; } From e5eb7cbf2958663dda1b72e1c0d98e66d25d218c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 31 Oct 2005 12:25:08 +0100 Subject: [PATCH 003/154] WL#2930 Adding view and cursor 'protocols' to mysqltest - Cleanup of mysqltest.c before extending it --- client/mysqltest.c | 1531 +++++++++++++-------------- mysql-test/include/master-slave.inc | 6 +- mysql-test/include/ps_query.inc | 1 - mysql-test/r/mysqltest.result | 3 + mysql-test/r/ps_2myisam.result | 2 + mysql-test/r/ps_3innodb.result | 2 + mysql-test/r/ps_4heap.result | 2 + mysql-test/r/ps_5merge.result | 4 + mysql-test/r/ps_6bdb.result | 2 + mysql-test/r/ps_7ndb.result | 2 + mysql-test/t/alias.test | 2 - mysql-test/t/group_by.test | 4 - mysql-test/t/mysqltest.test | 9 + mysql-test/t/union.test | 21 - 14 files changed, 761 insertions(+), 830 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 6653d24e575..308bf6f9b79 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -248,8 +248,6 @@ typedef struct int read_lines,current_line; } PARSER; -MYSQL_RES *last_result=0; - PARSER parser; MASTER_POS master_pos; /* if set, all results are concated and compared against this file */ @@ -437,7 +435,7 @@ static VAR* var_init(VAR* v, const char *name, int name_len, const char *val, static void var_free(void* v); int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); -void reject_dump(const char *record_file, char *buf, int size); +void dump_result_to_reject_file(const char *record_file, char *buf, int size); int close_connection(struct st_query*); static void set_charset(struct st_query*); @@ -464,9 +462,8 @@ void free_replace(); static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); void free_pointer_array(POINTER_ARRAY *pa); static int initialize_replace_buffer(void); -static void free_replace_buffer(void); static void do_eval(DYNAMIC_STRING *query_eval, const char *query); -void str_to_file(const char *fname, char *str, int size); +static void str_to_file(const char *fname, char *str, int size); int do_server_op(struct st_query *q,const char *op); struct st_replace *glob_replace; @@ -491,10 +488,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); -static int handle_error(const char *query, struct st_query *q, - unsigned int err_errno, const char *err_error, - const char *err_sqlstate, DYNAMIC_STRING *ds); -static int handle_no_error(struct st_query *q); +static void handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds); +static void handle_no_error(struct st_query *q); static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { @@ -541,8 +538,6 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char *query) static void close_cons() { DBUG_ENTER("close_cons"); - if (last_result) - mysql_free_result(last_result); for (--next_con; next_con >= cons; --next_con) { mysql_close(&next_con->mysql); @@ -734,7 +729,21 @@ err: DBUG_RETURN(res); } -static int check_result(DYNAMIC_STRING* ds, const char *fname, +/* + Check the content of ds against content of file fname + + SYNOPSIS + check_result + ds - content to be checked + fname - name of file to check against + require_option - if set and check fails, the test will be aborted with the special + exit code "not supported test" + + RETURN VALUES + error - the function will not return + +*/ +static void check_result(DYNAMIC_STRING* ds, const char *fname, my_bool require_option) { int res= dyn_string_cmp(ds, fname); @@ -746,17 +755,18 @@ static int check_result(DYNAMIC_STRING* ds, const char *fname, case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - verbose_msg("Result length mismatch"); + dump_result_to_reject_file(fname, ds->str, ds->length); + die("Result length mismatch"); break; case RESULT_CONTENT_MISMATCH: - verbose_msg("Result content mismatch"); + dump_result_to_reject_file(fname, ds->str, ds->length); + die("Result content mismatch"); break; default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); } - if (res != RESULT_OK) - reject_dump(fname, ds->str, ds->length); - DBUG_RETURN(res); + + DBUG_VOID_RETURN; } @@ -1043,7 +1053,6 @@ static void do_exec(struct st_query *query) { int error; DYNAMIC_STRING *ds= NULL; - DYNAMIC_STRING ds_tmp; char buf[1024]; FILE *res_file; char *cmd= query->first_argument; @@ -1070,14 +1079,7 @@ static void do_exec(struct st_query *query) } else { - if (query->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; - + ds= &ds_res; while (fgets(buf, sizeof(buf), res_file)) replace_dynstr_append(ds, buf); } @@ -1118,25 +1120,7 @@ static void do_exec(struct st_query *query) cmd, query->expected_errno[0].code.errnum); } - if (!disable_result_log) - { - if (glob_replace) - free_replace(); - - if (record) - { - if (!query->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(query->record_file, ds->str, ds->length); - } - else if (query->record_file[0]) - { - error= check_result(ds, query->record_file, query->require_file); - } - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - } + free_replace(); } @@ -1354,25 +1338,16 @@ int do_echo(struct st_query *q) { char *p= q->first_argument; DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; VAR v; var_init(&v,0,0,0,0); - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 256, 512); - ds= &ds_tmp; - } - else - ds= &ds_res; + ds= &ds_res; eval_expr(&v, p, 0); /* NULL terminated */ if (v.str_val_len) dynstr_append_mem(ds, v.str_val, v.str_val_len); dynstr_append_mem(ds, "\n", 1); var_free(&v); - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); q->last_argument= q->end; return 0; } @@ -1401,7 +1376,7 @@ wait_for_position: die("failed in %s: %d: %s", query_buf, mysql_errno(mysql), mysql_error(mysql)); - if (!(last_result= res= mysql_store_result(mysql))) + if (!(res= mysql_store_result(mysql))) die("mysql_store_result() returned NULL for '%s'", query_buf); if (!(row= mysql_fetch_row(res))) die("empty result in %s", query_buf); @@ -1418,7 +1393,6 @@ wait_for_position: goto wait_for_position; } mysql_free_result(res); - last_result=0; if (rpl_parse) mysql_enable_rpl_parse(mysql); @@ -1457,13 +1431,13 @@ int do_save_master_pos() die("failed in show master status: %d: %s", mysql_errno(mysql), mysql_error(mysql)); - if (!(last_result =res = mysql_store_result(mysql))) + if (!(res = mysql_store_result(mysql))) die("mysql_store_result() retuned NULL for '%s'", query); if (!(row = mysql_fetch_row(res))) die("empty result in show master status"); strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1); master_pos.pos = strtoul(row[1], (char**) 0, 10); - mysql_free_result(res); last_result=0; + mysql_free_result(res); if (rpl_parse) mysql_enable_rpl_parse(mysql); @@ -1832,7 +1806,7 @@ void free_replace() { my_free((char*) glob_replace,MYF(0)); glob_replace=0; - free_replace_buffer(); + my_free(out_buff,MYF(MY_WME)); } DBUG_VOID_RETURN; } @@ -2029,21 +2003,11 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, const char* db, int port, const char* sock, int* create_conn) { - DYNAMIC_STRING ds_tmp, *ds; + DYNAMIC_STRING *ds; my_bool reconnect= 1; int error= 0; - /* - Altough we ignore --require or --result before connect() command we still - need to handle record_file because of "@result_file sql-command" syntax. - */ - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; + ds= &ds_res; if (!disable_query_log) { @@ -2076,13 +2040,15 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, CLIENT_MULTI_STATEMENTS)) { - error= handle_error("connect", q, mysql_errno(con), mysql_error(con), - mysql_sqlstate(con), ds); + handle_error("connect", q, mysql_errno(con), mysql_error(con), + mysql_sqlstate(con), ds); *create_conn= 0; goto err; } - else if (handle_no_error(q)) + else { + handle_no_error(q); + /* Fail if there was no error but we expected it. We also don't want to have connection in this case. @@ -2099,20 +2065,8 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, */ mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect); - if (record) - { - if (!q->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - error|= check_result(ds, q->record_file, q->require_file); - err: free_replace(); - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); return error; } @@ -2470,7 +2424,7 @@ int read_line(char *buf, int size) state= R_Q; } else - state= R_NORMAL; +state= R_NORMAL; break; case R_Q: @@ -2559,7 +2513,7 @@ static char read_query_buf[MAX_QUERY]; int read_query(struct st_query** q_ptr) { - char *p= read_query_buf, *p1; + char *p= read_query_buf; struct st_query* q; DBUG_ENTER("read_query"); @@ -2578,10 +2532,13 @@ int read_query(struct st_query** q_ptr) q->type= Q_UNKNOWN; q->query_buf= q->query= 0; + read_query_buf[0]= 0; if (read_line(read_query_buf, sizeof(read_query_buf))) { + check_eol_junk(read_query_buf); DBUG_RETURN(1); } + DBUG_PRINT("info", ("query: %s", read_query_buf)); if (*p == '#') { @@ -2606,15 +2563,6 @@ int read_query(struct st_query** q_ptr) { while (*p && my_isspace(charset_info, *p)) p++ ; - if (*p == '@') - { - p++; - p1 = q->record_file; - while (!my_isspace(charset_info, *p) && - p1 < q->record_file + sizeof(q->record_file) - 1) - *p1++ = *p++; - *p1 = 0; - } } end: @@ -2862,7 +2810,17 @@ char* safe_str_append(char *buf, const char *str, int size) return buf; } -void str_to_file(const char *fname, char *str, int size) + +/* + Write the content of str into file + + SYNOPSIS + str_to_file + fname - name of file to truncate/create and write to + str - content to write to file + size - size of content witten to file +*/ +static void str_to_file(const char *fname, char *str, int size) { int fd; char buff[FN_REFLEN]; @@ -2881,7 +2839,7 @@ void str_to_file(const char *fname, char *str, int size) my_close(fd, MYF(0)); } -void reject_dump(const char *record_file, char *buf, int size) +void dump_result_to_reject_file(const char *record_file, char *buf, int size) { char reject_file[FN_REFLEN]; str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size); @@ -2921,7 +2879,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) MYSQL_ROW row; uint num_fields= mysql_num_fields(res); MYSQL_FIELD *fields= !display_result_vertically ? 0 : mysql_fetch_fields(res); - unsigned long *lengths; + ulong *lengths; while ((row = mysql_fetch_row(res))) { uint i; @@ -2963,667 +2921,118 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) /* -* flags control the phased/stages of query execution to be performed -* if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on -* the result will be read - for regular query, both bits must be on + Append all results from ps execution to the dynamic string separated + with '\t'. Values may be converted with 'replace_column' */ -static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); -static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); -static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); -static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, - DYNAMIC_STRING *ds); - -static int run_query(MYSQL *mysql, struct st_query *q, int flags) +static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, + MYSQL_FIELD* field, uint num_fields) { - - /* - Try to find out if we can run this statement using the prepared - statement protocol. - - We don't have a mysql_stmt_send_execute() so we only handle - complete SEND+REAP. - - If it is a '?' in the query it may be a SQL level prepared - statement already and we can't do it twice - */ - - if (ps_protocol_enabled && disable_info && - (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query)) - return run_query_stmt(mysql, q, flags); - return run_query_normal(mysql, q, flags); -} - - -static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) -{ - MYSQL_RES* res= 0; - uint i; - int error= 0, err= 0, counter= 0; - DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; - DYNAMIC_STRING eval_query; - char* query; - int query_len, got_error_on_send= 0; - DBUG_ENTER("run_query_normal"); - DBUG_PRINT("enter",("flags: %d", flags)); - - if (q->type != Q_EVAL) - { - query = q->query; - query_len = strlen(query); - } - else - { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, q->query); - query = eval_query.str; - query_len = eval_query.length; - } - DBUG_PRINT("enter", ("query: '%-.60s'", query)); - - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds = &ds_tmp; - } - else - ds= &ds_res; - - if (flags & QUERY_SEND) - { - got_error_on_send= mysql_send_query(mysql, query, query_len); - if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) - die("unable to send query '%s' (mysql_errno=%d , errno=%d)", - query, mysql_errno(mysql), errno); - } - - do - { - if ((flags & QUERY_SEND) && !disable_query_log && !counter) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds, delimiter, delimiter_length); - dynstr_append_mem(ds, "\n", 1); - } - if (!(flags & QUERY_REAP)) - DBUG_RETURN(0); - - if (got_error_on_send || - (!counter && (*mysql->methods->read_query_result)(mysql)) || - (!(last_result= res= mysql_store_result(mysql)) && - mysql_field_count(mysql))) - { - if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), - mysql_sqlstate(mysql), ds)) - error= 1; - goto end; - } - - if (!disable_result_log) - { - ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ - LINT_INIT(affected_rows); - - if (res) - { - MYSQL_FIELD *field= mysql_fetch_fields(res); - uint num_fields= mysql_num_fields(res); - - if (display_metadata) - run_query_display_metadata(field, num_fields, ds); - - if (!display_result_vertically) - { - for (i = 0; i < num_fields; i++) - { - if (i) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append(ds, field[i].name); - } - dynstr_append_mem(ds, "\n", 1); - } - append_result(ds, res); - } - - /* - Need to call mysql_affected_rows() before the new - query to find the warnings - */ - if (!disable_info) - affected_rows= (ulong)mysql_affected_rows(mysql); - - /* - Add all warnings to the result. We can't do this if we are in - the middle of processing results from multi-statement, because - this will break protocol. - */ - if (!disable_warnings && !mysql_more_results(mysql) && - mysql_warning_count(mysql)) - { - MYSQL_RES *warn_res=0; - uint count= mysql_warning_count(mysql); - if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) - warn_res= mysql_store_result(mysql); - if (!warn_res) - die("Warning count is %u but didn't get any warnings", count); - else - { - dynstr_append_mem(ds, "Warnings:\n", 10); - append_result(ds, warn_res); - mysql_free_result(warn_res); - } - } - if (!disable_info) - { - char buf[40]; - sprintf(buf,"affected rows: %lu\n", affected_rows); - dynstr_append(ds, buf); - if (mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); - } - } - } - - if (record) - { - if (!q->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - { - error= check_result(ds, q->record_file, q->require_file); - } - if (res) - mysql_free_result(res); - last_result= 0; - counter++; - } while (!(err= mysql_next_result(mysql))); - if (err > 0) - { - /* We got an error from mysql_next_result, maybe expected */ - if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), - mysql_sqlstate(mysql), ds)) - error= 1; - goto end; - } - - /* If we come here the query is both executed and read successfully */ - if (handle_no_error(q)) - { - error= 1; - goto end; - } - -end: - free_replace(); - last_result=0; - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - if (q->type == Q_EVAL) - dynstr_free(&eval_query); - - /* - We save the return code (mysql_errno(mysql)) from the last call sent - to the server into the mysqltest builtin variable $mysql_errno. This - variable then can be used from the test case itself. - */ - var_set_errno(mysql_errno(mysql)); - DBUG_RETURN(error); -} - - -/* - Handle errors which occurred after execution - - SYNOPSIS - handle_error() - query - query string - q - query context - err_errno - error number - err_error - error message - err_sqlstate - sql state - ds - dynamic string which is used for output buffer - - NOTE - If there is an unexpected error this function will abort mysqltest - immediately. - - RETURN VALUE - 0 - OK - 1 - Some other error was expected. -*/ - -static int handle_error(const char *query, struct st_query *q, - unsigned int err_errno, const char *err_error, - const char* err_sqlstate, DYNAMIC_STRING *ds) -{ - uint i; - - DBUG_ENTER("handle_error"); - - if (q->require_file) - abort_not_supported_test(); - - if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, err_errno, err_error); - - for (i= 0 ; (uint) i < q->expected_errors ; i++) - { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == err_errno)) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) - { - if (q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds, "ERROR ", 6); - replace_dynstr_append(ds, err_sqlstate); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, err_error); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - /* OK */ - DBUG_RETURN(0); - } - } - - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, err_sqlstate); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, err_error); - dynstr_append_mem(ds, "\n", 1); - - if (i) - { - if (q->expected_errno[0].type == ERR_ERRNO) - die("query '%s' failed with wrong errno %d instead of %d...", - q->query, err_errno, q->expected_errno[0].code.errnum); - else - die("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); - DBUG_RETURN(1); - } - - /* - If we do not abort on error, failure to run the query does not fail the - whole test case. - */ - verbose_msg("query '%s' failed: %d: %s", q->query, err_errno, - err_error); - DBUG_RETURN(0); -} - - -/* - Handle absence of errors after execution - - SYNOPSIS - handle_no_error() - q - context of query - - RETURN VALUE - 0 - OK - 1 - Some error was expected from this query. -*/ - -static int handle_no_error(struct st_query *q) -{ - DBUG_ENTER("handle_no_error"); - - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) - { - /* Error code we wanted was != 0, i.e. not an expected success */ - die("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); - DBUG_RETURN(1); - } - else if (q->expected_errno[0].type == ERR_SQLSTATE && - strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) - { - /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - die("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); - DBUG_RETURN(1); - } - - DBUG_RETURN(0); -} - -/****************************************************************************\ - * If --ps-protocol run ordinary statements using prepared statemnt C API -\****************************************************************************/ - -/* - We don't have a mysql_stmt_send_execute() so we only handle - complete SEND+REAP -*/ - -static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) -{ - int error= 0; /* Function return code if "goto end;" */ - int err; /* Temporary storage of return code from calls */ - int query_len; + MYSQL_BIND *bind; + my_bool *is_null; + ulong *length; ulonglong num_rows; - char *query; - MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ - DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; - DYNAMIC_STRING eval_query; - MYSQL_STMT *stmt; - DBUG_ENTER("run_query_stmt"); - /* - We must allocate a new stmt for each query in this program becasue this - may be a new connection. - */ - if (!(stmt= mysql_stmt_init(mysql))) - die("unable init stmt structure"); - - if (q->type != Q_EVAL) - { - query= q->query; - query_len= strlen(query); - } - else - { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, q->query); - query= eval_query.str; - query_len= eval_query.length; - } - DBUG_PRINT("query", ("'%-.60s'", query)); - - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; - - /* Store the query into the output buffer if not disabled */ - if (!disable_query_log) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds, delimiter, delimiter_length); - dynstr_append_mem(ds, "\n", 1); - } - - /* - We use the prepared statement interface but there is actually no - '?' in the query. If unpreparable we fall back to use normal - C API. - */ - if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT) - return run_query_normal(mysql, q, flags); - - if (err != 0) + /* FIXME we don't handle vertical display ..... */ + uint col_idx, row_idx; + + /* Allocate array with bind structs, lengths and NULL flags */ + bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), + MYF(MY_WME | MY_FAE | MY_ZEROFILL)); + length= (ulong*) my_malloc(num_fields * sizeof(ulong), + MYF(MY_WME | MY_FAE)); + is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), + MYF(MY_WME | MY_FAE)); + + for (col_idx= 0; col_idx < num_fields; col_idx++) { + /* Allocate data for output */ /* - Preparing is part of normal execution and some errors may be expected + FIXME it may be a bug that for non string/blob types + 'max_length' is 0, should try out 'length' in that case */ - if (handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) - error= 1; - goto end; + uint max_length= max(field[col_idx].max_length + 1, 1024); + char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); + + bind[col_idx].buffer_type= MYSQL_TYPE_STRING; + bind[col_idx].buffer= (char *)str_data; + bind[col_idx].buffer_length= max_length; + bind[col_idx].is_null= &is_null[col_idx]; + bind[col_idx].length= &length[col_idx]; } - - /* We may have got warnings already, collect them if any */ - if (!disable_ps_warnings) - run_query_stmt_handle_warnings(mysql, ds); - - /* - No need to call mysql_stmt_bind_param() because we have no - parameter markers. - - To optimize performance we use a global 'stmt' that is initiated - once. A new prepare will implicitely close the old one. When we - terminate we will lose the connection, this also closes the last - prepared statement. - */ - - if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */ - { - /* We got an error, maybe expected */ - if (handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) - error= 1; - goto end; - } - - /* - We instruct that we want to update the "max_length" field in - mysql_stmt_store_result(), this is our only way to know how much - buffer to allocate for result data - */ - { - my_bool one= 1; - if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, - (void*) &one)) != 0) - die("unable to set stmt attribute " - "'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err); - } - - /* - If we got here the statement succeeded and was expected to do so, - get data. Note that this can still give errors found during execution! - */ - if ((err= mysql_stmt_store_result(stmt)) != 0) - { - /* We got an error, maybe expected */ - if(handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) - error = 1; - goto end; - } - - /* If we got here the statement was both executed and read succeesfully */ - if (handle_no_error(q)) - { - error= 1; - goto end; - } - + + /* Fill in the data into the structures created above */ + if (mysql_stmt_bind_result(stmt, bind)) + die("mysql_stmt_bind_result failed: %d: %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + + /* Read result from each row */ num_rows= mysql_stmt_num_rows(stmt); - - /* - Not all statements creates a result set. If there is one we can - now create another normal result set that contains the meta - data. This set can be handled almost like any other non prepared - statement result set. - */ - if (!disable_result_log && ((res= mysql_stmt_result_metadata(stmt)) != NULL)) + for (row_idx= 0; row_idx < num_rows; row_idx++) { - /* Take the column count from meta info */ - MYSQL_FIELD *field= mysql_fetch_fields(res); - uint num_fields= mysql_num_fields(res); - - if (display_metadata) - run_query_display_metadata(field, num_fields, ds); - + if (mysql_stmt_fetch(stmt)) + die("mysql_stmt_fetch failed: %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + + /* Read result from each column */ + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + /* FIXME is string terminated? */ + const char *val= (const char *)bind[col_idx].buffer; + ulonglong len= *bind[col_idx].length; + if (col_idx < max_replace_column && replace_column[col_idx]) + { + val= replace_column[col_idx]; + len= strlen(val); + } + if (*bind[col_idx].is_null) + { + val= "NULL"; + len= 4; + } + if (!display_result_vertically) + { + if (col_idx) /* No tab before first col */ + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, (int)len); + } + else + { + dynstr_append(ds, field[col_idx].name); + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, (int)len); + dynstr_append_mem(ds, "\n", 1); + } + } if (!display_result_vertically) - { - /* Display the table heading with the names tab separated */ - uint col_idx; - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - if (col_idx) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append(ds, field[col_idx].name); - } dynstr_append_mem(ds, "\n", 1); - } - - /* Now we are to put the real result into the output buffer */ - /* FIXME when it works, create function append_stmt_result() */ - { - MYSQL_BIND *bind; - my_bool *is_null; - unsigned long *length; - /* FIXME we don't handle vertical display ..... */ - uint col_idx, row_idx; - - /* Allocate array with bind structs, lengths and NULL flags */ - bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), - MYF(MY_WME | MY_FAE | MY_ZEROFILL)); - length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long), - MYF(MY_WME | MY_FAE)); - is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), - MYF(MY_WME | MY_FAE)); - - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - /* Allocate data for output */ - /* - FIXME it may be a bug that for non string/blob types - 'max_length' is 0, should try out 'length' in that case - */ - uint max_length= max(field[col_idx].max_length + 1, 1024); - char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); - - bind[col_idx].buffer_type= MYSQL_TYPE_STRING; - bind[col_idx].buffer= (char *)str_data; - bind[col_idx].buffer_length= max_length; - bind[col_idx].is_null= &is_null[col_idx]; - bind[col_idx].length= &length[col_idx]; - } - - /* Fill in the data into the structures created above */ - if ((err= mysql_stmt_bind_result(stmt, bind)) != 0) - die("unable to bind result to statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - /* Read result from each row */ - for (row_idx= 0; row_idx < num_rows; row_idx++) - { - if ((err= mysql_stmt_fetch(stmt)) != 0) - die("unable to fetch all rows from statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - /* Read result from each column */ - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - /* FIXME is string terminated? */ - const char *val= (const char *)bind[col_idx].buffer; - ulonglong len= *bind[col_idx].length; - if (col_idx < max_replace_column && replace_column[col_idx]) - { - val= replace_column[col_idx]; - len= strlen(val); - } - if (*bind[col_idx].is_null) - { - val= "NULL"; - len= 4; - } - if (!display_result_vertically) - { - if (col_idx) /* No tab before first col */ - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, (int)len); - } - else - { - dynstr_append(ds, field[col_idx].name); - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, (int)len); - dynstr_append_mem(ds, "\n", 1); - } - } - if (!display_result_vertically) - dynstr_append_mem(ds, "\n", 1); - } - - if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA) - die("fetch didn't end with MYSQL_NO_DATA from statement " - "'%s': %s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - free_replace_column(); - - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - /* Free data for output */ - my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE)); - } - /* Free array with bind structs, lengths and NULL flags */ - my_free((gptr)bind , MYF(MY_WME | MY_FAE)); - my_free((gptr)length , MYF(MY_WME | MY_FAE)); - my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); - } - - /* Add all warnings to the result */ - run_query_stmt_handle_warnings(mysql, ds); - - if (!disable_info) - { - char buf[40]; - sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql)); - dynstr_append(ds, buf); - if (mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); - } - } } - run_query_stmt_handle_warnings(mysql, ds); - - if (record) + + if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", + mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); + + free_replace_column(); + + for (col_idx= 0; col_idx < num_fields; col_idx++) { - if (!q->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); + /* Free data for output */ + my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE)); } - else if (q->record_file[0]) - { - error= check_result(ds, q->record_file, q->require_file); - } - if (res) - mysql_free_result(res); /* Free normal result set with meta data */ - last_result= 0; /* FIXME have no idea what this is about... */ - -end: - free_replace(); - last_result=0; - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - if (q->type == Q_EVAL) - dynstr_free(&eval_query); - var_set_errno(mysql_stmt_errno(stmt)); - mysql_stmt_close(stmt); - DBUG_RETURN(error); + /* Free array with bind structs, lengths and NULL flags */ + my_free((gptr)bind , MYF(MY_WME | MY_FAE)); + my_free((gptr)length , MYF(MY_WME | MY_FAE)); + my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); } -/****************************************************************************\ - * Broken out sub functions to run_query_stmt() -\****************************************************************************/ +/* + Append metadata for fields to output +*/ -static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, - DYNAMIC_STRING *ds) +static void append_metadata(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, + uint num_fields) { MYSQL_FIELD *field_end; dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t" @@ -3676,39 +3085,564 @@ static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, } } +/* + Append affected row count and other info to output +*/ -static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) +static void append_info(DYNAMIC_STRING* ds, ulong affected_rows, + const char* info) +{ + char buf[40]; + sprintf(buf,"affected rows: %lu\n", affected_rows); + dynstr_append(ds, buf); + if (info) + { + dynstr_append(ds, "info: "); + dynstr_append(ds, info); + dynstr_append_mem(ds, "\n", 1); + } +} + + +/* + Display the table headings with the names tab separated +*/ +static void append_table_headings(DYNAMIC_STRING* ds, + MYSQL_FIELD* field, + uint num_fields) +{ + uint col_idx; + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + if (col_idx) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append(ds, field[col_idx].name); + } + dynstr_append_mem(ds, "\n", 1); +} + +/* + Fetch warnings from server and append to output +*/ + +static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; - DBUG_ENTER("run_query_stmt_handle_warnings"); + DBUG_ENTER("append_warnings"); - if (!disable_warnings && (count= mysql_warning_count(mysql))) + if (!(count= mysql_warning_count(mysql))) + DBUG_VOID_RETURN; + + /* + If one day we will support execution of multi-statements + through PS API we should not issue SHOW WARNINGS until + we have not read all results... + */ + DBUG_ASSERT(!mysql_more_results(mysql)); + + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) + die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql)); + + MYSQL_RES *warn_res= mysql_store_result(mysql); + if (!warn_res) + die("Warning count is %u but didn't get any warnings", + count); + + + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); + + DBUG_VOID_RETURN; +} + + +/* + Run query using MySQL C API + + SYNPOSIS + run_query_normal + mysql - mysql handle + command - currrent command pointer + query - query string to execute + query_len - length query string to execute + ds - output buffer wherte to store result form query + + RETURN VALUE + error - function will not return +*/ + +static void run_query_normal(MYSQL *mysql, struct st_query *command, + int flags, char *query, int query_len, + DYNAMIC_STRING *ds) +{ + MYSQL_RES *res= 0; + int err= 0, counter= 0; + DBUG_ENTER("run_query_normal"); + DBUG_PRINT("enter",("flags: %d", flags)); + DBUG_PRINT("enter", ("query: '%-.60s'", query)); + + if (flags & QUERY_SEND) { - /* - If one day we will support execution of multi-statements - through PS API we should not issue SHOW WARNINGS until - we have not read all results... - */ - DBUG_ASSERT(!mysql_more_results(mysql)); - - if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0) + /* + Send the query, using the undocumented function mysql_send_query + */ + if (mysql_send_query(mysql, query, query_len)) { - MYSQL_RES *warn_res= mysql_store_result(mysql); - if (!warn_res) - die("Warning count is %u but didn't get any warnings", - count); - else - { - dynstr_append_mem(ds, "Warnings:\n", 10); - append_result(ds, warn_res); - mysql_free_result(warn_res); - } + handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; } } + + if (!(flags & QUERY_REAP)) + DBUG_VOID_RETURN; + + do + { + /* + When on first result set, call mysql_read_query_result to retrrieve + answer to the query sent earlier + */ + if ((counter==0) && mysql_read_query_result(mysql)) + { + handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + + } + + /* + Store the result. If res is NULL, use mysql_field_count to + determine if that was expected + */ + if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql)) + { + handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + } + + if (!disable_result_log) + { + ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + LINT_INIT(affected_rows); + + if (res) + { + MYSQL_FIELD *fields= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + if (display_metadata) + append_metadata(ds, fields, num_fields); + + if (!display_result_vertically) + append_table_headings(ds, fields, num_fields); + + append_result(ds, res); + } + + /* + Need to call mysql_affected_rows() before the "new" + query to find the warnings + */ + if (!disable_info) + affected_rows= (ulong)mysql_affected_rows(mysql); + + /* + Add all warnings to the result. We can't do this if we are in + the middle of processing results from multi-statement, because + this will break protocol. + */ + if (!disable_warnings && !mysql_more_results(mysql)) + append_warnings(ds, mysql); + + if (!disable_info) + append_info(ds, affected_rows, mysql_info(mysql)); + } + + if (res) + mysql_free_result(res); + counter++; + } while (!(err= mysql_next_result(mysql))); + if (err > 0) + { + /* We got an error from mysql_next_result, maybe expected */ + handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + } + DBUG_ASSERT(err == -1); /* Successful and there are no more results */ + + /* If we come here the query is both executed and read successfully */ + handle_no_error(command); + +end: + free_replace(); + + /* + We save the return code (mysql_errno(mysql)) from the last call sent + to the server into the mysqltest builtin variable $mysql_errno. This + variable then can be used from the test case itself. + */ + var_set_errno(mysql_errno(mysql)); DBUG_VOID_RETURN; } +/* + Handle errors which occurred during execution + + SYNOPSIS + handle_error() + query - query string + q - query context + err_errno - error number + err_error - error message + err_sqlstate - sql state + ds - dynamic string which is used for output buffer + + NOTE + If there is an unexpected error this function will abort mysqltest + immediately. + + RETURN VALUE + error - function will not return +*/ + +static void handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds) +{ + uint i; + + DBUG_ENTER("handle_error"); + + if (q->require_file) + abort_not_supported_test(); + + if (q->abort_on_error) + die("query '%s' failed: %d: %s", query, err_errno, err_error); + + for (i= 0 ; (uint) i < q->expected_errors ; i++) + { + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == err_errno)) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) + { + if (q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds, "ERROR ", 6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds,"\n",1); + } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) + dynstr_append(ds,"Got one of the listed errors\n"); + /* OK */ + DBUG_VOID_RETURN; + } + } + + DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds, "\n", 1); + + if (i) + { + if (q->expected_errno[0].type == ERR_ERRNO) + die("query '%s' failed with wrong errno %d instead of %d...", + q->query, err_errno, q->expected_errno[0].code.errnum); + else + die("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); + } + + /* + If we do not abort on error, failure to run the query does not fail the + whole test case. + */ + verbose_msg("query '%s' failed: %d: %s", q->query, err_errno, + err_error); + DBUG_VOID_RETURN; +} + + +/* + Handle absence of errors after execution + + SYNOPSIS + handle_no_error() + q - context of query + + RETURN VALUE + error - function will not return +*/ + +static void handle_no_error(struct st_query *q) +{ + DBUG_ENTER("handle_no_error"); + + if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); + } + else if (q->expected_errno[0].type == ERR_SQLSTATE && + strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + { + /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ + die("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); + } + + DBUG_VOID_RETURN; +} + + +/* + Run query using prepared statement C API + + SYNPOSIS + run_query_stmt + mysql - mysql handle + command - currrent command pointer + query - query string to execute + query_len - length query string to execute + ds - output buffer wherte to store result form query + + RETURN VALUE + error - function will not return +*/ + +static void run_query_stmt(MYSQL *mysql, struct st_query *command, + char *query, int query_len, DYNAMIC_STRING *ds) +{ + MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ + MYSQL_STMT *stmt; + DBUG_ENTER("run_query_stmt"); + DBUG_PRINT("query", ("'%-.60s'", query)); + + /* + We must allocate a new stmt for each query in this program because this + may be a new connection. + + Well, it could be stored togeter with mysql pointer in cur_con struct + */ + if (!(stmt= mysql_stmt_init(mysql))) + die("unable to init stmt structure"); + + /* + Prepare the query + */ + if (mysql_stmt_prepare(stmt, query, query_len)) + { + handle_error(query, command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* + No need to call mysql_stmt_bind_param() because we have no + parameter markers. + */ + + /* + Execute the query + */ + if (mysql_stmt_execute(stmt)) + { + handle_error(query, command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* + We instruct that we want to update the "max_length" field in + mysql_stmt_store_result(), this is our only way to know how much + buffer to allocate for result data + */ + { + my_bool one= 1; + if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) + die("mysql_stmt_attr_set failed': %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + } + + /* + If we got here the statement succeeded and was expected to do so, + get data. Note that this can still give errors found during execution! + */ + if (mysql_stmt_store_result(stmt)) + { + handle_error(query, command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* If we got here the statement was both executed and read succeesfully */ + handle_no_error(command); + + /* + Not all statements creates a result set. If there is one we can + now create another normal result set that contains the meta + data. This set can be handled almost like any other non prepared + statement result set. + */ + if (!disable_result_log) + { + if ((res= mysql_stmt_result_metadata(stmt)) != NULL) + { + /* Take the column count from meta info */ + MYSQL_FIELD *fields= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + if (display_metadata) + append_metadata(ds, fields, num_fields); + + if (!display_result_vertically) + append_table_headings(ds, fields, num_fields); + + append_stmt_result(ds, stmt, fields, num_fields); + + mysql_free_result(res); /* Free normal result set with meta data */ + + } + + if (!disable_warnings) + append_warnings(ds, mysql); + + if (!disable_info) + append_info(ds, (ulong)mysql_affected_rows(mysql), mysql_info(mysql)); + } + +end: + free_replace(); + /* + We save the return code (mysql_stmt_errno(stmt)) from the last call sent + to the server into the mysqltest builtin variable $mysql_errno. This + variable then can be used from the test case itself. + */ + var_set_errno(mysql_stmt_errno(stmt)); + mysql_stmt_close(stmt); + DBUG_VOID_RETURN; +} + + +/* + + Run query + + flags control the phased/stages of query execution to be performed + if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on + the result will be read - for regular query, both bits must be on + + SYNPOSIS + run_query + mysql - mysql handle + command - currrent command pointer + +*/ + +static void run_query(MYSQL *mysql, struct st_query *command, int flags) +{ + DYNAMIC_STRING *ds; + DYNAMIC_STRING ds_tmp; + DYNAMIC_STRING eval_query; + char *query; + int query_len; + + /* + Evaluate query if this is an eval command + */ + if (command->type == Q_EVAL) + { + init_dynamic_string(&eval_query, "", 16384, 65536); + do_eval(&eval_query, command->query); + query = eval_query.str; + query_len = eval_query.length; + } + else + { + query = command->query; + query_len = strlen(query); + } + + /* + When command->record_file is set the output of _this_ query + should be compared with an already existing file + Create a temporary dynamic string to contain the output from + this query. + */ + if (command->record_file[0]) + { + init_dynamic_string(&ds_tmp, "", 16384, 65536); + ds= &ds_tmp; + } + else + ds= &ds_res; + + /* Store the query into the output buffer */ + if (!disable_query_log && (flags & QUERY_SEND)) + { + replace_dynstr_append_mem(ds,query, query_len); + dynstr_append_mem(ds, delimiter, delimiter_length); + dynstr_append_mem(ds, "\n", 1); + } + + /* + Find out how to run this query + + We don't have a mysql_stmt_send_execute() so it must be a + complete SEND+REAP to use prepared statement + + If it is a '?' in the query it may be a SQL level prepared + statement already and we can't do it twice + */ + if (ps_protocol_enabled && + (flags & QUERY_SEND) && (flags & QUERY_REAP) && + ps_match_re(query)) + run_query_stmt(mysql, command, query, query_len, ds); + else + run_query_normal(mysql, command, flags, query, query_len, ds); + + if (record) + { + /* Recording in progress */ + if (!command->record_file[0]) + die("Missing result file"); + + /* Dump the output from _this_ query to the specified record_file */ + str_to_file(command->record_file, ds->str, ds->length); + } + else if (command->record_file[0]) + { + /* + The output from _this_ query should be checked against an already + existing file which has been specified using --require or --result + */ + check_result(ds, command->record_file, command->require_file); + } + + if (ds == &ds_tmp) + dynstr_free(&ds_tmp); + if (command->type == Q_EVAL) + dynstr_free(&eval_query); +} + + /****************************************************************************\ * Functions to match SQL statements that can be prepared \****************************************************************************/ @@ -3911,7 +3845,6 @@ static void init_var_hash(MYSQL *mysql) int main(int argc, char **argv) { - int error = 0; struct st_query *q; my_bool require_file=0, q_send_flag=0, abort_flag= 0, query_executed= 0; @@ -4005,7 +3938,7 @@ int main(int argc, char **argv) processed = 1; switch (q->type) { case Q_CONNECT: - error|= do_connect(q); + do_connect(q); break; case Q_CONNECTION: select_connection(q); break; case Q_DISCONNECT: @@ -4039,7 +3972,7 @@ int main(int argc, char **argv) #endif case Q_INC: do_modify_var(q, "inc", DO_INC); break; case Q_DEC: do_modify_var(q, "dec", DO_DEC); break; - case Q_ECHO: do_echo(q); break; + case Q_ECHO: do_echo(q); query_executed= 1; break; case Q_SYSTEM: do_system(q); break; case Q_DELIMITER: strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); @@ -4066,15 +3999,6 @@ int main(int argc, char **argv) case Q_QUERY_HORIZONTAL: { my_bool old_display_result_vertically= display_result_vertically; - if (!q->query[q->first_word_len]) - { - /* This happens when we use 'query_..' on it's own line */ - q_send_flag=1; - DBUG_PRINT("info", - ("query: '%s' first_word_len: %d send_flag=1", - q->query, q->first_word_len)); - break; - } /* fix up query pointer if this is * first iteration for this line */ if (q->query == q->query_buf) q->query += q->first_word_len + 1; @@ -4085,7 +4009,7 @@ int main(int argc, char **argv) q->require_file=require_file; save_file[0]=0; } - error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); + run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); display_result_vertically= old_display_result_vertically; q->last_argument= q->end; query_executed= 1; @@ -4112,7 +4036,7 @@ int main(int argc, char **argv) q->require_file=require_file; save_file[0]=0; } - error |= run_query(&cur_con->mysql, q, flags); + run_query(&cur_con->mysql, q, flags); query_executed= 1; q->last_argument= q->end; break; @@ -4133,7 +4057,7 @@ int main(int argc, char **argv) query and read the result some time later when reap instruction is given on this connection. */ - error |= run_query(&cur_con->mysql, q, QUERY_SEND); + run_query(&cur_con->mysql, q, QUERY_SEND); query_executed= 1; q->last_argument= q->end; break; @@ -4255,6 +4179,12 @@ int main(int argc, char **argv) parser.current_line += current_line_inc; } + /* + The whole test has been executed sucessfully + Time to compare result or save it to record file + The entire output from test is now kept in ds_res + */ + if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) { /* @@ -4265,39 +4195,46 @@ int main(int argc, char **argv) no query output from the test file, e.g. regarded as no error. */ if (res_info.st_size) - error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH); + die("No queries executed but result file found!"); } - if (ds_res.length && !error) + + if (ds_res.length) { if (result_file) { - if (!record) - error |= check_result(&ds_res, result_file, q->require_file); + if (record) + { + /* Dump the output from test to result file */ + str_to_file(result_file, ds_res.str, ds_res.length); + } else - str_to_file(result_file, ds_res.str, ds_res.length); + { + /* Check that the output from test is equal to result file */ + check_result(&ds_res, result_file, 0); + } } else { - /* Print the result to stdout */ + /* No result_file to compare with, print the result to stdout */ printf("%s", ds_res.str); } + } + else + { + /* The test didn't produce any output */ } dynstr_free(&ds_res); - if (!silent) - { - if (error) - printf("not ok\n"); - else - printf("ok\n"); - } - if (!got_end_timer) timer_output(); /* No end_timer cmd, end it */ free_used_memory(); my_end(MY_CHECK_ERROR); - exit(error ? 1 : 0); - return error ? 1 : 0; /* Keep compiler happy */ + + /* Yes, if we got this far the test has suceeded! Sakila smiles */ + if (!silent) + printf("ok\n"); + exit(0); + return 0; /* Keep compiler happy */ } @@ -5094,12 +5031,6 @@ static int initialize_replace_buffer(void) return 0; } -static void free_replace_buffer(void) -{ - my_free(out_buff,MYF(MY_WME)); -} - - /**************************************************************************** Replace results for a column *****************************************************************************/ diff --git a/mysql-test/include/master-slave.inc b/mysql-test/include/master-slave.inc index 5ec4b4379f8..ea09f4e842b 100644 --- a/mysql-test/include/master-slave.inc +++ b/mysql-test/include/master-slave.inc @@ -8,7 +8,8 @@ connection slave; --disable_warnings stop slave; --enable_warnings -@r/slave-stopped.result show status like 'Slave_running'; +--require r/slave-stopped.result +show status like 'Slave_running'; connection master; --disable_warnings drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; @@ -21,7 +22,8 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings start slave; -@r/slave-running.result show status like 'Slave_running'; +--require r/slave-running.result +show status like 'Slave_running'; # Set the default connection to 'master' connection master; diff --git a/mysql-test/include/ps_query.inc b/mysql-test/include/ps_query.inc index 27a86f88231..e96d666eaec 100644 --- a/mysql-test/include/ps_query.inc +++ b/mysql-test/include/ps_query.inc @@ -52,7 +52,6 @@ execute stmt1; ##### parameter used for keyword like SELECT (must fail) set @arg00='SELECT' ; -# mysqltest gives no output for the next statement, Why ?? --error 1064 @arg00 a from t1 where a=1; --error 1064 diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 0ad6db8c57e..abcf4d049ed 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -149,6 +149,9 @@ hello mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: Missing delimiter +mysqltest: End of line junk detected: "sleep 7 +# Another comment +" mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Extra delimiter ";" found MySQL diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index c839c8a65b9..603de2afe4e 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 81d6180e41f..9e635f60f14 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 931e6b7c86c..fd51c71cad6 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -86,6 +86,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 3b9244c251f..876f7615672 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -128,6 +128,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; @@ -3140,6 +3142,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 643e12f7e2d..c39621d184f 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 9fbe67f581b..7c83099311e 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +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 '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; 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 '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/t/alias.test b/mysql-test/t/alias.test index 2746409c7e5..6546581eef2 100644 --- a/mysql-test/t/alias.test +++ b/mysql-test/t/alias.test @@ -61,9 +61,7 @@ INSERT INTO t1 VALUES (3359361,406,3359361,'Mustermann Musterfrau',7001,'2000-05 INSERT INTO t1 VALUES (3359362,406,3359362,'Mustermann Musterfrau',7001,'2000-05-20','workflow','Auftrag erledigt','Originalvertrag eingegangen und geprüft','','privat',1509984,2145874,'+','','P',1909154,'MobilComSuper92000D1(Akquise)',NULL,NULL,'MS9ND1',327,24,'MobilCom Intern',7003,NULL,'auto',20010202105916,'Mobilfunk','PP','','',''); # This died because we used the field Kundentyp twice ---disable_ps_protocol SELECT ELT(FIELD(kundentyp,'PP','PPA','PG','PGA','FK','FKA','FP','FPA','K','KA','V','VA',''), 'Privat (Private Nutzung)','Privat (Private Nutzung) Sitz im Ausland','Privat (geschaeftliche Nutzung)','Privat (geschaeftliche Nutzung) Sitz im Ausland','Firma (Kapitalgesellschaft)','Firma (Kapitalgesellschaft) Sitz im Ausland','Firma (Personengesellschaft)','Firma (Personengesellschaft) Sitz im Ausland','oeff. rechtl. Koerperschaft','oeff. rechtl. Koerperschaft Sitz im Ausland','Eingetragener Verein','Eingetragener Verein Sitz im Ausland','Typ unbekannt') AS Kundentyp ,kategorie FROM t1 WHERE hdl_nr < 2000000 AND kategorie IN ('Prepaid','Mobilfunk') AND st_klasse = 'Workflow' GROUP BY kundentyp ORDER BY kategorie; ---enable_ps_protocol drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index bf557029a55..fb9835c5d7f 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -596,9 +596,7 @@ drop table t1; CREATE TABLE t1 (n int); INSERT INTO t1 VALUES (1); ---disable_ps_protocol SELECT n+1 AS n FROM t1 GROUP BY n; ---enable_ps_protocol DROP TABLE t1; # @@ -623,11 +621,9 @@ insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); # query with ambiguous column reference 'c2' ---disable_ps_protocol select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 group by c2; show warnings; ---enable_ps_protocol # this query has no ambiguity select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 11fbb023963..a1f7e8b4251 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -364,6 +364,15 @@ select 3 from t1 ; --error 1 --exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +# +# Missing delimiter until eof +# The comment will be "sucked into" the sleep command since +# delimiter is missing +--system echo "sleep 7" > var/log/mysqltest.sql +--system echo "# Another comment" >> var/log/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + # # Extra delimiter # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index daa83ef0fa4..a30321470ea 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -27,12 +27,9 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; (select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; select found_rows(); ---enable_ps_protocol # # Test some error conditions with UNION @@ -210,27 +207,15 @@ insert into t2 values (3),(4),(5); # Test global limits (SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2) LIMIT 1; -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---enable_ps_protocol (SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2) LIMIT 2; -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---enable_ps_protocol # Test cases where found_rows() should return number of returned rows (SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION all (SELECT * FROM t2); -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---enable_ps_protocol (SELECT SQL_CALC_FOUND_ROWS * FROM t1) UNION all (SELECT * FROM t2 LIMIT 1); -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---enable_ps_protocol # This used to work in 4.0 but not anymore in 4.1 --error 1064 (SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1) UNION SELECT * FROM t2 LIMIT 1; @@ -238,15 +223,9 @@ select found_rows(); # In these case found_rows() should work SELECT SQL_CALC_FOUND_ROWS * FROM t1 LIMIT 1 UNION all SELECT * FROM t2 LIMIT 2; -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---disable_ps_protocol SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION all SELECT * FROM t2 LIMIT 2; -# PS doesn't work correctly with found_rows: to be fixed ---disable_ps_protocol select found_rows(); ---disable_ps_protocol # The following examples will not be exact SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 2; From 718839a1c157f89f3112974efe6d14f07d18a0ce Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 3 Nov 2005 19:00:37 +0100 Subject: [PATCH 004/154] WL#2930 Adding view and cursor 'protocols' to mysqltest - Part2, actually adding the new functionality --- client/mysqltest.c | 353 ++++++++++++++++++++++++++--------- mysql-test/mysql-test-run.pl | 25 +++ 2 files changed, 290 insertions(+), 88 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index b5a0f65f55c..1b24d44bdf3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "2.5" +#define MTEST_VERSION "2.6" #include #include @@ -108,7 +108,8 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, - OPT_SSL_CIPHER,OPT_PS_PROTOCOL}; + OPT_SSL_CIPHER,OPT_PS_PROTOCOL,OPT_SP_PROTOCOL,OPT_CURSOR_PROTOCOL, + OPT_VIEW_PROTOCOL}; /* ************************************************************************ */ /* @@ -158,7 +159,11 @@ static char *db = 0, *pass=0; const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; static int port = 0; static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0; -static my_bool tty_password= 0, ps_protocol= 0, ps_protocol_enabled= 0; +static my_bool tty_password= 0; +static my_bool ps_protocol= 0, ps_protocol_enabled= 0; +static my_bool sp_protocol= 0, sp_protocol_enabled= 0; +static my_bool view_protocol= 0, view_protocol_enabled= 0; +static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0; static int parsing_disabled= 0; static uint start_lineno, *lineno; const char *manager_user="root",*manager_host=0; @@ -212,11 +217,14 @@ static int got_end_timer= FALSE; static void timer_output(void); static ulonglong timer_now(void); -static my_regex_t ps_re; /* Holds precompiled re for valid PS statements */ -static void ps_init_re(void); -static int ps_match_re(char *); -static char *ps_eprint(int); -static void ps_free_reg(void); +/* Precompiled re's */ +static my_regex_t ps_re; /* the query can be run using PS protocol */ +static my_regex_t sp_re; /* the query can be run as a SP */ +static my_regex_t view_re; /* the query can be run as a view*/ + +static void init_re(void); +static int match_re(my_regex_t *, char *); +static void free_re(void); static const char *embedded_server_groups[]= { @@ -240,6 +248,7 @@ struct connection { MYSQL mysql; char *name; + MYSQL_STMT* stmt; }; typedef struct @@ -433,7 +442,6 @@ static VAR* var_init(VAR* v, const char *name, int name_len, const char *val, static void var_free(void* v); -int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); void dump_result_to_reject_file(const char *record_file, char *buf, int size); int close_connection(struct st_query*); @@ -539,6 +547,9 @@ static void close_cons() DBUG_ENTER("close_cons"); for (--next_con; next_con >= cons; --next_con) { + if (next_con->stmt) + mysql_stmt_close(next_con->stmt); + next_con->stmt= 0; mysql_close(&next_con->mysql); my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR)); } @@ -593,8 +604,7 @@ static void free_used_memory() my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); mysql_server_end(); - if (ps_protocol) - ps_free_reg(); + free_re(); DBUG_VOID_RETURN; } @@ -660,7 +670,7 @@ void init_parser() } -int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +static int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { MY_STAT stat_info; char *tmp, *res_ptr; @@ -2153,7 +2163,7 @@ int do_connect(struct st_query *q) p= safe_get_param(p, &con_db, "Missing connection db"); /* Port */ - VAR* var_port; + VAR *var_port; p= safe_get_param(p, &con_port_str, 0); if (*con_port_str) { @@ -2223,7 +2233,7 @@ int do_connect(struct st_query *q) if (!mysql_init(&next_con->mysql)) die("Failed on mysql_init()"); if (opt_compress || con_compress) - mysql_options(&next_con->mysql,MYSQL_OPT_COMPRESS,NullS); + mysql_options(&next_con->mysql, MYSQL_OPT_COMPRESS, NullS); mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); @@ -2715,6 +2725,15 @@ static struct my_option my_long_options[] = {"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication", (gptr*) &ps_protocol, (gptr*) &ps_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select", + (gptr*) &sp_protocol, (gptr*) &sp_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statment", + (gptr*) &cursor_protocol, (gptr*) &cursor_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select", + (gptr*) &view_protocol, (gptr*) &view_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"quiet", 's', "Suppress all normal output.", (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"record", 'r', "Record output of test_file into result file.", @@ -2776,8 +2795,6 @@ void usage() #include -#include - static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -3222,6 +3239,7 @@ static void append_table_headings(DYNAMIC_STRING* ds, static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; + MYSQL_RES *warn_res; DBUG_ENTER("append_warnings"); if (!(count= mysql_warning_count(mysql))) @@ -3237,11 +3255,9 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql)); - MYSQL_RES *warn_res= mysql_store_result(mysql); - if (!warn_res) + if (!(warn_res= mysql_store_result(mysql))) die("Warning count is %u but didn't get any warnings", count); - dynstr_append_mem(ds, "Warnings:\n", 10); append_result(ds, warn_res); @@ -3258,6 +3274,7 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) run_query_normal mysql - mysql handle command - currrent command pointer + flags -flags indicating wheter to SEND and/or REAP query - query string to execute query_len - length query string to execute ds - output buffer wherte to store result form query @@ -3279,7 +3296,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, if (flags & QUERY_SEND) { /* - Send the query, using the undocumented function mysql_send_query + Send the query */ if (mysql_send_query(mysql, query, query_len)) { @@ -3295,7 +3312,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, do { /* - When on first result set, call mysql_read_query_result to retrrieve + When on first result set, call mysql_read_query_result to retrieve answer to the query sent earlier */ if ((counter==0) && mysql_read_query_result(mysql)) @@ -3526,18 +3543,20 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ MYSQL_STMT *stmt; + DYNAMIC_STRING ds_prepare_warnings; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); - + /* - We must allocate a new stmt for each query in this program because this - may be a new connection. - - Well, it could be stored togeter with mysql pointer in cur_con struct + Init a new stmt if it's not alreday one created for this connectoon */ - if (!(stmt= mysql_stmt_init(mysql))) - die("unable to init stmt structure"); - + if(!(stmt= cur_con->stmt)) + { + if (!(stmt= mysql_stmt_init(mysql))) + die("unable to init stmt structure"); + cur_con->stmt= stmt; + } + /* Prepare the query */ @@ -3548,11 +3567,36 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, goto end; } + /* + Get the warnings from mysql_stmt_prepare and keep them in a + separate string + */ + + if (!disable_warnings) + { + init_dynamic_string(&ds_prepare_warnings, "", 1024, 1024); + append_warnings(&ds_prepare_warnings, mysql); + } + + /* No need to call mysql_stmt_bind_param() because we have no parameter markers. */ +#ifdef BUG14013_FIXED + /* + Use cursor when retrieving result + */ + if (cursor_protocol_enabled) + { + unsigned long type= CURSOR_TYPE_READ_ONLY; + if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) + die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + } +#endif + /* Execute the query */ @@ -3571,7 +3615,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { my_bool one= 1; if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) - die("mysql_stmt_attr_set failed': %d %s", + die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } @@ -3589,14 +3633,14 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* If we got here the statement was both executed and read succeesfully */ handle_no_error(command); - /* - Not all statements creates a result set. If there is one we can - now create another normal result set that contains the meta - data. This set can be handled almost like any other non prepared - statement result set. - */ if (!disable_result_log) { + /* + Not all statements creates a result set. If there is one we can + now create another normal result set that contains the meta + data. This set can be handled almost like any other non prepared + statement result set. + */ if ((res= mysql_stmt_result_metadata(stmt)) != NULL) { /* Take the column count from meta info */ @@ -3612,7 +3656,19 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, append_stmt_result(ds, stmt, fields, num_fields); mysql_free_result(res); /* Free normal result set with meta data */ + + } + else + { + /* + This is a query without resultset + */ + /* + Add warnings from prepare to output + */ + if (!disable_warnings) + dynstr_append(ds, ds_prepare_warnings.str); } if (!disable_warnings) @@ -3620,23 +3676,26 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, if (!disable_info) append_info(ds, (ulong)mysql_affected_rows(mysql), mysql_info(mysql)); + } end: free_replace(); + + if (!disable_warnings) + dynstr_free(&ds_prepare_warnings); + /* We save the return code (mysql_stmt_errno(stmt)) from the last call sent to the server into the mysqltest builtin variable $mysql_errno. This variable then can be used from the test case itself. */ var_set_errno(mysql_stmt_errno(stmt)); - mysql_stmt_close(stmt); DBUG_VOID_RETURN; } /* - Run query flags control the phased/stages of query execution to be performed @@ -3653,10 +3712,12 @@ end: static void run_query(MYSQL *mysql, struct st_query *command, int flags) { DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; + DYNAMIC_STRING ds_result; DYNAMIC_STRING eval_query; char *query; int query_len; + my_bool view_created= 0, sp_created= 0; + my_bool complete_query= ((flags & QUERY_SEND) && (flags & QUERY_REAP)); /* Evaluate query if this is an eval command @@ -3682,35 +3743,122 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) */ if (command->record_file[0]) { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; + init_dynamic_string(&ds_result, "", 16384, 65536); + ds= &ds_result; } else ds= &ds_res; - /* Store the query into the output buffer */ + /* + Log the query into the output buffer + */ if (!disable_query_log && (flags & QUERY_SEND)) { - replace_dynstr_append_mem(ds,query, query_len); + replace_dynstr_append_mem(ds, query, query_len); dynstr_append_mem(ds, delimiter, delimiter_length); dynstr_append_mem(ds, "\n", 1); } + if (view_protocol_enabled && + complete_query && + match_re(&view_re, query)) + { + /* + Create the query as a view. + Use replace since view can exist from a failed mysqltest run + */ + DYNAMIC_STRING query_str; + init_dynamic_string(&query_str, + "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ", + query_len+64, 256); + dynstr_append_mem(&query_str, query, query_len); + if (mysql_query(mysql, query_str.str)) + { + /* + Failed to create the view, this is not fatal + just run the query the normal way + */ + DBUG_PRINT("view_create_error", + ("Failed to create view '%s': %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql))); + } + else + { + /* + Yes, it was possible to create this query as a view + */ + view_created= 1; + query= (char*)"SELECT * FROM mysqltest_tmp_v"; + query_len = strlen(query); + } + + dynstr_free(&query_str); + + } + + if (sp_protocol_enabled && + complete_query && + match_re(&sp_re, query)) + { + /* + Create the query as a stored procedure + Drop first since sp can exist from a failed mysqltest run + */ + DYNAMIC_STRING query_str; + init_dynamic_string(&query_str, + "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;\n", + query_len+64, 256); + mysql_query(mysql, query_str.str); + dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n"); + dynstr_append_mem(&query_str, query, query_len); + if (mysql_query(mysql, query_str.str)) + { + /* + Failed to create the stored procedure for this query, + this is not fatal just run the query the normal way + */ + DBUG_PRINT("sp_create_error", + ("Failed to create sp '%s': %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql))); + } + else + { + sp_created= 1; + + query= (char*)"CALL mysqltest_tmp_sp()"; + query_len = strlen(query); + } + dynstr_free(&query_str); + } + /* Find out how to run this query - We don't have a mysql_stmt_send_execute() so it must be a - complete SEND+REAP to use prepared statement + Always run with normal C API if it's not a complete + SEND + REAP If it is a '?' in the query it may be a SQL level prepared - statement already and we can't do it twice + statement already and we can't do it twice */ if (ps_protocol_enabled && - (flags & QUERY_SEND) && (flags & QUERY_REAP) && - ps_match_re(query)) + complete_query && + match_re(&ps_re, query)) run_query_stmt(mysql, command, query, query_len, ds); else run_query_normal(mysql, command, flags, query, query_len, ds); + + if (sp_created) + { + if (mysql_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) + die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); + } + + if (view_created) + { + if (mysql_query(mysql, "DROP VIEW mysqltest_tmp_v ")) + die("Failed to drop view: %d: %s", + mysql_errno(mysql), mysql_error(mysql)); + } if (record) { @@ -3730,19 +3878,45 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) check_result(ds, command->record_file, command->require_file); } - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); + if (ds == &ds_result) + dynstr_free(&ds_result); if (command->type == Q_EVAL) dynstr_free(&eval_query); } /****************************************************************************\ - * Functions to match SQL statements that can be prepared + * Functions to detect different SQL statements \****************************************************************************/ -static void ps_init_re(void) +static char *re_eprint(int err) { + static char epbuf[100]; + size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, + epbuf, sizeof(epbuf)); + assert(len <= sizeof(epbuf)); + return(epbuf); +} + +static void init_re_comp(my_regex_t *re, const char* str) +{ + int err= my_regcomp(re, str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), + &my_charset_latin1); + if (err) + { + char erbuf[100]; + int len= my_regerror(err, re, erbuf, sizeof(erbuf)); + die("error %s, %d/%d `%s'\n", + re_eprint(err), len, (int)sizeof(erbuf), erbuf); + } +} + +static void init_re(void) +{ + /* + Filter for queries that can be run using the + MySQL Prepared Statements C API + */ const char *ps_re_str = "^(" "[[:space:]]*REPLACE[[:space:]]|" @@ -3757,50 +3931,48 @@ static void ps_init_re(void) "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; - int err= my_regcomp(&ps_re, ps_re_str, - (REG_EXTENDED | REG_ICASE | REG_NOSUB), - &my_charset_latin1); - if (err) - { - char erbuf[100]; - int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); - fprintf(stderr, "error %s, %d/%d `%s'\n", - ps_eprint(err), len, (int)sizeof(erbuf), erbuf); - exit(1); - } + /* + Filter for queries that can be run using the + Stored procedures + */ + const char *sp_re_str =ps_re_str; + + /* + Filter for queries that can be run as views + */ + const char *view_re_str = + "^(" + "[[:space:]]*SELECT[[:space:]])"; + + init_re_comp(&ps_re, ps_re_str); + init_re_comp(&sp_re, sp_re_str); + init_re_comp(&view_re, view_re_str); } -static int ps_match_re(char *stmt_str) +static int match_re(my_regex_t *re, char *str) { - int err= my_regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); + int err= my_regexec(re, str, (size_t)0, NULL, 0); if (err == 0) return 1; else if (err == REG_NOMATCH) return 0; - else - { + + { char erbuf[100]; - int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); - fprintf(stderr, "error %s, %d/%d `%s'\n", - ps_eprint(err), len, (int)sizeof(erbuf), erbuf); - exit(1); + int len= my_regerror(err, re, erbuf, sizeof(erbuf)); + die("error %s, %d/%d `%s'\n", + re_eprint(err), len, (int)sizeof(erbuf), erbuf); } + return 0; } -static char *ps_eprint(int err) -{ - static char epbuf[100]; - size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); - assert(len <= sizeof(epbuf)); - return(epbuf); -} - - -static void ps_free_reg(void) +static void free_re(void) { my_regfree(&ps_re); + my_regfree(&sp_re); + my_regfree(&view_re); } /****************************************************************************/ @@ -3930,8 +4102,7 @@ static void init_var_hash(MYSQL *mysql) v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0); my_hash_insert(&var_hash, (byte*) v); v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0); - my_hash_insert(&var_hash, (byte*) v); - v= var_init(0,"DB", 2, db, 0); + my_hash_insert(&var_hash, (byte*) v); v= var_init(0,"DB", 2, db, 0); my_hash_insert(&var_hash, (byte*) v); DBUG_VOID_RETURN; } @@ -3969,7 +4140,7 @@ int main(int argc, char **argv) cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= cmd_none; - + init_dynamic_string(&ds_res, "", 0, 65536); parse_args(argc, argv); @@ -3988,11 +4159,15 @@ int main(int argc, char **argv) if (manager_host) init_manager(); #endif - if (ps_protocol) - { + init_re(); + ps_protocol_enabled= ps_protocol; + sp_protocol_enabled= sp_protocol; + view_protocol_enabled= view_protocol; + cursor_protocol_enabled= cursor_protocol; + /* Cursor protcol implies ps protocol */ + if (cursor_protocol_enabled) ps_protocol_enabled= 1; - ps_init_re(); - } + if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) @@ -5282,3 +5457,5 @@ FILE *my_popen(const char *cmd, const char *mode __attribute__((unused))) } #endif /* __NETWARE__ or __WIN__*/ + + diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 2ca7e7c5e15..3ab0d016f48 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -191,6 +191,9 @@ our $opt_ssl; our $opt_skip_ssl; our $opt_ssl_supported; our $opt_ps_protocol; +our $opt_sp_protocol; +our $opt_cursor_protocol; +our $opt_view_protocol; our $opt_current_test; our $opt_ddd; @@ -490,6 +493,9 @@ sub command_line_setup () { # Control what engine/variation to run 'embedded-server' => \$opt_embedded_server, 'ps-protocol' => \$opt_ps_protocol, + 'sp-protocol' => \$opt_sp_protocol, + 'view-protocol' => \$opt_view_protocol, + 'cursor-protocol' => \$opt_cursor_protocol, 'ssl|with-openssl' => \$opt_ssl, 'skip-ssl' => \$opt_skip_ssl, 'compress' => \$opt_compress, @@ -2554,6 +2560,21 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--ps-protocol"); } + if ( $opt_sp_protocol ) + { + mtr_add_arg($args, "--sp-protocol"); + } + + if ( $opt_view_protocol ) + { + mtr_add_arg($args, "--view-protocol"); + } + + if ( $opt_cursor_protocol ) + { + mtr_add_arg($args, "--cursor-protocol"); + } + if ( $opt_strace_client ) { $exe= "strace"; # FIXME there are ktrace, .... @@ -2685,6 +2706,10 @@ Options to control what engine/variation to run embedded-server Use the embedded server, i.e. no mysqld daemons ps-protocol Use the binary protocol between client and server + cursor-protocol Use the cursor protocol between client and server + (implies --ps-protocol) + view-protocol Create a view to execute all non updating queries + sp-protocol Create a stored procedure to execute all queries compress Use the compressed protocol between client and server ssl Use ssl protocol between client and server skip-ssl Dont start sterver with support for ssl connections From 39b2fb2b3c314976ea848ad740dc8de7bcad5089 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 3 Nov 2005 19:32:19 +0100 Subject: [PATCH 005/154] Reapplying patch Check for NULLs only if we don't replace column results, get real results after all checks. (see bug #14254: func_crypt.test fails on FreeBSD with --ps-protocol). Remove two FIXME's --- client/mysqltest.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index a2b2b3477eb..89f164b9a47 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3043,8 +3043,6 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, my_bool *is_null; ulong *length; ulonglong num_rows; - - /* FIXME we don't handle vertical display ..... */ uint col_idx, row_idx; /* Allocate array with bind structs, lengths and NULL flags */ @@ -3088,19 +3086,23 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, /* Read result from each column */ for (col_idx= 0; col_idx < num_fields; col_idx++) { - /* FIXME is string terminated? */ - const char *val= (const char *)bind[col_idx].buffer; - ulonglong len= *bind[col_idx].length; + const char *val; + ulonglong len; if (col_idx < max_replace_column && replace_column[col_idx]) { val= replace_column[col_idx]; len= strlen(val); } - if (*bind[col_idx].is_null) + else if (*bind[col_idx].is_null) { val= "NULL"; len= 4; } + else + { + val= (const char *) bind[col_idx].buffer; + len= *bind[col_idx].length; + } if (!display_result_vertically) { if (col_idx) /* No tab before first col */ From 4f26b443185b820de1d979917f42882930c861f4 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 4 Nov 2005 12:00:34 +0100 Subject: [PATCH 006/154] Remove trailing whitespace --- client/mysqltest.c | 208 +++++++++++++++++++++++---------------------- 1 file changed, 105 insertions(+), 103 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 89f164b9a47..04ad33bb8bc 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -119,7 +119,7 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, set to type ERR_EMPTY. When an SQL statement return an error we use this list to check if this is an expected error. */ - + enum match_err_type { ERR_EMPTY= 0, @@ -300,7 +300,7 @@ struct connection* cur_con, *next_con, *cons_end; enum enum_commands { Q_CONNECTION=1, Q_QUERY, -Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, +Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, Q_INC, Q_DEC, Q_SOURCE, Q_DISCONNECT, Q_LET, Q_ECHO, @@ -740,14 +740,14 @@ err: /* Check the content of ds against content of file fname - + SYNOPSIS check_result ds - content to be checked fname - name of file to check against - require_option - if set and check fails, the test will be aborted with the special + require_option - if set and check fails, the test will be aborted with the special exit code "not supported test" - + RETURN VALUES error - the function will not return @@ -1645,7 +1645,7 @@ static uint get_errcodes(match_err *to,struct st_query *q) /* SQL error as string */ st_error *e= global_error; char *start= p++; - + for (; *p == '_' || my_isalnum(charset_info, *p); p++) ; for (; e->name; e++) @@ -1919,13 +1919,13 @@ int close_connection(struct st_query *q) SYNOPSIS safe_get_param str - string to get param from - arg - pointer to string where result will be stored + arg - pointer to string where result will be stored msg - Message to display if param is not found if msg is 0 this param is not required and param may be empty - + RETURNS pointer to str after param - + */ char* safe_get_param(char *str, char** arg, const char *msg) @@ -1933,7 +1933,7 @@ char* safe_get_param(char *str, char** arg, const char *msg) DBUG_ENTER("safe_get_param"); if(!*str) { - if (msg) + if (msg) die(msg); *arg= str; DBUG_RETURN(str); @@ -2082,7 +2082,7 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, *create_conn= 0; goto err; } - else + else { handle_no_error(q); @@ -2528,7 +2528,7 @@ int read_line(char *buf, int size) state= R_Q; } else -state= R_NORMAL; + state= R_NORMAL; break; case R_Q: @@ -2922,9 +2922,9 @@ char* safe_str_append(char *buf, const char *str, int size) } -/* +/* Write the content of str into file - + SYNOPSIS str_to_file fname - name of file to truncate/create and write to @@ -2941,7 +2941,7 @@ static void str_to_file(const char *fname, char *str, int size) fname=buff; } fn_format(buff,fname,"","",4); - + if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, MYF(MY_WME | MY_FFNF))) < 0) die("Could not open %s: errno = %d", buff, errno); @@ -3032,7 +3032,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) /* - Append all results from ps execution to the dynamic string separated + Append all results from ps execution to the dynamic string separated with '\t'. Values may be converted with 'replace_column' */ @@ -3044,7 +3044,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, ulong *length; ulonglong num_rows; uint col_idx, row_idx; - + /* Allocate array with bind structs, lengths and NULL flags */ bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), MYF(MY_WME | MY_FAE | MY_ZEROFILL)); @@ -3052,7 +3052,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, MYF(MY_WME | MY_FAE)); is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), MYF(MY_WME | MY_FAE)); - + for (col_idx= 0; col_idx < num_fields; col_idx++) { /* Allocate data for output */ @@ -3062,19 +3062,19 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, */ uint max_length= max(field[col_idx].max_length + 1, 1024); char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); - + bind[col_idx].buffer_type= MYSQL_TYPE_STRING; bind[col_idx].buffer= (char *)str_data; bind[col_idx].buffer_length= max_length; bind[col_idx].is_null= &is_null[col_idx]; bind[col_idx].length= &length[col_idx]; } - + /* Fill in the data into the structures created above */ if (mysql_stmt_bind_result(stmt, bind)) - die("mysql_stmt_bind_result failed: %d: %s", + die("mysql_stmt_bind_result failed: %d: %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - + /* Read result from each row */ num_rows= mysql_stmt_num_rows(stmt); for (row_idx= 0; row_idx < num_rows; row_idx++) @@ -3082,7 +3082,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, if (mysql_stmt_fetch(stmt)) die("mysql_stmt_fetch failed: %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - + /* Read result from each column */ for (col_idx= 0; col_idx < num_fields; col_idx++) { @@ -3120,13 +3120,13 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1); } - + if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); - + free_replace_column(); - + for (col_idx= 0; col_idx < num_fields; col_idx++) { /* Free data for output */ @@ -3144,7 +3144,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, */ static void append_metadata(DYNAMIC_STRING *ds, - MYSQL_FIELD *field, + MYSQL_FIELD *field, uint num_fields) { MYSQL_FIELD *field_end; @@ -3217,10 +3217,10 @@ static void append_info(DYNAMIC_STRING* ds, ulong affected_rows, } -/* - Display the table headings with the names tab separated +/* + Display the table headings with the names tab separated */ -static void append_table_headings(DYNAMIC_STRING* ds, +static void append_table_headings(DYNAMIC_STRING* ds, MYSQL_FIELD* field, uint num_fields) { @@ -3253,14 +3253,14 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) we have not read all results... */ DBUG_ASSERT(!mysql_more_results(mysql)); - + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql)); - + if (!(warn_res= mysql_store_result(mysql))) die("Warning count is %u but didn't get any warnings", count); - + dynstr_append_mem(ds, "Warnings:\n", 10); append_result(ds, warn_res); mysql_free_result(warn_res); @@ -3271,7 +3271,7 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) /* Run query using MySQL C API - + SYNPOSIS run_query_normal mysql - mysql handle @@ -3285,8 +3285,8 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) error - function will not return */ -static void run_query_normal(MYSQL *mysql, struct st_query *command, - int flags, char *query, int query_len, +static void run_query_normal(MYSQL *mysql, struct st_query *command, + int flags, char *query, int query_len, DYNAMIC_STRING *ds) { MYSQL_RES *res= 0; @@ -3297,7 +3297,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, if (flags & QUERY_SEND) { - /* + /* Send the query */ if (mysql_send_query(mysql, query, query_len)) @@ -3310,11 +3310,11 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, if (!(flags & QUERY_REAP)) DBUG_VOID_RETURN; - + do { /* - When on first result set, call mysql_read_query_result to retrieve + When on first result set, call mysql_read_query_result to retrieve answer to the query sent earlier */ if ((counter==0) && mysql_read_query_result(mysql)) @@ -3325,8 +3325,8 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, } - /* - Store the result. If res is NULL, use mysql_field_count to + /* + Store the result. If res is NULL, use mysql_field_count to determine if that was expected */ if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql)) @@ -3386,7 +3386,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, goto end; } DBUG_ASSERT(err == -1); /* Successful and there are no more results */ - + /* If we come here the query is both executed and read successfully */ handle_no_error(command); @@ -3428,12 +3428,12 @@ static void handle_error(const char *query, struct st_query *q, const char *err_sqlstate, DYNAMIC_STRING *ds) { uint i; - + DBUG_ENTER("handle_error"); if (q->require_file) abort_not_supported_test(); - + if (q->abort_on_error) die("query '%s' failed: %d: %s", query, err_errno, err_error); @@ -3527,7 +3527,7 @@ static void handle_no_error(struct st_query *q) /* Run query using prepared statement C API - + SYNPOSIS run_query_stmt mysql - mysql handle @@ -3540,7 +3540,7 @@ static void handle_no_error(struct st_query *q) error - function will not return */ -static void run_query_stmt(MYSQL *mysql, struct st_query *command, +static void run_query_stmt(MYSQL *mysql, struct st_query *command, char *query, int query_len, DYNAMIC_STRING *ds) { MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ @@ -3548,7 +3548,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, DYNAMIC_STRING ds_prepare_warnings; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); - + /* Init a new stmt if it's not alreday one created for this connectoon */ @@ -3558,7 +3558,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, die("unable to init stmt structure"); cur_con->stmt= stmt; } - + /* Prepare the query */ @@ -3570,10 +3570,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, } /* - Get the warnings from mysql_stmt_prepare and keep them in a - separate string + Get the warnings from mysql_stmt_prepare and keep them in a + separate string */ - + if (!disable_warnings) { init_dynamic_string(&ds_prepare_warnings, "", 1024, 1024); @@ -3594,7 +3594,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { unsigned long type= CURSOR_TYPE_READ_ONLY; if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) - die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", + die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } #endif @@ -3602,7 +3602,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* Execute the query */ - if (mysql_stmt_execute(stmt)) + if (mysql_stmt_execute(stmt)) { handle_error(query, command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); @@ -3617,7 +3617,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { my_bool one= 1; if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) - die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s", + die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } @@ -3635,6 +3635,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* If we got here the statement was both executed and read succeesfully */ handle_no_error(command); if (!disable_result_log) + { /* Not all statements creates a result set. If there is one we can now create another normal result set that contains the meta @@ -3642,27 +3643,28 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, statement result set. */ if ((res= mysql_stmt_result_metadata(stmt)) != NULL) + { /* Take the column count from meta info */ MYSQL_FIELD *fields= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); - + if (display_metadata) append_metadata(ds, fields, num_fields); - + if (!display_result_vertically) append_table_headings(ds, fields, num_fields); - - append_stmt_result(ds, stmt, fields, num_fields); - + + append_stmt_result(ds, stmt, fields, num_fields); + mysql_free_result(res); /* Free normal result set with meta data */ - } - else + } + else { /* This is a query without resultset */ - + /* Add warnings from prepare to output */ @@ -3672,15 +3674,15 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, if (!disable_warnings) append_warnings(ds, mysql); - + if (!disable_info) append_info(ds, (ulong)mysql_affected_rows(mysql), mysql_info(mysql)); - + } end: free_replace(); - + if (!disable_warnings) dynstr_free(&ds_prepare_warnings); @@ -3705,7 +3707,7 @@ end: run_query mysql - mysql handle command - currrent command pointer - + */ static void run_query(MYSQL *mysql, struct st_query *command, int flags) @@ -3735,7 +3737,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) } /* - When command->record_file is set the output of _this_ query + When command->record_file is set the output of _this_ query should be compared with an already existing file Create a temporary dynamic string to contain the output from this query. @@ -3748,8 +3750,8 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) else ds= &ds_res; - /* - Log the query into the output buffer + /* + Log the query into the output buffer */ if (!disable_query_log && (flags & QUERY_SEND)) { @@ -3762,13 +3764,13 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) complete_query && match_re(&view_re, query)) { - /* + /* Create the query as a view. - Use replace since view can exist from a failed mysqltest run - */ - DYNAMIC_STRING query_str; - init_dynamic_string(&query_str, - "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ", + Use replace since view can exist from a failed mysqltest run + */ + DYNAMIC_STRING query_str; + init_dynamic_string(&query_str, + "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ", query_len+64, 256); dynstr_append_mem(&query_str, query, query_len); if (mysql_query(mysql, query_str.str)) @@ -3777,7 +3779,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) Failed to create the view, this is not fatal just run the query the normal way */ - DBUG_PRINT("view_create_error", + DBUG_PRINT("view_create_error", ("Failed to create view '%s': %d: %s", query_str.str, mysql_errno(mysql), mysql_error(mysql))); } @@ -3787,12 +3789,12 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) Yes, it was possible to create this query as a view */ view_created= 1; - query= (char*)"SELECT * FROM mysqltest_tmp_v"; + query= (char*)"SELECT * FROM mysqltest_tmp_v"; query_len = strlen(query); } dynstr_free(&query_str); - + } if (sp_protocol_enabled && @@ -3801,19 +3803,19 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) { /* Create the query as a stored procedure - Drop first since sp can exist from a failed mysqltest run - */ + Drop first since sp can exist from a failed mysqltest run + */ DYNAMIC_STRING query_str; - init_dynamic_string(&query_str, + init_dynamic_string(&query_str, "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;\n", query_len+64, 256); - mysql_query(mysql, query_str.str); + mysql_query(mysql, query_str.str); dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n"); dynstr_append_mem(&query_str, query, query_len); if (mysql_query(mysql, query_str.str)) { /* - Failed to create the stored procedure for this query, + Failed to create the stored procedure for this query, this is not fatal just run the query the normal way */ DBUG_PRINT("sp_create_error", @@ -3823,8 +3825,8 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) else { sp_created= 1; - - query= (char*)"CALL mysqltest_tmp_sp()"; + + query= (char*)"CALL mysqltest_tmp_sp()"; query_len = strlen(query); } dynstr_free(&query_str); @@ -3833,7 +3835,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) /* Find out how to run this query - Always run with normal C API if it's not a complete + Always run with normal C API if it's not a complete SEND + REAP If it is a '?' in the query it may be a SQL level prepared @@ -3845,17 +3847,17 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) run_query_stmt(mysql, command, query, query_len, ds); else run_query_normal(mysql, command, flags, query, query_len, ds); - + if (sp_created) { if (mysql_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); } - + if (view_created) { if (mysql_query(mysql, "DROP VIEW mysqltest_tmp_v ")) - die("Failed to drop view: %d: %s", + die("Failed to drop view: %d: %s", mysql_errno(mysql), mysql_error(mysql)); } @@ -3871,7 +3873,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) else if (command->record_file[0]) { /* - The output from _this_ query should be checked against an already + The output from _this_ query should be checked against an already existing file which has been specified using --require or --result */ check_result(ds, command->record_file, command->require_file); @@ -3891,7 +3893,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) static char *re_eprint(int err) { static char epbuf[100]; - size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, + size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); assert(len <= sizeof(epbuf)); return(epbuf); @@ -3905,15 +3907,15 @@ static void init_re_comp(my_regex_t *re, const char* str) { char erbuf[100]; int len= my_regerror(err, re, erbuf, sizeof(erbuf)); - die("error %s, %d/%d `%s'\n", + die("error %s, %d/%d `%s'\n", re_eprint(err), len, (int)sizeof(erbuf), erbuf); } } static void init_re(void) { - /* - Filter for queries that can be run using the + /* + Filter for queries that can be run using the MySQL Prepared Statements C API */ const char *ps_re_str = @@ -3930,13 +3932,13 @@ static void init_re(void) "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; - /* - Filter for queries that can be run using the + /* + Filter for queries that can be run using the Stored procedures */ const char *sp_re_str =ps_re_str; - /* + /* Filter for queries that can be run as views */ const char *view_re_str = @@ -3958,7 +3960,7 @@ static int match_re(my_regex_t *re, char *str) else if (err == REG_NOMATCH) return 0; - { + { char erbuf[100]; int len= my_regerror(err, re, erbuf, sizeof(erbuf)); die("error %s, %d/%d `%s'\n", @@ -4093,7 +4095,7 @@ static void init_var_hash(MYSQL *mysql) { VAR *v; DBUG_ENTER("init_var_hash"); - if (hash_init(&var_hash, charset_info, + if (hash_init(&var_hash, charset_info, 1024, 0, 0, get_var_key, var_free, MYF(0))) die("Variable hash initialization failed"); my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0, @@ -4139,7 +4141,7 @@ int main(int argc, char **argv) cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= cmd_none; - + init_dynamic_string(&ds_res, "", 0, 65536); parse_args(argc, argv); @@ -4486,8 +4488,8 @@ int main(int argc, char **argv) /* No result_file to compare with, print the result to stdout */ printf("%s", ds_res.str); } - } - else + } + else { /* The test didn't produce any output */ } @@ -5440,7 +5442,7 @@ static char *subst_env_var(const char *str) */ #undef popen /* Remove wrapper */ -#ifdef __WIN__ +#ifdef __WIN__ #define popen _popen /* redefine for windows */ #endif From a6031b6425a8ae7f687c12b56913dc07ab793d39 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 4 Nov 2005 12:15:49 +0100 Subject: [PATCH 007/154] Formatting improved --- client/mysqltest.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 04ad33bb8bc..224985227cd 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2912,15 +2912,6 @@ int parse_args(int argc, char **argv) return 0; } -char* safe_str_append(char *buf, const char *str, int size) -{ - int i,c ; - for (i = 0; (c = *str++) && i < size - 1; i++) - *buf++ = c; - *buf = 0; - return buf; -} - /* Write the content of str into file @@ -2931,6 +2922,7 @@ char* safe_str_append(char *buf, const char *str, int size) str - content to write to file size - size of content witten to file */ + static void str_to_file(const char *fname, char *str, int size) { int fd; @@ -2938,11 +2930,11 @@ static void str_to_file(const char *fname, char *str, int size) if (!test_if_hard_path(fname)) { strxmov(buff, opt_basedir, fname, NullS); - fname=buff; + fname= buff; } fn_format(buff,fname,"","",4); - if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, + if ((fd= my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, MYF(MY_WME | MY_FFNF))) < 0) die("Could not open %s: errno = %d", buff, errno); if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP))) @@ -2950,6 +2942,7 @@ static void str_to_file(const char *fname, char *str, int size) my_close(fd, MYF(0)); } + void dump_result_to_reject_file(const char *record_file, char *buf, int size) { char reject_file[FN_REFLEN]; @@ -2972,6 +2965,7 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, dynstr_append_mem(ds, val, len); } + /* Append zero-terminated string to ds, with optional replace */ static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val) @@ -3036,8 +3030,8 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) with '\t'. Values may be converted with 'replace_column' */ -static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt, - MYSQL_FIELD* field, uint num_fields) +static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, + MYSQL_FIELD *field, uint num_fields) { MYSQL_BIND *bind; my_bool *is_null; @@ -3198,12 +3192,13 @@ static void append_metadata(DYNAMIC_STRING *ds, } } + /* Append affected row count and other info to output */ -static void append_info(DYNAMIC_STRING* ds, ulong affected_rows, - const char* info) +static void append_info(DYNAMIC_STRING *ds, ulong affected_rows, + const char *info) { char buf[40]; sprintf(buf,"affected rows: %lu\n", affected_rows); @@ -3220,8 +3215,9 @@ static void append_info(DYNAMIC_STRING* ds, ulong affected_rows, /* Display the table headings with the names tab separated */ -static void append_table_headings(DYNAMIC_STRING* ds, - MYSQL_FIELD* field, + +static void append_table_headings(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, uint num_fields) { uint col_idx; From 58db54364f964f7fb7f324bd2b3f8d5fb18b7706 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 4 Nov 2005 15:37:39 +0100 Subject: [PATCH 008/154] Fixed BUG#14498: Stored procedures: hang if undefined variable and exception The problem was to continue at the right place in the code after the test expression in a flow control statement fails with an exception (internally, the test in sp_instr_jump_if_not), and the exception is caught by a continue handler. Execution must then be resumed after the the entire flow control statement (END IF, END WHILE, etc). --- mysql-test/r/sp.result | 84 +++++++++++++++++++++++++ mysql-test/t/sp.test | 86 +++++++++++++++++++++++++ sql/sp_head.cc | 140 ++++++++++++++++++++++------------------- sql/sp_head.h | 88 ++++++++++++++------------ sql/sql_yacc.yy | 20 +++++- 5 files changed, 308 insertions(+), 110 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1f3f7dba7da..7a3d519ebb9 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3575,4 +3575,88 @@ DROP VIEW bug13095_v1 DROP PROCEDURE IF EXISTS bug13095; DROP VIEW IF EXISTS bug13095_v1; DROP TABLE IF EXISTS bug13095_t1; +drop procedure if exists bug14498_1| +drop procedure if exists bug14498_2| +drop procedure if exists bug14498_3| +drop procedure if exists bug14498_4| +drop procedure if exists bug14498_5| +create procedure bug14498_1() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +if v then +select 'yes' as 'v'; +else +select 'no' as 'v'; +end if; +select 'done' as 'End'; +end| +create procedure bug14498_2() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +while v do +select 'yes' as 'v'; +end while; +select 'done' as 'End'; +end| +create procedure bug14498_3() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +repeat +select 'maybe' as 'v'; +until v end repeat; +select 'done' as 'End'; +end| +create procedure bug14498_4() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +case v +when 1 then +select '1' as 'v'; +when 2 then +select '2' as 'v'; +else +select '?' as 'v'; +end case; +select 'done' as 'End'; +end| +create procedure bug14498_5() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +case +when v = 1 then +select '1' as 'v'; +when v = 2 then +select '2' as 'v'; +else +select '?' as 'v'; +end case; +select 'done' as 'End'; +end| +call bug14498_1()| +Handler +error +End +done +call bug14498_2()| +Handler +error +End +done +call bug14498_3()| +v +maybe +Handler +error +End +done +call bug14498_5()| +Handler +error +End +done +drop procedure bug14498_1| +drop procedure bug14498_2| +drop procedure bug14498_3| +drop procedure bug14498_4| +drop procedure bug14498_5| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index ab57139bb77..19169273cba 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4489,6 +4489,92 @@ DROP TABLE IF EXISTS bug13095_t1; delimiter |; +# +# BUG#14498: Stored procedures: hang if undefined variable and exception +# +--disable_warnings +drop procedure if exists bug14498_1| +drop procedure if exists bug14498_2| +drop procedure if exists bug14498_3| +drop procedure if exists bug14498_4| +drop procedure if exists bug14498_5| +--enable_warnings + +create procedure bug14498_1() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + if v then + select 'yes' as 'v'; + else + select 'no' as 'v'; + end if; + select 'done' as 'End'; +end| + +create procedure bug14498_2() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + while v do + select 'yes' as 'v'; + end while; + select 'done' as 'End'; +end| + +create procedure bug14498_3() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + repeat + select 'maybe' as 'v'; + until v end repeat; + select 'done' as 'End'; +end| + +create procedure bug14498_4() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + case v + when 1 then + select '1' as 'v'; + when 2 then + select '2' as 'v'; + else + select '?' as 'v'; + end case; + select 'done' as 'End'; +end| + +create procedure bug14498_5() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + case + when v = 1 then + select '1' as 'v'; + when v = 2 then + select '2' as 'v'; + else + select '?' as 'v'; + end case; + select 'done' as 'End'; +end| + +call bug14498_1()| +call bug14498_2()| +call bug14498_3()| +# QQ We can't call this at the moment, due to a known bug (BUG#14643) +#call bug14498_4()| +call bug14498_5()| + +drop procedure bug14498_1| +drop procedure bug14498_2| +drop procedure bug14498_3| +drop procedure bug14498_4| +drop procedure bug14498_5| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index abc66ce0b21..7d3a708a5a8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -437,13 +437,14 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), - m_flags(0), m_returns_cs(NULL) + m_flags(0), m_returns_cs(NULL), m_cont_level(0) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); m_backpatch.empty(); + m_cont_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); @@ -1568,6 +1569,39 @@ sp_head::check_backpatch(THD *thd) return 0; } +void +sp_head::new_cont_backpatch(sp_instr_jump_if_not *i) +{ + m_cont_level+= 1; + if (i) + { + /* Use the cont. destination slot to store the level */ + i->m_cont_dest= m_cont_level; + (void)m_cont_backpatch.push_front(i); + } +} + +void +sp_head::add_cont_backpatch(sp_instr_jump_if_not *i) +{ + i->m_cont_dest= m_cont_level; + (void)m_cont_backpatch.push_front(i); +} + +void +sp_head::do_cont_backpatch() +{ + uint dest= instructions(); + uint lev= m_cont_level--; + sp_instr_jump_if_not *i; + + while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev) + { + i->m_cont_dest= dest; + (void)m_cont_backpatch.pop(); + } +} + void sp_head::set_info(char *definer, uint definerlen, longlong created, longlong modified, @@ -1782,7 +1816,10 @@ sp_head::show_create_function(THD *thd) /* - TODO: what does this do?? + Do some minimal optimization of the code: + 1) Mark used instructions + 1.1) While doing this, shortcut jumps to jump instructions + 2) Compact the code, removing unused instructions */ void sp_head::optimize() @@ -1805,7 +1842,7 @@ void sp_head::optimize() else { if (src != dst) - { + { // Move the instruction and update prev. jumps sp_instr *ibp; List_iterator_fast li(bp); @@ -1813,8 +1850,7 @@ void sp_head::optimize() while ((ibp= li++)) { sp_instr_jump *ji= static_cast(ibp); - if (ji->m_dest == src) - ji->m_dest= dst; + ji->set_destination(src, dst); } } i->opt_move(dst, &bp); @@ -2144,65 +2180,6 @@ sp_instr_jump::opt_move(uint dst, List *bp) } -/* - sp_instr_jump_if class functions -*/ - -int -sp_instr_jump_if::execute(THD *thd, uint *nextp) -{ - DBUG_ENTER("sp_instr_jump_if::execute"); - DBUG_PRINT("info", ("destination: %u", m_dest)); - DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); -} - -int -sp_instr_jump_if::exec_core(THD *thd, uint *nextp) -{ - Item *it; - int res; - - it= sp_prepare_func_item(thd, &m_expr); - if (!it) - res= -1; - else - { - res= 0; - if (it->val_bool()) - *nextp = m_dest; - else - *nextp = m_ip+1; - } - - return res; -} - -void -sp_instr_jump_if::print(String *str) -{ - str->reserve(12); - str->append("jump_if "); - str->qs_append(m_dest); - str->append(' '); - m_expr->print(str); -} - -uint -sp_instr_jump_if::opt_mark(sp_head *sp) -{ - sp_instr *i; - - marked= 1; - if ((i= sp->get_instr(m_dest))) - { - m_dest= i->opt_shortcut_jump(sp, this); - m_optdest= sp->get_instr(m_dest); - } - sp->opt_mark(m_dest); - return m_ip+1; -} - - /* sp_instr_jump_if_not class functions */ @@ -2224,7 +2201,10 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) it= sp_prepare_func_item(thd, &m_expr); if (! it) + { res= -1; + *nextp = m_cont_dest; + } else { res= 0; @@ -2241,10 +2221,12 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - str->reserve(16); + str->reserve(24); str->append("jump_if_not "); str->qs_append(m_dest); - str->append(' '); + str->append('('); + str->qs_append(m_cont_dest); + str->append(") "); m_expr->print(str); } @@ -2261,9 +2243,35 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); + if ((i= sp->get_instr(m_cont_dest))) + { + m_cont_dest= i->opt_shortcut_jump(sp, this); + m_cont_optdest= sp->get_instr(m_cont_dest); + } + sp->opt_mark(m_cont_dest); return m_ip+1; } +void +sp_instr_jump_if_not::opt_move(uint dst, List *bp) +{ + /* + cont. destinations may point backwards after shortcutting jumps + during the mark phase. If it's still pointing forwards, only + push this for backpatching if sp_instr_jump::opt_move() will not + do it (i.e. if the m_dest points backwards). + */ + if (m_cont_dest > m_ip) + { // Forward + if (m_dest < m_ip) + bp->push_back(this); + } + else if (m_cont_optdest) + m_cont_dest= m_cont_optdest->m_ip; // Backward + /* This will take care of m_dest and m_ip */ + sp_instr_jump::opt_move(dst, bp); +} + /* sp_instr_freturn class functions diff --git a/sql/sp_head.h b/sql/sp_head.h index ed0f3987e01..e822ed96c02 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -38,6 +38,7 @@ sp_get_flags_for_command(LEX *lex); struct sp_label; class sp_instr; +class sp_instr_jump_if_not; struct sp_cond_type; struct sp_pvar; @@ -240,6 +241,18 @@ public: int check_backpatch(THD *thd); + // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. + void + new_cont_backpatch(sp_instr_jump_if_not *i); + + // Add an instruction to the current level + void + add_cont_backpatch(sp_instr_jump_if_not *i); + + // Backpatch (and pop) the current level to the current position. + void + do_cont_backpatch(); + char *name(uint *lenp = 0) const { if (lenp) @@ -309,6 +322,18 @@ private: sp_instr *instr; } bp_t; List m_backpatch; // Instructions needing backpatching + /* + We need a special list for backpatching of conditional jump's continue + destination (in the case of a continue handler catching an error in + the test), since it would otherwise interfere with the normal backpatch + mechanism - jump_if_not instructions have two different destination + which are to be patched differently. + Since these occur in a more restricted way (always the same "level" in + the code), we don't need the label. + */ + List m_cont_backpatch; + uint m_cont_level; // The current cont. backpatch level + /* Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. @@ -622,6 +647,12 @@ public: m_dest= dest; } + virtual void set_destination(uint old_dest, uint new_dest) + { + if (m_dest == old_dest) + m_dest= new_dest; + } + protected: sp_instr *m_optdest; // Used during optimization @@ -629,45 +660,6 @@ protected: }; // class sp_instr_jump : public sp_instr -class sp_instr_jump_if : public sp_instr_jump -{ - sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */ - void operator=(sp_instr_jump_if &); - -public: - - sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) - : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) - {} - - sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) - : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) - {} - - virtual ~sp_instr_jump_if() - {} - - virtual int execute(THD *thd, uint *nextp); - - virtual int exec_core(THD *thd, uint *nextp); - - virtual void print(String *str); - - virtual uint opt_mark(sp_head *sp); - - virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) - { - return m_ip; - } - -private: - - Item *m_expr; // The condition - sp_lex_keeper m_lex_keeper; - -}; // class sp_instr_jump_if : public sp_instr_jump - - class sp_instr_jump_if_not : public sp_instr_jump { sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */ @@ -675,12 +667,16 @@ class sp_instr_jump_if_not : public sp_instr_jump public: + uint m_cont_dest; // Where continue handlers will go + sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) - : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) + : sp_instr_jump(ip, ctx), m_cont_dest(0), m_expr(i), + m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) - : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) + : sp_instr_jump(ip, ctx, dest), m_cont_dest(0), m_expr(i), + m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} virtual ~sp_instr_jump_if_not() @@ -699,10 +695,20 @@ public: return m_ip; } + virtual void opt_move(uint dst, List *ibp); + + virtual void set_destination(uint old_dest, uint new_dest) + { + sp_instr_jump::set_destination(old_dest, new_dest); + if (m_cont_dest == old_dest) + m_cont_dest= new_dest; + } + private: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; + sp_instr *m_cont_optdest; // Used during optimization }; // class sp_instr_jump_if_not : public sp_instr_jump diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 109dcd7e86a..a93ac1e7061 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2009,14 +2009,21 @@ sp_proc_stmt: } sp->restore_lex(YYTHD); } - | IF sp_if END IF {} + | IF + { Lex->sphead->new_cont_backpatch(NULL); } + sp_if END IF + { Lex->sphead->do_cont_backpatch(); } | CASE_SYM WHEN_SYM { Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE; + Lex->sphead->new_cont_backpatch(NULL); } - sp_case END CASE_SYM {} + sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); } | CASE_SYM - { Lex->sphead->reset_lex(YYTHD); } + { + Lex->sphead->reset_lex(YYTHD); + Lex->sphead->new_cont_backpatch(NULL); + } expr WHEN_SYM { /* We "fake" this by using an anonymous variable which we @@ -2038,6 +2045,7 @@ sp_proc_stmt: sp_case END CASE_SYM { Lex->spcont->pop_pvar(); + Lex->sphead->do_cont_backpatch(); } | sp_labeled_control {} @@ -2306,6 +2314,7 @@ sp_if: $2, lex); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2360,6 +2369,7 @@ sp_case: lex->variables_used= 1; } sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2489,6 +2499,7 @@ sp_unlabeled_control: /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()); + sp->new_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2500,6 +2511,7 @@ sp_unlabeled_control: sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); lex->sphead->add_instr(i); + lex->sphead->do_cont_backpatch(); } | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM { Lex->sphead->reset_lex(YYTHD); } @@ -2513,6 +2525,8 @@ sp_unlabeled_control: lex); lex->sphead->add_instr(i); lex->sphead->restore_lex(YYTHD); + /* We can shortcut the cont_backpatch here */ + i->m_cont_dest= ip+1; } ; From 01dbce64d0f4c000f01d4aa9c3dce166e3cd16dc Mon Sep 17 00:00:00 2001 From: "ramil@mysql.com" <> Date: Thu, 24 Nov 2005 13:04:05 +0400 Subject: [PATCH 009/154] Fix for bug #15108: mysqld crashes when innodb_log_file_size is set > 4G --- sql/ha_innodb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 56e5fd8923f..6c89618c83a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1218,7 +1218,7 @@ innobase_init(void) "innobase_buffer_pool_size can't be over 4GB" " on 32-bit systems"); - DBUG_RETURN(0); + goto error; } if (innobase_log_file_size > UINT_MAX32) { @@ -1226,7 +1226,7 @@ innobase_init(void) "innobase_log_file_size can't be over 4GB" " on 32-bit systems"); - DBUG_RETURN(0); + goto error; } } From c9dc609d21425eee9dbc98c6c9b165fcf987e385 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Tue, 29 Nov 2005 08:42:36 +0100 Subject: [PATCH 010/154] DbdihMain.cpp: management server performs this check on configuration. If we get this far with something incorrect, something is very wrong. --- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index ca066b588e7..d666f9d3488 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -10976,7 +10976,8 @@ void Dbdih::initCommonData() cnoReplicas = 1; ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas); - cnoReplicas = cnoReplicas > 4 ? 4 : cnoReplicas; + progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, + "Only up to four replicas are supported. Check NoOfReplicas."); cgcpDelay = 2000; ndb_mgm_get_int_parameter(p, CFG_DB_GCP_INTERVAL, &cgcpDelay); From e6f2d500d624df1ce8ebf64bbd5c19f01d2e826d Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Tue, 29 Nov 2005 14:29:09 +0100 Subject: [PATCH 011/154] fix spuling mastaeke. Goup is not needed to run cluster --- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index d666f9d3488..14ff1003ff2 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -11569,14 +11569,14 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal) break; case CheckNodeGroups::GetNodeGroupMembers: { ok = true; - Uint32 ownNodeGoup = + Uint32 ownNodeGroup = Sysfile::getNodeGroup(sd->nodeId, SYSFILE->nodeGroups); - sd->output = ownNodeGoup; + sd->output = ownNodeGroup; sd->mask.clear(); NodeGroupRecordPtr ngPtr; - ngPtr.i = ownNodeGoup; + ngPtr.i = ownNodeGroup; ptrAss(ngPtr, nodeGroupRecord); for (Uint32 j = 0; j < ngPtr.p->nodeCount; j++) { jam(); @@ -11584,7 +11584,7 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal) } #if 0 for (int i = 0; i < MAX_NDB_NODES; i++) { - if (ownNodeGoup == + if (ownNodeGroup == Sysfile::getNodeGroup(i, SYSFILE->nodeGroups)) { sd->mask.set(i); } From 416cd04a519c327ef9c18e87f0277d7ba396eabe Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Tue, 29 Nov 2005 14:55:26 +0100 Subject: [PATCH 012/154] ndb_size.pl: fix incorrect quoting of column name --- ndb/tools/ndb_size.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl index ece0901e0b2..e0085c619f0 100644 --- a/ndb/tools/ndb_size.pl +++ b/ndb/tools/ndb_size.pl @@ -146,9 +146,9 @@ foreach(@{$tables}) elsif($type =~ /varchar/ || $type =~ /varbinary/) { my $fixed= 1+$size; - my @dynamic=$dbh->selectrow_array("select avg(length(" - .$dbh->quote($name) - .")) from `".$table.'`'); + my @dynamic=$dbh->selectrow_array("select avg(length(`" + .$name. + ."`)) from `".$table.'`'); $dynamic[0]=0 if !$dynamic[0]; @realsize= ($fixed,$fixed,ceil($dynamic[0])); } From ffdaaf30c6850ace62fa44485b393d8ab6ebc797 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Tue, 29 Nov 2005 15:38:39 +0100 Subject: [PATCH 013/154] DbdihMain.cpp: fix small error that jonas pointed out that would mean we always die on assert, intsead of just on error --- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 14ff1003ff2..4b6056aed91 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -10976,8 +10976,11 @@ void Dbdih::initCommonData() cnoReplicas = 1; ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas); - progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, - "Only up to four replicas are supported. Check NoOfReplicas."); + if (cnoReplicas > 4) + { + progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, + "Only up to four replicas are supported. Check NoOfReplicas."); + } cgcpDelay = 2000; ndb_mgm_get_int_parameter(p, CFG_DB_GCP_INTERVAL, &cgcpDelay); From 76861ac6ad643d0472cd6f728678ea62a438fe61 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Tue, 29 Nov 2005 19:17:39 +0100 Subject: [PATCH 014/154] BUG#5390 - problems with merge tables Problem #1: INSERT...SELECT INSERT ... SELECT with the same table on both sides (hidden below a MERGE table) does now work by buffering the select result. The duplicate detection works now after open_and_lock_tables() on the locks. I did not find a test case that failed without the change in sql_update.cc. I made the change anyway as it should in theory fix a possible MERGE table problem with multi-table update. --- mysql-test/r/create.result | 11 ----- mysql-test/r/merge.result | 49 +++++++++++++++++++++ mysql-test/t/create.test | 7 --- mysql-test/t/merge.test | 26 +++++++++++ sql/lock.cc | 89 ++++++++++++++++++++++++++++++++++++-- sql/mysql_priv.h | 1 + sql/sql_parse.cc | 11 ++--- sql/sql_update.cc | 2 +- 8 files changed, 169 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index c99ad8960dc..b362cdf7f58 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -189,17 +189,6 @@ select * from t1; 0 1 2 0 0 1 drop table t1; -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; -create table if not exists t1 select 1,2,3,4; -Column count doesn't match value count at row 1 -create table if not exists t1 select 1; -select * from t1; -1 2 3 -1 2 3 -0 1 2 -0 0 1 -drop table t1; create table t1 (a int not null, b int, primary key (a)); insert into t1 values (1,1); create table if not exists t1 select 2; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index ffb715e3903..c6e9ec0d46f 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -645,3 +645,52 @@ select min(a), max(a) from t1; min(a) max(a) 9999999999.9990 9999999999.9990 drop table t1, t2, t3; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +a +1 +2 +insert t2 select * from t2; +select * from t2; +a +2 +2 +insert t3 select * from t1; +select * from t3; +a +1 +1 +2 +2 +insert t1 select * from t3; +select * from t1; +a +1 +1 +1 +1 +2 +2 +select * from t2; +a +2 +2 +select * from t3; +a +1 +1 +1 +1 +2 +2 +2 +2 +check table t1, t2; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +drop table t1, t2, t3; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index ed2c76932da..644f4af15eb 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -151,13 +151,6 @@ drop table t1; # bug #1434 # -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; ---error 1136 -create table if not exists t1 select 1,2,3,4; -create table if not exists t1 select 1; -select * from t1; -drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; --error 1136 diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a3e3d487c67..ef12227d8f1 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -297,3 +297,29 @@ select min(a), max(a) from t1; flush tables; select min(a), max(a) from t1; drop table t1, t2, t3; + +# +# BUG#5390 - problems with merge tables +# Problem #1: INSERT...SELECT +# +#drop table if exists t1, t2, t3; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +# +insert t2 select * from t2; +select * from t2; +# +insert t3 select * from t1; +select * from t3; +# +insert t1 select * from t3; +select * from t1; +select * from t2; +select * from t3; +check table t1, t2; +drop table t1, t2, t3; + diff --git a/sql/lock.cc b/sql/lock.cc index 47ccc44952d..8944f23977f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -390,6 +390,88 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) } +/* + Find duplicate lock in tables. + + SYNOPSIS + mysql_lock_have_duplicate() + thd The current thread. + table The table to check for duplicate lock. + tables The list of tables to search for the dup lock. + + NOTE + This is mainly meant for MERGE tables in INSERT ... SELECT + situations. The 'real', underlying tables can be found only after + the table is opened. The easier way is to check this after the + tables are locked. + + RETURN + 1 A table from 'tables' matches a lock on 'table'. + 0 No duplicate lock is present. + -1 Error. +*/ + +int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables) +{ + uint count; + MYSQL_LOCK *sql_lock1; + MYSQL_LOCK *sql_lock2; + TABLE **tables1= &table; + TABLE **tables2; + TABLE **table_ptr; + TABLE_LIST *tablist2; + TABLE *write_lock_used; + THR_LOCK_DATA **lock_data1; + THR_LOCK_DATA **end_data1; + THR_LOCK_DATA **lock_data2; + THR_LOCK_DATA **end_data2; + THR_LOCK *lock1; + DBUG_ENTER("mysql_lock_have_duplicate"); + + if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used))) + goto err0; + + count=0; + for (tablist2 = tables; tablist2; tablist2= tablist2->next) + count++; + if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count))) + goto err1; + table_ptr= tables2; + for (tablist2 = tables; tablist2; tablist2= tablist2->next) + *(table_ptr++)= tablist2->table; + if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used))) + goto err1; + + count= 1; + for (lock_data1= sql_lock1->locks, + end_data1= lock_data1 + sql_lock1->lock_count; + lock_data1 < end_data1; + lock_data1++) + { + lock1= (*lock_data1)->lock; + for (lock_data2= sql_lock2->locks, + end_data2= lock_data2 + sql_lock2->lock_count; + lock_data2 < end_data2; + lock_data2++) + { + if ((*lock_data2)->lock == lock1) + goto end; + } + } + count= 0; + + end: + my_free((gptr) sql_lock2, MYF(0)); + my_free((gptr) sql_lock1, MYF(0)); + DBUG_RETURN(count); + + err1: + my_free((gptr) sql_lock1, MYF(0)); + err0: + DBUG_RETURN(-1); +} + + /* unlock a set of external */ static int unlock_external(THD *thd, TABLE **table,uint count) @@ -426,6 +508,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, MYSQL_LOCK *sql_lock; THR_LOCK_DATA **locks; TABLE **to; + DBUG_ENTER("get_lock_data"); *write_lock_used=0; for (i=tables=lock_count=0 ; i < count ; i++) @@ -441,7 +524,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, my_malloc(sizeof(*sql_lock)+ sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count, MYF(0)))) - return 0; + DBUG_RETURN(0); locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); to=sql_lock->table=(TABLE**) (locks+tables); sql_lock->table_count=lock_count; @@ -461,13 +544,13 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name); my_free((gptr) sql_lock,MYF(0)); - return 0; + DBUG_RETURN(0); } } locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE : lock_type); } - return sql_lock; + DBUG_RETURN(sql_lock); } /***************************************************************************** diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 62e65ea95da..3972a01f7ba 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -788,6 +788,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); +int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables); bool lock_global_read_lock(THD *thd); void unlock_global_read_lock(THD *thd); bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index aac442d35a2..f49e257a85a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2078,11 +2078,6 @@ mysql_execute_command(void) if (thd->select_limit < select_lex->select_limit) thd->select_limit= HA_POS_ERROR; // No limit - if (check_dup(tables->db, tables->real_name, tables->next)) - { - /* Using same table for INSERT and SELECT */ - select_lex->options |= OPTION_BUFFER_RESULT; - } { /* TODO: Delete the following loop when locks is set by sql_yacc */ TABLE_LIST *table; @@ -2095,6 +2090,12 @@ mysql_execute_command(void) (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next); if (!(res=open_and_lock_tables(thd, tables))) { + /* MERGE sub-tables can only be detected after open. */ + if (mysql_lock_have_duplicate(thd, tables->table, tables->next)) + { + /* Using same table for INSERT and SELECT */ + select_lex->options |= OPTION_BUFFER_RESULT; + } if ((result=new select_insert(tables->table,&lex->field_list, lex->duplicates))) res=handle_select(thd,lex,result); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b2b10a9b59a..888b475ffce 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -712,7 +712,7 @@ int multi_update::prepare(List ¬_used_values) { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && - check_dup(table_ref->db, table_ref->real_name, update_tables)) + mysql_lock_have_duplicate(thd, table, update_tables)) table->no_cache= 1; // Disable row cache } DBUG_RETURN(thd->fatal_error != 0); From d28ad864bd6ec9d1586163ca1aeebe8119c8680e Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 30 Nov 2005 14:18:43 +0100 Subject: [PATCH 015/154] DblqhMain.cpp: Use DBblock_REF instead of calcBLOCKBlockRef(getOwnNodeId()) as they are the same and the former is more efficient. Makes it easier to grep for senders of signals to specific blocks --- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 30 +++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index b6178227d31..1a02b5feb26 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -18444,60 +18444,54 @@ void Dblqh::execCREATE_TRIG_REQ(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference tupref = calcTupBlockRef(myNodeId); - sendSignal(tupref, GSN_CREATE_TRIG_REQ, signal, CreateTrigReq::SignalLength, JBB); + sendSignal(DBTUP_REF, GSN_CREATE_TRIG_REQ, signal, + CreateTrigReq::SignalLength, JBB); } void Dblqh::execCREATE_TRIG_CONF(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference dictref = calcDictBlockRef(myNodeId); - sendSignal(dictref, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB); + sendSignal(DBDICT_REF, GSN_CREATE_TRIG_CONF, signal, + CreateTrigConf::SignalLength, JBB); } void Dblqh::execCREATE_TRIG_REF(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference dictref = calcDictBlockRef(myNodeId); - sendSignal(dictref, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB); + sendSignal(DBDICT_REF, GSN_CREATE_TRIG_REF, signal, + CreateTrigRef::SignalLength, JBB); } void Dblqh::execDROP_TRIG_REQ(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference tupref = calcTupBlockRef(myNodeId); - sendSignal(tupref, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); + sendSignal(DBTUP_REF, GSN_DROP_TRIG_REQ, signal, + DropTrigReq::SignalLength, JBB); } void Dblqh::execDROP_TRIG_CONF(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference dictref = calcDictBlockRef(myNodeId); - sendSignal(dictref, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB); + sendSignal(DBDICT_REF, GSN_DROP_TRIG_CONF, signal, + DropTrigConf::SignalLength, JBB); } void Dblqh::execDROP_TRIG_REF(Signal* signal) { jamEntry(); - NodeId myNodeId = getOwnNodeId(); - BlockReference dictref = calcDictBlockRef(myNodeId); - sendSignal(dictref, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB); + sendSignal(DBDICT_REF, GSN_DROP_TRIG_REF, signal, + DropTrigRef::SignalLength, JBB); } Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){ From 0046710609c414e4a944206c5f868f40fafb54b4 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Thu, 1 Dec 2005 14:55:25 +0100 Subject: [PATCH 016/154] Backup.cpp: convert comment to english --- ndb/src/kernel/blocks/backup/Backup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 56af24c5cf0..b26ff63028b 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -3769,7 +3769,7 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr) req->userReference = reference(); req->varIndex = 0; req->offset = tmp - c_startOfPages; - req->size = sz; // Avrunda uppot + req->size = sz; // Round up sendSignal(NDBFS_REF, GSN_FSAPPENDREQ, signal, FsAppendReq::SignalLength, JBA); From 88eee63d8c02e5a4b3ac39c0ed31794dcf243a29 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Sat, 3 Dec 2005 18:13:06 +0200 Subject: [PATCH 017/154] Set thread_stack after return from end_thread() Fixes core dump when reusing thread when running debug binary --- sql-bench/bench-init.pl.sh | 2 +- sql-bench/server-cfg.sh | 10 +++++----- sql/mysqld.cc | 1 + sql/sql_parse.cc | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh index d61551ffb3b..31282d06abf 100644 --- a/sql-bench/bench-init.pl.sh +++ b/sql-bench/bench-init.pl.sh @@ -447,7 +447,7 @@ All benchmarks takes the following options: --create-options=# Extra argument to all create statements. If you for example want to create all MySQL tables as BDB tables use: - --create-options=TYPE=BDB + --create-options=ENGINE=BDB --database (Default $opt_database) In which database the test tables are created. diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh index b0c40102a6b..75528b24b77 100644 --- a/sql-bench/server-cfg.sh +++ b/sql-bench/server-cfg.sh @@ -174,29 +174,29 @@ sub new # Some fixes that depends on the environment if (defined($main::opt_create_options) && - $main::opt_create_options =~ /type=heap/i) + $main::opt_create_options =~ /engine=heap/i) { $limits{'working_blobs'} = 0; # HEAP tables can't handle BLOB's } if (defined($main::opt_create_options) && - $main::opt_create_options =~ /type=innodb/i) + $main::opt_create_options =~ /engine=innodb/i) { $self->{'transactions'} = 1; # Transactions enabled } if (defined($main::opt_create_options) && - $main::opt_create_options =~ /type=ndb/i) + $main::opt_create_options =~ /engine=ndb/i) { $self->{'transactions'} = 1; # Transactions enabled $limits{'max_columns'} = 90; # Max number of columns in table $limits{'max_tables'} = 32; # No comments } if (defined($main::opt_create_options) && - $main::opt_create_options =~ /type=bdb/i) + $main::opt_create_options =~ /engine=bdb/i) { $self->{'transactions'} = 1; # Transactions enabled } if (defined($main::opt_create_options) && - $main::opt_create_options =~ /type=gemini/i) + $main::opt_create_options =~ /engine=gemini/i) { $limits{'working_blobs'} = 0; # Blobs not implemented yet $limits{'max_tables'} = 500; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b5b95e48889..857658207ba 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1589,6 +1589,7 @@ void end_thread(THD *thd, bool put_in_cache) wake_thread--; thd=thread_cache.get(); thd->real_id=pthread_self(); + thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); thd->thr_create_time= time(NULL); threads.append(thd); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 00124225719..1a9b4ef4db7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1182,6 +1182,7 @@ end_thread: or this thread has been schedule to handle the next query */ thd= current_thd; + thd->thread_stack= (char*) &thd; } while (!(test_flags & TEST_NO_THREADS)); /* The following is only executed if we are not using --one-thread */ return(0); /* purecov: deadcode */ From 600a74b0d404e98103c4ddf5a9019e04512f0dcc Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 6 Dec 2005 21:28:13 +0100 Subject: [PATCH 018/154] WL#2930 - Updated after review --- client/mysqltest.c | 138 +++++++++++++++++--------- mysql-test/include/have_multi_ndb.inc | 8 +- mysql-test/r/init_file.result | 1 + mysql-test/r/mysql_client_test.result | 1 + mysql-test/r/mysqltest.result | 4 + mysql-test/t/init_file.test | 1 + mysql-test/t/mysql_client_test.test | 2 + mysql-test/t/mysqltest.test | 54 +++++++--- 8 files changed, 146 insertions(+), 63 deletions(-) create mode 100644 mysql-test/r/init_file.result create mode 100644 mysql-test/r/mysql_client_test.result diff --git a/client/mysqltest.c b/client/mysqltest.c index 224985227cd..91791145db5 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -628,6 +628,10 @@ static void die(const char *fmt, ...) va_end(args); free_used_memory(); my_end(MY_CHECK_ERROR); + + if (!silent) + printf("not ok\n"); + exit(1); } @@ -3050,11 +3054,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, for (col_idx= 0; col_idx < num_fields; col_idx++) { /* Allocate data for output */ - /* - FIXME it may be a bug that for non string/blob types - 'max_length' is 0, should try out 'length' in that case - */ - uint max_length= max(field[col_idx].max_length + 1, 1024); + uint max_length= field[col_idx].max_length + 1; char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); bind[col_idx].buffer_type= MYSQL_TYPE_STRING; @@ -3062,6 +3062,11 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, bind[col_idx].buffer_length= max_length; bind[col_idx].is_null= &is_null[col_idx]; bind[col_idx].length= &length[col_idx]; + + DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %d", + col_idx, + bind[col_idx].buffer_type, + bind[col_idx].buffer_length)); } /* Fill in the data into the structures created above */ @@ -3197,11 +3202,11 @@ static void append_metadata(DYNAMIC_STRING *ds, Append affected row count and other info to output */ -static void append_info(DYNAMIC_STRING *ds, ulong affected_rows, +static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, const char *info) { char buf[40]; - sprintf(buf,"affected rows: %lu\n", affected_rows); + sprintf(buf,"affected rows: %llu\n", affected_rows); dynstr_append(ds, buf); if (info) { @@ -3231,17 +3236,20 @@ static void append_table_headings(DYNAMIC_STRING *ds, } /* - Fetch warnings from server and append to output + Fetch warnings from server and append to ds + + RETURN VALUE + Number of warnings appended to ds */ -static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) +static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; MYSQL_RES *warn_res; DBUG_ENTER("append_warnings"); if (!(count= mysql_warning_count(mysql))) - DBUG_VOID_RETURN; + DBUG_RETURN(0); /* If one day we will support execution of multi-statements @@ -3257,14 +3265,14 @@ static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) die("Warning count is %u but didn't get any warnings", count); - dynstr_append_mem(ds, "Warnings:\n", 10); append_result(ds, warn_res); mysql_free_result(warn_res); - DBUG_VOID_RETURN; + DBUG_RETURN(count); } + /* Run query using MySQL C API @@ -3287,6 +3295,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, { MYSQL_RES *res= 0; int err= 0, counter= 0; + DYNAMIC_STRING ds_warnings; DBUG_ENTER("run_query_normal"); DBUG_PRINT("enter",("flags: %d", flags)); DBUG_PRINT("enter", ("query: '%-.60s'", query)); @@ -3334,7 +3343,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, if (!disable_result_log) { - ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */ LINT_INIT(affected_rows); if (res) @@ -3356,7 +3365,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, query to find the warnings */ if (!disable_info) - affected_rows= (ulong)mysql_affected_rows(mysql); + affected_rows= mysql_affected_rows(mysql); /* Add all warnings to the result. We can't do this if we are in @@ -3364,7 +3373,15 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, this will break protocol. */ if (!disable_warnings && !mysql_more_results(mysql)) - append_warnings(ds, mysql); + { + init_dynamic_string(&ds_warnings, NULL, 0, 256); + if (append_warnings(&ds_warnings, mysql)) + { + dynstr_append_mem(ds, "Warnings:\n", 10); + dynstr_append_mem(ds, ds_warnings.str, ds_warnings.length); + } + dynstr_free(&ds_warnings); + } if (!disable_info) append_info(ds, affected_rows, mysql_info(mysql)); @@ -3542,6 +3559,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ MYSQL_STMT *stmt; DYNAMIC_STRING ds_prepare_warnings; + DYNAMIC_STRING ds_execute_warnings; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); @@ -3562,6 +3580,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { handle_error(query, command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); +#ifndef BUG15518_FIXED + mysql_stmt_close(stmt); + cur_con->stmt= NULL; +#endif goto end; } @@ -3569,10 +3591,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, Get the warnings from mysql_stmt_prepare and keep them in a separate string */ - if (!disable_warnings) { - init_dynamic_string(&ds_prepare_warnings, "", 1024, 1024); + init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256); + init_dynamic_string(&ds_execute_warnings, NULL, 0, 256); append_warnings(&ds_prepare_warnings, mysql); } @@ -3588,7 +3610,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, */ if (cursor_protocol_enabled) { - unsigned long type= CURSOR_TYPE_READ_ONLY; + ulong type= CURSOR_TYPE_READ_ONLY; if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); @@ -3654,25 +3676,36 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, mysql_free_result(res); /* Free normal result set with meta data */ + /* Clear prepare warnings */ + dynstr_set(&ds_prepare_warnings, NULL); } else { /* This is a query without resultset */ - - /* - Add warnings from prepare to output - */ - if (!disable_warnings) - dynstr_append(ds, ds_prepare_warnings.str); } if (!disable_warnings) - append_warnings(ds, mysql); + { + /* Get the warnings from execute */ + + /* Append warnings to ds - if there are any */ + if (append_warnings(&ds_execute_warnings, mysql) || + ds_prepare_warnings.length) + { + dynstr_append_mem(ds, "Warnings:\n", 10); + if (ds_prepare_warnings.length) + dynstr_append_mem(ds, ds_prepare_warnings.str, + ds_prepare_warnings.length); + if (ds_execute_warnings.length) + dynstr_append_mem(ds, ds_execute_warnings.str, + ds_execute_warnings.length); + } + } if (!disable_info) - append_info(ds, (ulong)mysql_affected_rows(mysql), mysql_info(mysql)); + append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql)); } @@ -3680,7 +3713,10 @@ end: free_replace(); if (!disable_warnings) + { dynstr_free(&ds_prepare_warnings); + dynstr_free(&ds_execute_warnings); + } /* We save the return code (mysql_stmt_errno(stmt)) from the last call sent @@ -3778,6 +3814,10 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) DBUG_PRINT("view_create_error", ("Failed to create view '%s': %d: %s", query_str.str, mysql_errno(mysql), mysql_error(mysql))); + + /* Log error to create view */ + verbose_msg("Failed to create view '%s' %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql)); } else { @@ -3817,6 +3857,11 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) DBUG_PRINT("sp_create_error", ("Failed to create sp '%s': %d: %s", query_str.str, mysql_errno(mysql), mysql_error(mysql))); + + /* Log error to create sp */ + verbose_msg("Failed to create sp '%s' %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql)); + } else { @@ -4446,24 +4491,10 @@ int main(int argc, char **argv) } /* - The whole test has been executed sucessfully + The whole test has been executed _sucessfully_ Time to compare result or save it to record file The entire output from test is now kept in ds_res - */ - - if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) - { - /* - my_stat() successful on result file. Check if we have not run a - single query, but we do have a result file that contains data. - Note that we don't care, if my_stat() fails. For example for - non-existing or non-readable file we assume it's fine to have - no query output from the test file, e.g. regarded as no error. - */ - if (res_info.st_size) - die("No queries executed but result file found!"); - } - + */ if (ds_res.length) { if (result_file) @@ -4475,20 +4506,37 @@ int main(int argc, char **argv) } else { - /* Check that the output from test is equal to result file */ + /* Check that the output from test is equal to result file + - detect missing result file + - detect zero size result file + */ check_result(&ds_res, result_file, 0); } } else { - /* No result_file to compare with, print the result to stdout */ + /* No result_file specified to compare with, print to stdout */ printf("%s", ds_res.str); } } else { - /* The test didn't produce any output */ + die("The test didn't produce any output"); } + + if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) + { + /* + my_stat() successful on result file. Check if we have not run a + single query, but we do have a result file that contains data. + Note that we don't care, if my_stat() fails. For example for + non-existing or non-readable file we assume it's fine to have + no query output from the test file, e.g. regarded as no error. + */ + die("No queries executed but result file found!"); + } + + dynstr_free(&ds_res); if (!got_end_timer) diff --git a/mysql-test/include/have_multi_ndb.inc b/mysql-test/include/have_multi_ndb.inc index ec1a93311fb..45a551274f7 100644 --- a/mysql-test/include/have_multi_ndb.inc +++ b/mysql-test/include/have_multi_ndb.inc @@ -9,8 +9,8 @@ disable_query_log; drop table if exists t1, t2; --enable_warnings flush tables; -@r/have_ndb.require show variables like "have_ndbcluster"; -# @r/server_id.require show variables like "server_id"; +--require r/have_ndb.require +show variables like "have_ndbcluster"; enable_query_log; # Check that server2 has NDB support @@ -20,8 +20,8 @@ disable_query_log; drop table if exists t1, t2; --enable_warnings flush tables; -@r/have_ndb.require show variables like "have_ndbcluster"; -# @r/server_id1.require show variables like "server_id"; +--require r/have_ndb.require +show variables like "have_ndbcluster"; enable_query_log; # Set the default connection to 'server1' diff --git a/mysql-test/r/init_file.result b/mysql-test/r/init_file.result new file mode 100644 index 00000000000..9766475a418 --- /dev/null +++ b/mysql-test/r/init_file.result @@ -0,0 +1 @@ +ok diff --git a/mysql-test/r/mysql_client_test.result b/mysql-test/r/mysql_client_test.result new file mode 100644 index 00000000000..9766475a418 --- /dev/null +++ b/mysql-test/r/mysql_client_test.result @@ -0,0 +1 @@ +ok diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index df4c2091f3b..22c7fb02f00 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -331,6 +331,7 @@ mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_re mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a;' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a ' +OK mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c ' select "a" as col1, "c" as col2; @@ -356,6 +357,7 @@ mysqltest: At line 1: Missing connection db mysqltest: At line 1: Could not open connection 'con2': Unknown database 'illegal_db' mysqltest: At line 1: Illegal argument for port: 'illegal_port' mysqltest: At line 1: Illegal option to connect: SMTP +OK mysqltest: In included file "./var/tmp/con.sql": At line 7: Connection limit exhausted - increase MAX_CONS in mysqltest.c mysqltest: In included file "./var/tmp/con.sql": At line 3: connection 'test_con1' not found in connection pool mysqltest: In included file "./var/tmp/con.sql": At line 2: Connection test_con1 already exists @@ -394,3 +396,5 @@ root@localhost -------------------------------------------------------------------------------- this will be executed this will be executed +mysqltest: Result length mismatch +mysqltest: The test didn't produce any output diff --git a/mysql-test/t/init_file.test b/mysql-test/t/init_file.test index de6aca455bd..8b4b788777b 100644 --- a/mysql-test/t/init_file.test +++ b/mysql-test/t/init_file.test @@ -7,3 +7,4 @@ # # End of 4.1 tests +echo ok; diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 66b57dd5fb7..9cacb008d09 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -10,3 +10,5 @@ --exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M # End of 4.1 tests +echo ok; + diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 26e25af2a8d..f229b5cdc1d 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -368,10 +368,10 @@ select 3 from t1 ; # Missing delimiter until eof # The comment will be "sucked into" the sleep command since # delimiter is missing ---system echo "sleep 7" > var/log/mysqltest.sql ---system echo "# Another comment" >> var/log/mysqltest.sql +--system echo "sleep 7" > var/tmp/mysqltest.sql +--system echo "# Another comment" >> var/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < var/tmp/mysqltest.sql 2>&1 # # Extra delimiter @@ -737,20 +737,20 @@ while ($i) --error 1 --exec echo "{;" | $MYSQL_TEST 2>&1 ---system echo "while (0)" > var/log/mysqltest.sql ---system echo "echo hej;" >> var/log/mysqltest.sql +--system echo "while (0)" > var/tmp/mysqltest.sql +--system echo "echo hej;" >> var/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < var/tmp/mysqltest.sql 2>&1 ---system echo "while (0)" > var/log/mysqltest.sql ---system echo "{echo hej;" >> var/log/mysqltest.sql +--system echo "while (0)" > var/tmp/mysqltest.sql +--system echo "{echo hej;" >> var/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < var/tmp/mysqltest.sql 2>&1 ---system echo "while (0){" > var/log/mysqltest.sql ---system echo "echo hej;" >> var/log/mysqltest.sql +--system echo "while (0){" > var/tmp/mysqltest.sql +--system echo "echo hej;" >> var/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < var/tmp/mysqltest.sql 2>&1 # ---------------------------------------------------------------------------- # Test error messages returned from comments starting with a command @@ -778,7 +778,7 @@ select "a" as col1, "c" as col2; --exec echo "replace_result a;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "replace_result a ;" | $MYSQL_TEST 2>&1 ---exec echo "replace_result a b;" | $MYSQL_TEST 2>&1 +--exec echo "replace_result a b; echo OK;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "--replace_result a b c" | $MYSQL_TEST 2>&1 --error 1 @@ -848,7 +848,7 @@ select "a" as col1, "c" as col2; --exec echo " disconnect test_con1; " >> var/tmp/con.sql --exec echo " dec \$i; " >> var/tmp/con.sql --exec echo "}" >> var/tmp/con.sql ---exec echo "source var/tmp/con.sql;" | $MYSQL_TEST 2>&1 +--exec echo "source var/tmp/con.sql; echo OK;" | $MYSQL_TEST 2>&1 # Repeat connect/disconnect, exceed max number of connections --exec echo "let \$i=200;" > var/tmp/con.sql @@ -954,3 +954,29 @@ select "this will not be executed"; --enable_parsing select "this will be executed"; --enable_query_log + +# +# Test zero length result file. Should not pass +# +--exec touch $MYSQL_TEST_DIR/var/tmp/zero_length_file.result +--exec echo "echo ok;" > $MYSQL_TEST_DIR/var/tmp/query.sql +--error 1 +--exec $MYSQL_TEST -x var/tmp/query.sql -R var/tmp/zero_length_file.result 2>&1 +# +# Test that a test file that does not generate any output fails. +# +--exec echo "let \$i= 1;" > $MYSQL_TEST_DIR/var/tmp/query.sql +--error 1 +--exec $MYSQL_TEST -x var/tmp/query.sql 2>&1 + +# +# Test that mysqltest fails when there are no queries executed +# but a result file exist +# NOTE! This will never happen as long as it's not allowed to have +# test files that does not produce any output +#--exec echo "something" > $MYSQL_TEST_DIR/var/tmp/result_file.result +#--exec echo "let \$i= 1;" > $MYSQL_TEST_DIR/var/tmp/query.sql +#--error 1 +#--exec $MYSQL_TEST -x var/tmp/query.sql -R var/tmp/result_file.result 2>&1 + + From 60806003fb154b2b217ed6316bc0bc7901afc462 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 6 Dec 2005 21:34:35 +0100 Subject: [PATCH 019/154] Improved valgrinding of mysqltest --- mysql-test/mysql-test-run.sh | 51 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 2133043a587..517ce0420e6 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -110,6 +110,20 @@ wait_for_pid() #$WAIT_PID pid $SLEEP_TIME_FOR_DELETE } +# Check that valgrind is installed +find_valgrind() +{ + FIND_VALGRIND=`which valgrind` # this will print an error if not found + # Give good warning to the user and stop + if [ -z "$FIND_VALGRIND" ] ; then + $ECHO "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://valgrind.kde.org ." + exit 1 + fi + # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr + valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && FIND_VALGRIND="$FIND_VALGRIND --tool=memcheck" + FIND_VALGRIND="$FIND_VALGRIND --alignment=8 --leak-check=yes --num-callers=16 --suppressions=$CWD/valgrind.supp" +} + # No paths below as we can't be sure where the program is! SED=sed @@ -255,7 +269,6 @@ DO_GDB="" MANUAL_GDB="" DO_DDD="" DO_CLIENT_GDB="" -DO_VALGRIND_MYSQL_TEST="" SLEEP_TIME_AFTER_RESTART=1 SLEEP_TIME_FOR_DELETE=10 SLEEP_TIME_FOR_FIRST_MASTER=400 # Enough time to create innodb tables @@ -470,15 +483,8 @@ while test $# -gt 0; do EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; --valgrind | --valgrind-all) - VALGRIND=`which valgrind` # this will print an error if not found - # Give good warning to the user and stop - if [ -z "$VALGRIND" ] ; then - $ECHO "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://valgrind.kde.org ." - exit 1 - fi - # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr - valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" - VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16 --suppressions=$CWD/valgrind.supp" + find_valgrind; + VALGRIND=$FIND_VALGRIND EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb" SLEEP_TIME_AFTER_RESTART=10 @@ -493,8 +499,13 @@ while test $# -gt 0; do TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` VALGRIND="$VALGRIND $TMP" ;; - --valgrind-mysqltest) - DO_VALGRIND_MYSQL_TEST=1 + --valgrind-mysqltest | --valgrind-mysqltest-all) + find_valgrind; + VALGRIND_MYSQLTEST=$FIND_VALGRIND + if test "$1" = "--valgrind-mysqltest-all" + then + VALGRIND_MYSQLTEST="$VALGRIND_MYSQLTEST -v --show-reachable=yes" + fi ;; --skip-ndbcluster | --skip-ndb) USE_NDBCLUSTER="" @@ -599,7 +610,7 @@ DASH72=`$ECHO '-------------------------------------------------------'|$CUT -c if [ x$SOURCE_DIST = x1 ] ; then if [ "x$USE_EMBEDDED_SERVER" = "x1" ] ; then if [ -f "$BASEDIR/libmysqld/examples/mysqltest_embedded" ] ; then - MYSQL_TEST="$VALGRIND $BASEDIR/libmysqld/examples/mysqltest_embedded" + MYSQL_TEST="$BASEDIR/libmysqld/examples/mysqltest_embedded" else echo "Fatal error: Cannot find embedded server 'mysqltest_embedded'" 1>&2 exit 1 @@ -733,7 +744,7 @@ else fi if [ "x$USE_EMBEDDED_SERVER" = "x1" ] ; then if [ -f "$CLIENT_BINDIR/mysqltest_embedded" ] ; then - MYSQL_TEST="$VALGRIND $CLIENT_BINDIR/mysqltest_embedded" + MYSQL_TEST="$CLIENT_BINDIR/mysqltest_embedded" else echo "Fatal error: Cannot find embedded server 'mysqltest_embedded'" 1>&2 exit 1 @@ -744,7 +755,7 @@ else MYSQL_CLIENT_TEST="$CLIENT_BINDIR/mysql_client_test_embedded" fi else - MYSQL_TEST="$VALGRIND_MYSQLTEST $CLIENT_BINDIR/mysqltest" + MYSQL_TEST="$CLIENT_BINDIR/mysqltest" MYSQL_CLIENT_TEST="$CLIENT_BINDIR/mysql_client_test" fi fi @@ -759,8 +770,9 @@ then SLAVE_MYSQLD=$MYSQLD fi -if [ x$DO_VALGRIND_MYSQL_TEST = x1 ] ; then - MYSQL_TEST="$VALGRIND $MYSQL_TEST" +# If mysqltest should be valgrinded, add valgrind and options to MYSQL_TEST +if ! [ -z "$VALGRIND_MYSQLTEST" ] ; then + MYSQL_TEST="$VALGRIND_MYSQLTEST $MYSQL_TEST" fi # If we should run all tests cases, we will use a local server for that @@ -829,6 +841,7 @@ GPROF_DIR=$MYSQL_TMP_DIR/gprof GPROF_MASTER=$GPROF_DIR/master.gprof GPROF_SLAVE=$GPROF_DIR/slave.gprof TIMEFILE="$MYSQL_TEST_DIR/var/log/mysqltest-time" +MYSQLTEST_LOG="$MYSQL_TEST_DIR/var/log/mysqltest.log" if [ -n "$DO_CLIENT_GDB" -o -n "$DO_GDB" ] ; then XTERM=`which xterm` fi @@ -1774,6 +1787,10 @@ run_testcase () res=$? + # Save the testcase log to mysqltest log file + echo "CURRENT_TEST: $tname" >> $MYSQLTEST_LOG + cat $TIMEFILE >> $MYSQLTEST_LOG + pname=`$ECHO "$tname "|$CUT -c 1-24` RES="$pname" From 1e630458f76f10bdbad0975b64a93b9119a5cd17 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 7 Dec 2005 11:11:59 +0100 Subject: [PATCH 020/154] New tool to collate all information to form a good error report for NDB. It will copy from each node the logs and trace dumps (if any) and create a tarball. Having this tarball attached to a bug report greatly helps troubleshooting and avoids user error. It will (optionally) also get the filesystem. --- ndb/tools/ndb_error_reporter | 88 ++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100755 ndb/tools/ndb_error_reporter diff --git a/ndb/tools/ndb_error_reporter b/ndb/tools/ndb_error_reporter new file mode 100755 index 00000000000..2b5aadb6171 --- /dev/null +++ b/ndb/tools/ndb_error_reporter @@ -0,0 +1,88 @@ +#!/usr/bin/perl -w + +use strict; + +if(@ARGV < 1) +{ + print STDERR "Usage:\n"; + print STDERR "\tndb_error_reporter config.ini [username] [--fs]\n\n"; + print STDERR "\tusername is a user that you can use to ssh into\n"; + print STDERR "\t all of your nodes with.\n\n"; + print STDERR "\t--fs means include the filesystems in the report\n"; + print STDERR "\t WARNING: This may require a lot of disk space.\n"; + print STDERR "\t Only use this option when asked to.\n\n"; + exit(1); +} + +my $config_file= $ARGV[0]; +my $config_get_fs= 0; +my $config_username= ''; +if(defined($ARGV[1])) +{ + $config_get_fs= 1 if $ARGV[1] eq '--fs'; + $config_username= $ARGV[1].'@' if $ARGV[1] ne '--fs'; + $config_get_fs= (defined $ARGV[2] && $ARGV[2] eq '--fs')?1:$config_get_fs; +} + +if(!stat($config_file)) +{ + print STDERR "Cannot open configuration file.\n\n"; + exit(1); +} + +my @nodes= split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndbd`; + +push @nodes, split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndb_mgmd`; + +sub config { + my $nodeid= shift; + my $query= shift; + my $res= `ndb_config --config-file=$ARGV[0] --id=$nodeid --query=$query`; + chomp $res; + $res; +} + +my @t= localtime(); +my $reportdir= sprintf('ndb_error_report_%u%02u%02u%02u%02u%02u', + ($t[5]+1900),($t[4]+1),$t[3],$t[2],$t[1],$t[0]); + +if(stat($reportdir) || stat($reportdir.'tar.bz2')) +{ + print STDERR "It looks like another ndb_error_report process is running.\n"; + print STDERR "If that is not the case, remove the ndb_error_report directory"; + print STDERR " and run ndb_error_report again.\n\n"; + exit(1); +} + +mkdir($reportdir); + +foreach my $node (@nodes) +{ + print "\n\n Copying data from node $node". + (($config_get_fs)?" with filesystem":""). + "\n\n"; + my $recurse= ($config_get_fs)?'-r ':''; + system 'scp '.$recurse.$config_username.config($node,'host'). + ':'.config($node,'datadir')."/ndb_".$node."* ". + "$reportdir/\n"; +} + +print "\n\n Copying configuration file...\n\n\t$config_file\n\n"; +system "cp $config_file $reportdir/"; + +my $r = system 'bzip2 2>&1 > /dev/null < /dev/null'; +my $outfile; +if($r==0) +{ + $outfile= "$reportdir.tar.bz2"; + system "tar c $reportdir|bzip2 > $outfile"; +} +else +{ + $outfile= "$reportdir.tar.gz"; + system "tar c $reportdir|gzip > $outfile"; +} + +system "rm -rf $reportdir"; + +print "\n\nPlease attach $outfile to your error report\n\n"; From d80516aa96d2249134f0d78fce45e08abfb70048 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 7 Dec 2005 14:52:37 +0100 Subject: [PATCH 021/154] Fix memory leak --- client/mysqltest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/mysqltest.c b/client/mysqltest.c index 91791145db5..285aa0fe033 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4015,6 +4015,7 @@ static void free_re(void) my_regfree(&ps_re); my_regfree(&sp_re); my_regfree(&view_re); + my_regex_end(); } /****************************************************************************/ From 58d0d5387ec777e7bb2e7ec8dac93e98ab3f496c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 7 Dec 2005 14:54:06 +0100 Subject: [PATCH 022/154] valgrind for mysqltest --- mysql-test/mysql-test-run.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 517ce0420e6..3a8aa8614a2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -770,11 +770,6 @@ then SLAVE_MYSQLD=$MYSQLD fi -# If mysqltest should be valgrinded, add valgrind and options to MYSQL_TEST -if ! [ -z "$VALGRIND_MYSQLTEST" ] ; then - MYSQL_TEST="$VALGRIND_MYSQLTEST $MYSQL_TEST" -fi - # If we should run all tests cases, we will use a local server for that if [ -z "$1" -a -z "$DO_STRESS" ] @@ -831,7 +826,10 @@ if [ x$USE_TIMER = x1 ] ; then fi MYSQL_TEST_BIN=$MYSQL_TEST MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS" + +# Export MYSQL_TEST variable for use from .test files export MYSQL_TEST + GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave @@ -1780,7 +1778,7 @@ run_testcase () $RM -f r/$tname.*reject mysql_test_args="-R $result_file $EXTRA_MYSQL_TEST_OPT" if [ -z "$DO_CLIENT_GDB" ] ; then - `$MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`; + `$VALGRIND_MYSQLTEST $MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`; else do_gdb_test "$mysql_test_args" "$tf" fi From 5aa315e23a86dc5d376df09a11654799a7a80843 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Wed, 7 Dec 2005 19:52:26 +0100 Subject: [PATCH 023/154] BUG#5390 - problems with merge tables Problem #1: INSERT...SELECT, Version for 4.1. INSERT ... SELECT with the same table on both sides (hidden below a MERGE table) does now work by buffering the select result. The duplicate detection works now after open_and_lock_tables() on the locks. I did not find a test case that failed without the change in sql_update.cc. I made the change anyway as it should in theory fix a possible MERGE table problem with multi-table update. --- mysql-test/r/create.result | 15 ------- mysql-test/r/merge.result | 49 +++++++++++++++++++++ mysql-test/t/create.test | 7 --- mysql-test/t/merge.test | 26 +++++++++++ sql/lock.cc | 89 ++++++++++++++++++++++++++++++++++++-- sql/mysql_priv.h | 1 + sql/sql_parse.cc | 11 ++--- sql/sql_update.cc | 3 +- 8 files changed, 169 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index a933027cdb1..d096de4ff6a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -247,21 +247,6 @@ select * from t1; 0 1 2 0 0 1 drop table t1; -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; -Warnings: -Note 1050 Table 't1' already exists -create table if not exists t1 select 1,2,3,4; -ERROR 21S01: Column count doesn't match value count at row 1 -create table if not exists t1 select 1; -Warnings: -Note 1050 Table 't1' already exists -select * from t1; -1 2 3 -1 2 3 -0 1 2 -0 0 1 -drop table t1; create table t1 (a int not null, b int, primary key (a)); insert into t1 values (1,1); create table if not exists t1 select 2; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 3035908688a..038ea43cabc 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -717,3 +717,52 @@ SELECT b FROM t2; b 3 DROP TABLE t1, t2; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +a +1 +2 +insert t2 select * from t2; +select * from t2; +a +2 +2 +insert t3 select * from t1; +select * from t3; +a +1 +1 +2 +2 +insert t1 select * from t3; +select * from t1; +a +1 +1 +1 +1 +2 +2 +select * from t2; +a +2 +2 +select * from t3; +a +1 +1 +1 +1 +2 +2 +2 +2 +check table t1, t2; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +drop table t1, t2, t3; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index c9d16916f8a..f8570b4d373 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -200,13 +200,6 @@ drop table t1; # bug #1434 # -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; ---error 1136 -create table if not exists t1 select 1,2,3,4; -create table if not exists t1 select 1; -select * from t1; -drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; --error 1136 diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index d384c017611..a723443b395 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -350,4 +350,30 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3; SELECT b FROM t2; DROP TABLE t1, t2; + +# +# BUG#5390 - problems with merge tables +# Problem #1: INSERT...SELECT +# +#drop table if exists t1, t2, t3; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +# +insert t2 select * from t2; +select * from t2; +# +insert t3 select * from t1; +select * from t3; +# +insert t1 select * from t3; +select * from t1; +select * from t2; +select * from t3; +check table t1, t2; +drop table t1, t2, t3; + # End of 4.1 tests diff --git a/sql/lock.cc b/sql/lock.cc index 944c36d4d1e..a571b7f8ee8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -394,6 +394,88 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) } +/* + Find duplicate lock in tables. + + SYNOPSIS + mysql_lock_have_duplicate() + thd The current thread. + table The table to check for duplicate lock. + tables The list of tables to search for the dup lock. + + NOTE + This is mainly meant for MERGE tables in INSERT ... SELECT + situations. The 'real', underlying tables can be found only after + the table is opened. The easier way is to check this after the + tables are locked. + + RETURN + 1 A table from 'tables' matches a lock on 'table'. + 0 No duplicate lock is present. + -1 Error. +*/ + +int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables) +{ + uint count; + MYSQL_LOCK *sql_lock1; + MYSQL_LOCK *sql_lock2; + TABLE **tables1= &table; + TABLE **tables2; + TABLE **table_ptr; + TABLE_LIST *tablist2; + TABLE *write_lock_used; + THR_LOCK_DATA **lock_data1; + THR_LOCK_DATA **end_data1; + THR_LOCK_DATA **lock_data2; + THR_LOCK_DATA **end_data2; + THR_LOCK *lock1; + DBUG_ENTER("mysql_lock_have_duplicate"); + + if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used))) + goto err0; + + count=0; + for (tablist2 = tables; tablist2; tablist2= tablist2->next) + count++; + if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count))) + goto err1; + table_ptr= tables2; + for (tablist2 = tables; tablist2; tablist2= tablist2->next) + *(table_ptr++)= tablist2->table; + if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used))) + goto err1; + + count= 1; + for (lock_data1= sql_lock1->locks, + end_data1= lock_data1 + sql_lock1->lock_count; + lock_data1 < end_data1; + lock_data1++) + { + lock1= (*lock_data1)->lock; + for (lock_data2= sql_lock2->locks, + end_data2= lock_data2 + sql_lock2->lock_count; + lock_data2 < end_data2; + lock_data2++) + { + if ((*lock_data2)->lock == lock1) + goto end; + } + } + count= 0; + + end: + my_free((gptr) sql_lock2, MYF(0)); + my_free((gptr) sql_lock1, MYF(0)); + DBUG_RETURN(count); + + err1: + my_free((gptr) sql_lock1, MYF(0)); + err0: + DBUG_RETURN(-1); +} + + /* unlock a set of external */ static int unlock_external(THD *thd, TABLE **table,uint count) @@ -430,6 +512,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, MYSQL_LOCK *sql_lock; THR_LOCK_DATA **locks; TABLE **to; + DBUG_ENTER("get_lock_data"); *write_lock_used=0; for (i=tables=lock_count=0 ; i < count ; i++) @@ -445,7 +528,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, my_malloc(sizeof(*sql_lock)+ sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count, MYF(0)))) - return 0; + DBUG_RETURN(0); locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); to=sql_lock->table=(TABLE**) (locks+tables); sql_lock->table_count=lock_count; @@ -465,7 +548,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name); my_free((gptr) sql_lock,MYF(0)); - return 0; + DBUG_RETURN(0); } } THR_LOCK_DATA **org_locks = locks; @@ -475,7 +558,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, for ( ; org_locks != locks ; org_locks++) (*org_locks)->debug_print_param= (void *) table; } - return sql_lock; + DBUG_RETURN(sql_lock); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c128fac8d9e..429a71b4437 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1022,6 +1022,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); +int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables); bool lock_global_read_lock(THD *thd); void unlock_global_read_lock(THD *thd); bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fbca542dc24..90de630da60 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2897,16 +2897,17 @@ unsent_create_error: if (unit->select_limit_cnt < select_lex->select_limit) unit->select_limit_cnt= HA_POS_ERROR; // No limit - if (find_real_table_in_list(tables->next, tables->db, tables->real_name)) + if ((res= open_and_lock_tables(thd, tables))) + break; + + insert_table= tables->table; + /* MERGE sub-tables can only be detected after open. */ + if (mysql_lock_have_duplicate(thd, insert_table, tables->next)) { /* Using same table for INSERT and SELECT */ select_lex->options |= OPTION_BUFFER_RESULT; } - if ((res= open_and_lock_tables(thd, tables))) - break; - - insert_table= tables->table; /* Skip first table, which is the table we are inserting in */ select_lex->table_list.first= (byte*) first_local_table->next; tables= (TABLE_LIST *) select_lex->table_list.first; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 05e13c64aa7..d69a6b7cdd1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -854,8 +854,7 @@ int multi_update::prepare(List ¬_used_values, { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && - find_real_table_in_list(update_tables, table_ref->db, - table_ref->real_name)) + mysql_lock_have_duplicate(thd, table, update_tables)) table->no_cache= 1; // Disable row cache } DBUG_RETURN(thd->is_fatal_error != 0); From fe2ec19039ddc7e35824967e28feb0e3a648f294 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 8 Dec 2005 16:48:37 +0100 Subject: [PATCH 024/154] WL#2930 mysqltest++ - Updated after valgrinding --- client/mysqltest.c | 22 +++++++++++++--------- mysql-test/mysql-test-run.sh | 12 ++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 285aa0fe033..60dfb7a48a7 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2676,6 +2676,7 @@ int read_query(struct st_query** q_ptr) end: while (*p && my_isspace(charset_info, *p)) p++; + if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME)))) die(NullS); @@ -3573,6 +3574,13 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, cur_con->stmt= stmt; } + /* Init dynamic strings for warnings */ + if (!disable_warnings) + { + init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256); + init_dynamic_string(&ds_execute_warnings, NULL, 0, 256); + } + /* Prepare the query */ @@ -3580,10 +3588,6 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, { handle_error(query, command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); -#ifndef BUG15518_FIXED - mysql_stmt_close(stmt); - cur_con->stmt= NULL; -#endif goto end; } @@ -3592,12 +3596,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, separate string */ if (!disable_warnings) - { - init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256); - init_dynamic_string(&ds_execute_warnings, NULL, 0, 256); append_warnings(&ds_prepare_warnings, mysql); - } - /* No need to call mysql_stmt_bind_param() because we have no @@ -3724,6 +3723,10 @@ end: variable then can be used from the test case itself. */ var_set_errno(mysql_stmt_errno(stmt)); +#ifndef BUG15518_FIXED + mysql_stmt_close(stmt); + cur_con->stmt= NULL; +#endif DBUG_VOID_RETURN; } @@ -4050,6 +4053,7 @@ void get_query_type(struct st_query* q) q->type= Q_COMMENT; } else if (q->type == Q_COMMENT_WITH_COMMAND && + q->first_word_len && q->query[q->first_word_len-1] == ';') { /* diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 3a8aa8614a2..3454873bca4 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1002,6 +1002,18 @@ report_stats () { echo "WARNING: Got errors/warnings while running tests. Please examine" echo "$MY_LOG_DIR/warnings for details." fi + + fi # USE_RUNNING_SERVER + + # Check valgrind errors from mysqltest + if [ ! -z "$VALGRIND_MYSQLTEST" ] + then + if $GREP "ERROR SUMMARY" $MYSQLTEST_LOG | $GREP -v "0 errors" > /dev/null + then + $ECHO "Valgrind detected errors!" + $GREP "ERROR SUMMARY" $MYSQLTEST_LOG | $GREP -v "0 errors" + $ECHO "See $MYSQLTEST_LOG" + fi fi } From b99f9ab72389009a19fca4a9fcb962dfb9d4fad1 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Fri, 9 Dec 2005 16:37:58 +0400 Subject: [PATCH 025/154] Bug#15377 Valid multibyte sequences are truncated on INSERT ctype-euc_kr.c: ctype-gb2312.c: Adding specific well_formed_length functions for gb2312 and euckr, to allow storing characters which are correct according to the character set specifications but just don't have Unicode mapping. Previously only those which have Unicode mapping could be stored, while unassigned characters lead to data truncation. Many files: new file --- mysql-test/include/have_euckr.inc | 4 + mysql-test/include/have_gb2312.inc | 4 + mysql-test/r/ctype_euckr.result | 167 +++++++++++++++++++++++++++++ mysql-test/r/ctype_gb2312.result | 167 +++++++++++++++++++++++++++++ mysql-test/r/have_euckr.require | 2 + mysql-test/r/have_gb2312.require | 2 + mysql-test/t/ctype_euckr.test | 33 ++++++ mysql-test/t/ctype_gb2312.test | 33 ++++++ strings/ctype-euc_kr.c | 37 ++++++- strings/ctype-gb2312.c | 37 ++++++- 10 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/have_euckr.inc create mode 100644 mysql-test/include/have_gb2312.inc create mode 100644 mysql-test/r/ctype_euckr.result create mode 100644 mysql-test/r/ctype_gb2312.result create mode 100644 mysql-test/r/have_euckr.require create mode 100644 mysql-test/r/have_gb2312.require create mode 100644 mysql-test/t/ctype_euckr.test create mode 100644 mysql-test/t/ctype_gb2312.test diff --git a/mysql-test/include/have_euckr.inc b/mysql-test/include/have_euckr.inc new file mode 100644 index 00000000000..af794aafc04 --- /dev/null +++ b/mysql-test/include/have_euckr.inc @@ -0,0 +1,4 @@ +-- require r/have_euckr.require +disable_query_log; +show collation like "euckr_korean_ci"; +enable_query_log; diff --git a/mysql-test/include/have_gb2312.inc b/mysql-test/include/have_gb2312.inc new file mode 100644 index 00000000000..4328bc67639 --- /dev/null +++ b/mysql-test/include/have_gb2312.inc @@ -0,0 +1,4 @@ +-- require r/have_gb2312.require +disable_query_log; +show collation like "gb2312_chinese_ci"; +enable_query_log; diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result new file mode 100644 index 00000000000..6017bc07763 --- /dev/null +++ b/mysql-test/r/ctype_euckr.result @@ -0,0 +1,167 @@ +drop table if exists t1; +SET @test_character_set= 'euckr'; +SET @test_collation= 'euckr_korean_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) euckr_korean_ci YES MUL NULL +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) euckr_korean_ci YES MUL NULL +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; +SET NAMES euckr; +SET collation_connection='euckr_korean_ci'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +euckr_korean_ci 6109 +euckr_korean_ci 61 +euckr_korean_ci 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +euckr_korean_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +euckr_korean_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET collation_connection='euckr_bin'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +euckr_bin 6109 +euckr_bin 61 +euckr_bin 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +euckr_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +euckr_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET NAMES euckr; +CREATE TABLE t1 (a text) character set euckr; +INSERT INTO t1 VALUES (0xA2E6),(0xFEF7); +SELECT hex(a) FROM t1 ORDER BY a; +hex(a) +A2E6 +FEF7 +DROP TABLE t1; diff --git a/mysql-test/r/ctype_gb2312.result b/mysql-test/r/ctype_gb2312.result new file mode 100644 index 00000000000..314c336bab9 --- /dev/null +++ b/mysql-test/r/ctype_gb2312.result @@ -0,0 +1,167 @@ +drop table if exists t1; +SET @test_character_set= 'gb2312'; +SET @test_collation= 'gb2312_chinese_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) gb2312_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) gb2312_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; +SET NAMES gb2312; +SET collation_connection='gb2312_chinese_ci'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gb2312_chinese_ci 6109 +gb2312_chinese_ci 61 +gb2312_chinese_ci 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gb2312_chinese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +gb2312_chinese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET collation_connection='gb2312_bin'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gb2312_bin 6109 +gb2312_bin 61 +gb2312_bin 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gb2312_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +gb2312_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET NAMES gb2312; +CREATE TABLE t1 (a text) character set gb2312; +INSERT INTO t1 VALUES (0xA2A1),(0xD7FE); +SELECT hex(a) FROM t1 ORDER BY a; +hex(a) +A2A1 +D7FE +DROP TABLE t1; diff --git a/mysql-test/r/have_euckr.require b/mysql-test/r/have_euckr.require new file mode 100644 index 00000000000..0771ceec570 --- /dev/null +++ b/mysql-test/r/have_euckr.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +euckr_korean_ci euckr 19 Yes Yes 1 diff --git a/mysql-test/r/have_gb2312.require b/mysql-test/r/have_gb2312.require new file mode 100644 index 00000000000..9bcb7c94a14 --- /dev/null +++ b/mysql-test/r/have_gb2312.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +gb2312_chinese_ci gb2312 24 Yes Yes 1 diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test new file mode 100644 index 00000000000..56939817b2f --- /dev/null +++ b/mysql-test/t/ctype_euckr.test @@ -0,0 +1,33 @@ +-- source include/have_euckr.inc + +# +# Tests with the euckr character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET @test_character_set= 'euckr'; +SET @test_collation= 'euckr_korean_ci'; +-- source include/ctype_common.inc + +SET NAMES euckr; +SET collation_connection='euckr_korean_ci'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc +SET collation_connection='euckr_bin'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc + +# +# Bug#15377 Valid multibyte sequences are truncated on INSERT +# +SET NAMES euckr; +CREATE TABLE t1 (a text) character set euckr; +INSERT INTO t1 VALUES (0xA2E6),(0xFEF7); +SELECT hex(a) FROM t1 ORDER BY a; +DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_gb2312.test b/mysql-test/t/ctype_gb2312.test new file mode 100644 index 00000000000..835818d441c --- /dev/null +++ b/mysql-test/t/ctype_gb2312.test @@ -0,0 +1,33 @@ +-- source include/have_gb2312.inc + +# +# Tests with the gb2312 character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET @test_character_set= 'gb2312'; +SET @test_collation= 'gb2312_chinese_ci'; +-- source include/ctype_common.inc + +SET NAMES gb2312; +SET collation_connection='gb2312_chinese_ci'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc +SET collation_connection='gb2312_bin'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc + +# +# Bug#15377 Valid multibyte sequences are truncated on INSERT +# +SET NAMES gb2312; +CREATE TABLE t1 (a text) character set gb2312; +INSERT INTO t1 VALUES (0xA2A1),(0xD7FE); +SELECT hex(a) FROM t1 ORDER BY a; +DROP TABLE t1; + +# End of 4.1 tests diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index f15e97de5be..2863b192f50 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8635,6 +8635,41 @@ my_mb_wc_euc_kr(CHARSET_INFO *cs __attribute__((unused)), } +/* + Returns well formed length of a EUC-KR string. +*/ +static uint +my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, + uint pos, int *error) +{ + const char *b0= b; + const char *emb= e - 1; /* Last possible end of an MB character */ + + *error= 0; + while (pos-- && b < e) + { + if ((uchar) b[0] < 128) + { + /* Single byte ascii character */ + b++; + } + else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + *error= 1; + break; + } + } + return (uint) (b - b0); +} + + static MY_COLLATION_HANDLER my_collation_ci_handler = { NULL, /* init */ @@ -8655,7 +8690,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_euc_kr, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_euckr, my_lengthsp_8bit, my_numcells_8bit, my_mb_wc_euc_kr, /* mb_wc */ diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index 0cbad2d1c55..52dd61a8462 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5686,6 +5686,41 @@ my_mb_wc_gb2312(CHARSET_INFO *cs __attribute__((unused)), } +/* + Returns well formed length of a EUC-KR string. +*/ +static uint +my_well_formed_len_gb2312(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, + uint pos, int *error) +{ + const char *b0= b; + const char *emb= e - 1; /* Last possible end of an MB character */ + + *error= 0; + while (pos-- && b < e) + { + if ((uchar) b[0] < 128) + { + /* Single byte ascii character */ + b++; + } + else if (b < emb && isgb2312head(*b) && isgb2312tail(b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + *error= 1; + break; + } + } + return (uint) (b - b0); +} + + static MY_COLLATION_HANDLER my_collation_ci_handler = { NULL, /* init */ @@ -5706,7 +5741,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_gb2312, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_gb2312, my_lengthsp_8bit, my_numcells_8bit, my_mb_wc_gb2312, /* mb_wc */ From 8e199d9ade5d6edf41788162695e5d891a3f8d44 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 9 Dec 2005 17:52:29 +0100 Subject: [PATCH 026/154] Made it easier to valgrind mysqltest --- mysql-test/mysql-test-run.pl | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a1d051846ee..17cc470f1c3 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -151,6 +151,7 @@ our $path_client_bindir; our $path_language; our $path_timefile; our $path_manager_log; # Used by mysqldadmin +our $path_mysqltest_log; our $path_slave_load_tmpdir; # What is this?! our $path_my_basedir; our $opt_vardir; # A path but set directly on cmd line @@ -270,6 +271,7 @@ our $opt_user; our $opt_user_test; our $opt_valgrind; +our $opt_valgrind_mysqld; our $opt_valgrind_mysqltest; our $opt_valgrind_all; our $opt_valgrind_options; @@ -742,6 +744,7 @@ sub command_line_setup () { # "somestring" option is name/path of valgrind executable # Take executable path from any of them, if any + $opt_valgrind_mysqld= $opt_valgrind; $opt_valgrind= $opt_valgrind_mysqltest if $opt_valgrind_mysqltest; $opt_valgrind= $opt_valgrind_all if $opt_valgrind_all; @@ -885,6 +888,7 @@ sub command_line_setup () { } $path_timefile= "$opt_vardir/log/mysqltest-time"; + $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; } @@ -929,7 +933,19 @@ sub executable_setup () { } else { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + if ( $opt_valgrind_mysqltest ) + { + # client/mysqltest might be a libtool .sh script, so look for real exe + # to avoid valgrinding bash ;) + $exe_mysqltest= + mtr_exe_exists("$path_client_bindir/.libs/lt-mysqltest", + "$path_client_bindir/.libs/mysqltest", + "$path_client_bindir/mysqltest"); + } + else + { + $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + } $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/tests/mysql_client_test", "/usr/bin/false"); @@ -1859,6 +1875,11 @@ sub run_testcase ($) { } report_failure_and_restart($tinfo); } + # Save info from this testcase run to mysqltest.log + mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); + my $testcase_log= mtr_fromfile($path_timefile); + mtr_tofile($path_mysqltest_log, + $testcase_log); } # ---------------------------------------------------------------------- @@ -2019,7 +2040,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); - if ( defined $opt_valgrind ) + if ( defined $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); mtr_add_arg($args, "%s--skip-bdb", $prefix); @@ -2245,7 +2266,7 @@ sub mysqld_start ($$$$) { mtr_init_args(\$args); - if ( defined $opt_valgrind ) + if ( defined $opt_valgrind_mysqld ) { valgrind_arguments($args, \$exe); } @@ -2699,6 +2720,7 @@ sub valgrind_arguments { mtr_add_arg($args, split(' ', $opt_valgrind_options)); } + mtr_add_arg($args, $$exe); $$exe= $opt_valgrind || "valgrind"; @@ -2778,9 +2800,8 @@ Options for coverage, profiling etc gcov FIXME gprof FIXME - valgrind[=EXE] Run the "mysqltest" executable as well as the "mysqld" - server using valgrind, optionally specifying the - executable path/name + valgrind[=EXE] Run the "mysqld" server using valgrind, optionally + specifying the executable path/name valgrind-mysqltest[=EXE] In addition, run the "mysqltest" executable with valgrind valgrind-all[=EXE] Adds verbose flag, and --show-reachable to valgrind valgrind-options=ARGS Extra options to give valgrind From 8aeb3a1fbacd62126e94b02d44229683666f5a49 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 9 Dec 2005 18:51:45 +0100 Subject: [PATCH 027/154] Fix warnings for running with --view_protocol --- client/mysqltest.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 60dfb7a48a7..b500c3dbe1a 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3269,6 +3269,8 @@ static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) append_result(ds, warn_res); mysql_free_result(warn_res); + DBUG_PRINT("warnings", ("%s", ds->str)); + DBUG_RETURN(count); } @@ -3292,11 +3294,10 @@ static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) static void run_query_normal(MYSQL *mysql, struct st_query *command, int flags, char *query, int query_len, - DYNAMIC_STRING *ds) + DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) { MYSQL_RES *res= 0; int err= 0, counter= 0; - DYNAMIC_STRING ds_warnings; DBUG_ENTER("run_query_normal"); DBUG_PRINT("enter",("flags: %d", flags)); DBUG_PRINT("enter", ("query: '%-.60s'", query)); @@ -3375,13 +3376,11 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, */ if (!disable_warnings && !mysql_more_results(mysql)) { - init_dynamic_string(&ds_warnings, NULL, 0, 256); - if (append_warnings(&ds_warnings, mysql)) + if (append_warnings(ds_warnings, mysql) || ds_warnings->length) { dynstr_append_mem(ds, "Warnings:\n", 10); - dynstr_append_mem(ds, ds_warnings.str, ds_warnings.length); + dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length); } - dynstr_free(&ds_warnings); } if (!disable_info) @@ -3555,7 +3554,8 @@ static void handle_no_error(struct st_query *q) */ static void run_query_stmt(MYSQL *mysql, struct st_query *command, - char *query, int query_len, DYNAMIC_STRING *ds) + char *query, int query_len, DYNAMIC_STRING *ds, + DYNAMIC_STRING *ds_warnings) { MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ MYSQL_STMT *stmt; @@ -3691,9 +3691,13 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* Append warnings to ds - if there are any */ if (append_warnings(&ds_execute_warnings, mysql) || - ds_prepare_warnings.length) + ds_prepare_warnings.length || + ds_warnings->length) { dynstr_append_mem(ds, "Warnings:\n", 10); + if (ds_warnings->length) + dynstr_append_mem(ds, ds_warnings->str, + ds_warnings->length); if (ds_prepare_warnings.length) dynstr_append_mem(ds, ds_prepare_warnings.str, ds_prepare_warnings.length); @@ -3749,12 +3753,15 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) { DYNAMIC_STRING *ds; DYNAMIC_STRING ds_result; + DYNAMIC_STRING ds_warnings; DYNAMIC_STRING eval_query; char *query; int query_len; my_bool view_created= 0, sp_created= 0; my_bool complete_query= ((flags & QUERY_SEND) && (flags & QUERY_REAP)); + init_dynamic_string(&ds_warnings, NULL, 0, 256); + /* Evaluate query if this is an eval command */ @@ -3830,6 +3837,12 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) view_created= 1; query= (char*)"SELECT * FROM mysqltest_tmp_v"; query_len = strlen(query); + + /* + Collect warnings from create of the view that should otherwise + have been produced when the SELECT was executed + */ + append_warnings(&ds_warnings, mysql); } dynstr_free(&query_str); @@ -3888,9 +3901,10 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) if (ps_protocol_enabled && complete_query && match_re(&ps_re, query)) - run_query_stmt(mysql, command, query, query_len, ds); + run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings); else - run_query_normal(mysql, command, flags, query, query_len, ds); + run_query_normal(mysql, command, flags, query, query_len, + ds, &ds_warnings); if (sp_created) { @@ -3923,6 +3937,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) check_result(ds, command->record_file, command->require_file); } + dynstr_free(&ds_warnings); if (ds == &ds_result) dynstr_free(&ds_result); if (command->type == Q_EVAL) From d07a57c03ae13cbbf7fe68cd4eebc8b7266eaa69 Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Fri, 9 Dec 2005 15:00:33 -0800 Subject: [PATCH 028/154] Fix crash in BDB from improper cleanup of transactions, and avoid problem in NDB that the fix would cause due to improper registration of a transaction that isn't meant to be seen by the handler layer. (Bug #14212) Thanks to Sergei Golubchik for helping with this. --- mysql-test/r/bdb.result | 5 +++++ mysql-test/t/bdb.test | 11 +++++++++++ sql/ha_ndbcluster.cc | 14 ++++++++------ sql/handler.cc | 3 ++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index 2bba44d36e9..dd251eed0f0 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1895,3 +1895,8 @@ t1 CREATE TABLE `t1` ( ) ENGINE=BerkeleyDB DEFAULT CHARSET=latin1 drop table t1; set storage_engine=MyISAM; +set autocommit=0; +create table t1 (a int) engine=bdb; +commit; +alter table t1 add primary key(a); +drop table t1; diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index 3167682f816..bf72a4555b8 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -973,3 +973,14 @@ drop table t1; # End varchar test eval set storage_engine=$default; + +# +# Bug #14212: Server crash after COMMIT + ALTER TABLE +# +set autocommit=0; +create table t1 (a int) engine=bdb; +commit; +alter table t1 add primary key(a); +drop table t1; + +# End of 5.0 tests diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a0efcd2c4f9..b3d5d86dc52 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3221,6 +3221,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (lock_type != F_UNLCK) { DBUG_PRINT("info", ("lock_type != F_UNLCK")); + if (!thd->transaction.on) + m_transaction_on= FALSE; + else + m_transaction_on= thd->variables.ndb_use_transactions; if (!thd_ndb->lock_count++) { PRINT_OPTION_FLAGS(thd); @@ -3235,7 +3239,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) ERR_RETURN(ndb->getNdbError()); no_uncommitted_rows_reset(thd); thd_ndb->stmt= trans; - trans_register_ha(thd, FALSE, &ndbcluster_hton); + if (m_transaction_on) + trans_register_ha(thd, FALSE, &ndbcluster_hton); } else { @@ -3250,7 +3255,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) ERR_RETURN(ndb->getNdbError()); no_uncommitted_rows_reset(thd); thd_ndb->all= trans; - trans_register_ha(thd, TRUE, &ndbcluster_hton); + if (m_transaction_on) + trans_register_ha(thd, TRUE, &ndbcluster_hton); /* If this is the start of a LOCK TABLE, a table look @@ -3284,10 +3290,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) m_ha_not_exact_count= !thd->variables.ndb_use_exact_count; m_autoincrement_prefetch= (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz; - if (!thd->transaction.on) - m_transaction_on= FALSE; - else - m_transaction_on= thd->variables.ndb_use_transactions; m_active_trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt; DBUG_ASSERT(m_active_trans); diff --git a/sql/handler.cc b/sql/handler.cc index 81e94af5dc7..416455c9bb9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1910,7 +1910,8 @@ int ha_enable_transaction(THD *thd, bool on) is an optimization hint that storage engine is free to ignore. So, let's commit an open transaction (if any) now. */ - error= end_trans(thd, COMMIT); + if (!(error= ha_commit_stmt(thd))) + error= end_trans(thd, COMMIT); } DBUG_RETURN(error); } From 79d83094ad36fea117865e340d6ef76daaa127b4 Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Sun, 11 Dec 2005 15:26:15 +0300 Subject: [PATCH 029/154] Fix for bug #14863 "Triggers: crash if create and there is no current database". Now when we create or drop trigger we check that both trigger name and trigger table always have database part specified. Thus we give an error if it they are not specified explicitly or implicitly via current database. --- mysql-test/r/trigger.result | 6 ++++++ mysql-test/t/trigger.test | 15 +++++++++++++++ sql/sql_trigger.cc | 27 +++++++++++++++++---------- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ff92fc543d4..e0048515fed 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -780,3 +780,9 @@ end// CALL p2(); drop procedure p2; drop table t1; +create trigger t1_bi before insert on test.t1 for each row set @a:=0; +ERROR 3D000: No database selected +create trigger test.t1_bi before insert on t1 for each row set @a:=0; +ERROR 3D000: No database selected +drop trigger t1_bi; +ERROR 3D000: No database selected diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index d4fa5268762..b4074897689 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -13,6 +13,8 @@ drop procedure if exists p1; # Create additional connections used through test connect (addconroot1, localhost, root,,); connect (addconroot2, localhost, root,,); +# Connection without current database set +connect (addconwithoutdb, localhost, root,,*NO-ONE*); connection default; create table t1 (i int); @@ -946,3 +948,16 @@ CALL p2(); drop procedure p2; drop table t1; +# +# Test for bug #14863 "Triggers: crash if create and there is no current +# database". We should not crash and give proper error when database for +# trigger or its table is not specified and there is no current database. +# +connection addconwithoutdb; +--error ER_NO_DB_ERROR +create trigger t1_bi before insert on test.t1 for each row set @a:=0; +--error ER_NO_DB_ERROR +create trigger test.t1_bi before insert on t1 for each row set @a:=0; +--error ER_NO_DB_ERROR +drop trigger t1_bi; +connection default; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 779b044696e..13b79821a58 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -78,10 +78,6 @@ const char * const trigname_file_ext= ".TRN"; static File_option trigname_file_parameters[]= { { - /* - FIXME: Length specified for "trigger_table" key is erroneous, problem - caused by this are reported as BUG#14090 and should be fixed ASAP. - */ {STRING_WITH_LEN("trigger_table")}, offsetof(struct st_trigname, trigger_table), FILE_OPTIONS_ESTRING @@ -155,6 +151,17 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) But do we want this ? */ + /* + Note that once we will have check for TRIGGER privilege in place we won't + need second part of condition below, since check_access() function also + checks that db is specified. + */ + if (!thd->lex->spname->m_db.length || create && !tables->db_length) + { + my_error(ER_NO_DB_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (!create && !(tables= add_table_for_trigger(thd, thd->lex->spname))) DBUG_RETURN(TRUE); @@ -285,6 +292,9 @@ end: definer. The caller is responsible to provide memory for storing LEX_STRING object. + NOTE + Assumes that trigger name is fully qualified. + RETURN VALUE False - success True - error @@ -307,9 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, /* Trigger must be in the same schema as target table. */ - if (my_strcasecmp(table_alias_charset, table->s->db, - lex->spname->m_db.str ? lex->spname->m_db.str : - thd->db)) + if (my_strcasecmp(table_alias_charset, table->s->db, lex->spname->m_db.str)) { my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); return 1; @@ -1010,7 +1018,6 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) { - const char *db= !trig->m_db.str ? thd->db : trig->m_db.str; LEX *lex= thd->lex; char path_buff[FN_REFLEN]; LEX_STRING path; @@ -1018,7 +1025,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) struct st_trigname trigname; DBUG_ENTER("add_table_for_trigger"); - strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/", + strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", trig->m_db.str, "/", trig->m_name.str, trigname_file_ext, NullS); path.length= unpack_filename(path_buff, path_buff); path.str= path_buff; @@ -1047,7 +1054,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) /* We need to reset statement table list to be PS/SP friendly. */ lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; - DBUG_RETURN(sp_add_to_query_tables(thd, lex, db, + DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str, trigname.trigger_table.str, TL_WRITE)); } From c708d9140f41830fc86939752a7061c009dc21ea Mon Sep 17 00:00:00 2001 From: "paul@snake-hub.snake.net" <> Date: Mon, 12 Dec 2005 12:15:25 -0600 Subject: [PATCH 030/154] mysqltest.c: Put options in proper order. --- client/mysqltest.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index ba1b92b31a3..3a4ce5ce7cf 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2731,10 +2731,8 @@ end: static struct my_option my_long_options[] = { - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test, @@ -2742,13 +2740,17 @@ static struct my_option my_long_options[] = {"compress", 'C', "Use the compressed server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef DBUG_OFF + {"debug", '#', "This is a non-debug version. Catch this and exit", + 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#else + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.", - (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0, - 0, 0, 0, 0, 0}, {"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.", (gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -2757,6 +2759,9 @@ static struct my_option my_long_options[] = {"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.", (gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG, MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0}, + {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.", + (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0, + 0, 0, 0, 0, 0}, {"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT, "Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout, (gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0}, From 99451444992443f1d11e9442a438b2c4b8940ca6 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 13 Dec 2005 13:12:42 +0100 Subject: [PATCH 031/154] Fixed BUG#15231: Stored procedure bug with not found condition handler Make the distinction between "exception conditions" and "completion conditions" (warning and "no data") as defined by the standard. The latter should not terminate a routine if no handler is found in the lexical scope. --- mysql-test/r/sp.result | 74 +++++++++++++++++++++++++++---------- mysql-test/t/sp.test | 83 +++++++++++++++++++++++++++++++----------- sql/sp_rcontext.cc | 23 ++++++++---- 3 files changed, 133 insertions(+), 47 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ded9754f172..288d25262e8 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3557,8 +3557,6 @@ drop procedure if exists bug7049_1| drop procedure if exists bug7049_2| drop procedure if exists bug7049_3| drop procedure if exists bug7049_4| -drop procedure if exists bug7049_5| -drop procedure if exists bug7049_6| drop function if exists bug7049_1| drop function if exists bug7049_2| create table t3 ( x int unique )| @@ -3583,18 +3581,6 @@ select 'Caught it' as 'Result'; call bug7049_3(); select 'Missed it' as 'Result'; end| -create procedure bug7049_5() -begin -declare x decimal(2,1); -set x = 'zap'; -end| -create procedure bug7049_6() -begin -declare exit handler for sqlwarning -select 'Caught it' as 'Result'; -call bug7049_5(); -select 'Missed it' as 'Result'; -end| create function bug7049_1() returns int begin @@ -3624,9 +3610,6 @@ Caught it select * from t3| x 42 -call bug7049_6()| -Result -Caught it select bug7049_2()| bug7049_2() 1 @@ -3635,8 +3618,6 @@ drop procedure bug7049_1| drop procedure bug7049_2| drop procedure bug7049_3| drop procedure bug7049_4| -drop procedure bug7049_5| -drop procedure bug7049_6| drop function bug7049_1| drop function bug7049_2| drop function if exists bug13941| @@ -4320,4 +4301,59 @@ id county 2 NULL drop table t3| drop procedure bug15441| +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| +create table t3 (id int not null)| +create procedure bug15231_1() +begin +declare xid integer; +declare xdone integer default 0; +declare continue handler for not found set xdone = 1; +set xid=null; +call bug15231_2(xid); +select xid, xdone; +end| +create procedure bug15231_2(inout ioid integer) +begin +select "Before NOT FOUND condition is triggered" as '1'; +select id into ioid from t3 where id=ioid; +select "After NOT FOUND condtition is triggered" as '2'; +if ioid is null then +set ioid=1; +end if; +end| +create procedure bug15231_3() +begin +declare exit handler for sqlwarning +select 'Caught it (wrong)' as 'Result'; +call bug15231_4(); +end| +create procedure bug15231_4() +begin +declare x decimal(2,1); +set x = 'zap'; +select 'Missed it (correct)' as 'Result'; +end| +call bug15231_1()| +1 +Before NOT FOUND condition is triggered +2 +After NOT FOUND condtition is triggered +xid xdone +1 0 +Warnings: +Warning 1329 No data to FETCH +call bug15231_3()| +Result +Missed it (correct) +Warnings: +Warning 1366 Incorrect decimal value: 'zap' for column 'x' at row 1 +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f73288f04ba..8af5b4719a1 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4288,8 +4288,6 @@ drop procedure if exists bug7049_1| drop procedure if exists bug7049_2| drop procedure if exists bug7049_3| drop procedure if exists bug7049_4| -drop procedure if exists bug7049_5| -drop procedure if exists bug7049_6| drop function if exists bug7049_1| drop function if exists bug7049_2| --enable_warnings @@ -4323,22 +4321,6 @@ begin select 'Missed it' as 'Result'; end| -create procedure bug7049_5() -begin - declare x decimal(2,1); - - set x = 'zap'; -end| - -create procedure bug7049_6() -begin - declare exit handler for sqlwarning - select 'Caught it' as 'Result'; - - call bug7049_5(); - select 'Missed it' as 'Result'; -end| - create function bug7049_1() returns int begin @@ -4363,7 +4345,6 @@ select * from t3| delete from t3| call bug7049_4()| select * from t3| -call bug7049_6()| select bug7049_2()| drop table t3| @@ -4371,8 +4352,6 @@ drop procedure bug7049_1| drop procedure bug7049_2| drop procedure bug7049_3| drop procedure bug7049_4| -drop procedure bug7049_5| -drop procedure bug7049_6| drop function bug7049_1| drop function bug7049_2| @@ -5078,6 +5057,68 @@ call bug15441('Yale')| drop table t3| drop procedure bug15441| + +# +# BUG#15231: +# +--disable_warnings +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| +--enable_warnings + +create table t3 (id int not null)| + +create procedure bug15231_1() +begin + declare xid integer; + declare xdone integer default 0; + declare continue handler for not found set xdone = 1; + + set xid=null; + call bug15231_2(xid); + select xid, xdone; +end| + +create procedure bug15231_2(inout ioid integer) +begin + select "Before NOT FOUND condition is triggered" as '1'; + select id into ioid from t3 where id=ioid; + select "After NOT FOUND condtition is triggered" as '2'; + + if ioid is null then + set ioid=1; + end if; +end| + +create procedure bug15231_3() +begin + declare exit handler for sqlwarning + select 'Caught it (wrong)' as 'Result'; + + call bug15231_4(); +end| + +create procedure bug15231_4() +begin + declare x decimal(2,1); + + set x = 'zap'; + select 'Missed it (correct)' as 'Result'; +end| + +call bug15231_1()| +call bug15231_3()| + +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index eca87e69f8e..c36c904f45d 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -160,6 +160,10 @@ sp_rcontext::set_return_value(THD *thd, Item *return_value_item) } +#define IS_WARNING_CONDITION(S) ((S)[0] == '0' && (S)[1] == '1') +#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2') +#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2') + bool sp_rcontext::find_handler(uint sql_errno, MYSQL_ERROR::enum_warning_level level) @@ -193,18 +197,17 @@ sp_rcontext::find_handler(uint sql_errno, found= i; break; case sp_cond_type_t::warning: - if ((sqlstate[0] == '0' && sqlstate[1] == '1' || - level == MYSQL_ERROR::WARN_LEVEL_WARN) && - found < 0) + if ((IS_WARNING_CONDITION(sqlstate) || + level == MYSQL_ERROR::WARN_LEVEL_WARN) && + found < 0) found= i; break; case sp_cond_type_t::notfound: - if (sqlstate[0] == '0' && sqlstate[1] == '2' && - found < 0) + if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0) found= i; break; case sp_cond_type_t::exception: - if ((sqlstate[0] != '0' || sqlstate[1] > '2') && + if (IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR && found < 0) found= i; @@ -213,7 +216,13 @@ sp_rcontext::find_handler(uint sql_errno, } if (found < 0) { - if (m_prev_runtime_ctx) + /* + Only "exception conditions" are propagated to handlers in calling + contexts. If no handler is found locally for a "completion condition" + (warning or "not found") we will simply resume execution. + */ + if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && + level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level); return FALSE; } From 1d83ff5b986be421bfdfc6f55ac542b09e73de56 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 13 Dec 2005 13:22:15 +0100 Subject: [PATCH 032/154] Added bug synopsis in comment for sp.test case BUG#15231. --- mysql-test/t/sp.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 8af5b4719a1..2c323a6d2c6 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5059,7 +5059,7 @@ drop procedure bug15441| # -# BUG#15231: +# BUG#15231: Stored procedure bug with not found condition handler # --disable_warnings drop table if exists t3| From 36c86a4df64a01df6cf6dab96415fee1429f3a90 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 13 Dec 2005 18:07:13 +0100 Subject: [PATCH 033/154] Fix tests after merge Straighten out and comment behaviour for --require and --result in run_query --- client/mysqltest.c | 32 ++++++++++++++++++-------------- mysql-test/r/mysqltest.result | 17 ++++++++--------- mysql-test/t/mysqltest.test | 18 +++++++++--------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 135fa370688..3f8b6582eb9 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3925,22 +3925,26 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) mysql_errno(mysql), mysql_error(mysql)); } - if (record) + if (command->record_file[0]) { - /* Recording in progress */ - if (!command->record_file[0]) - die("Missing result file"); - /* Dump the output from _this_ query to the specified record_file */ - str_to_file(command->record_file, ds->str, ds->length); - } - else if (command->record_file[0]) - { - /* - The output from _this_ query should be checked against an already - existing file which has been specified using --require or --result - */ - check_result(ds, command->record_file, command->require_file); + /* A result file was specified for _this_ query */ + if (record) + { + /* + Recording in progress + Dump the output from _this_ query to the specified record_file + */ + str_to_file(command->record_file, ds->str, ds->length); + + } else { + + /* + The output from _this_ query should be checked against an already + existing file which has been specified using --require or --result + */ + check_result(ds, command->record_file, command->require_file); + } } dynstr_free(&ds_warnings); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 8ea3a48e948..2e78f468f93 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -396,12 +396,20 @@ root@localhost -------------------------------------------------------------------------------- this will be executed this will be executed +mysqltest: Result length mismatch +mysqltest: The test didn't produce any output +Failing multi statement query mysqltest: At line 3: query 'create table t1 (a int primary key); insert into t1 values (1); select 'select-me'; insertz 'error query'' failed: 1064: 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 'insertz 'error query'' at line 1 drop table t1; +mysqltest: At line 3: query 'create table t1 (a int primary key); +insert into t1 values (1); +select 'select-me'; +insertz 'error query'' failed: 1064: 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 'insertz 'error query'' at line 1 drop table t1; +Multi statement using expected error create table t1 (a int primary key); insert into t1 values (1); select 'select-me'; @@ -410,13 +418,4 @@ select-me select-me 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 'insertz error query' at line 1 drop table t1; -create table t1 (a int primary key); -insert into t1 values (1); -select 'select-me'; -insertz error query|||| -select-me -select-me -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 'insertz error query' at line 1 drop table t1; -mysqltest: Result length mismatch -mysqltest: The test didn't produce any output diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 1d22705fb8e..132a6329178 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -984,7 +984,7 @@ select "this will be executed"; # non-1st queries # -# Failing multi statement query +echo Failing multi statement query; # PS does not support multi statement --exec echo "--disable_ps_protocol" > var/tmp/bug11731.sql --exec echo "delimiter ||||;" >> var/tmp/bug11731.sql @@ -999,14 +999,13 @@ select "this will be executed"; drop table t1; --error 1 ---exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out -# The .out file should be empty, cat will fail! ---error 1 ---exec cat $MYSQL_TEST_DIR/var/tmp/bug11731.out +--exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out 2>&1 +# The .out file should be non existent +--exec test ! -e $MYSQL_TEST_DIR/var/tmp/bug11731.out drop table t1; -# Using expected error +echo Multi statement using expected error; # PS does not support multi statement --exec echo "--disable_ps_protocol" > var/tmp/bug11731.sql --exec echo "delimiter ||||;" >> var/tmp/bug11731.sql @@ -1018,11 +1017,12 @@ drop table t1; --exec echo "delimiter ;||||" >> var/tmp/bug11731.sql # These two should work since the error is expected ---exec $MYSQL_TEST -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql 2>&1 +--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql 2>&1 drop table t1; ---exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out ---exec cat $MYSQL_TEST_DIR/var/tmp/bug11731.out +--exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out 2>&1 +# The .out file should exist +--exec test -s $MYSQL_TEST_DIR/var/tmp/bug11731.out drop table t1; From b5d805b2d6e552c07257d5adf4da9737d3a343a3 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 13 Dec 2005 18:10:53 +0100 Subject: [PATCH 034/154] Remove confusing printout --- client/mysqltest.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 3f8b6582eb9..8938df1944f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3500,12 +3500,6 @@ static void handle_error(const char *query, struct st_query *q, q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); } - /* - If we do not abort on error, failure to run the query does not fail the - whole test case. - */ - verbose_msg("query '%s' failed: %d: %s", q->query, err_errno, - err_error); DBUG_VOID_RETURN; } From b38a183d6278a2bf62e35aaa0325c844bdcf664e Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 13 Dec 2005 18:47:34 +0100 Subject: [PATCH 035/154] Remove confusing printouts from expected to fail "system" commands --- client/mysqltest.c | 12 ++++++++++-- mysql-test/r/mysqltest.result | 1 + mysql-test/t/mysqltest.test | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 8938df1944f..7ba8dc31405 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1134,6 +1134,7 @@ static void do_exec(struct st_query *query) } free_replace(); + DBUG_VOID_RETURN; } @@ -1300,10 +1301,13 @@ int do_modify_var(struct st_query *query, const char *name, int do_system(struct st_query *q) { + DYNAMIC_STRING *ds; char *p=q->first_argument; VAR v; var_init(&v, 0, 0, 0, 0); eval_expr(&v, p, 0); /* NULL terminated */ + ds= &ds_res; + if (v.str_val_len) { char expr_buf[1024]; @@ -1316,8 +1320,11 @@ int do_system(struct st_query *q) { if (q->abort_on_error) die("system command '%s' failed", expr_buf); - /* If ! abort_on_error, display message and continue */ - verbose_msg("system command '%s' failed", expr_buf); + + /* If ! abort_on_error, log message and continue */ + dynstr_append(ds, "system command '"); + replace_dynstr_append(ds, expr_buf); + dynstr_append(ds, "' failed\n"); } } else @@ -1582,6 +1589,7 @@ int do_sleep(struct st_query *query, my_bool real_sleep) if (opt_sleep && !real_sleep) sleep_val= opt_sleep; + DBUG_PRINT("info", ("sleep_val: %f", sleep_val)); my_sleep((ulong) (sleep_val * 1000000L)); query->last_argument= sleep_end; return 0; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 2e78f468f93..0109436fac9 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -304,6 +304,7 @@ mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: system command 'false' failed +system command 'NonExistsinfComamdn 2> /dev/null' failed test test2 test3 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 132a6329178..3d851605823 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -689,7 +689,7 @@ system echo "hej" > /dev/null; --exec echo "system false;" | $MYSQL_TEST 2>&1 --disable_abort_on_error -system NonExistsinfComamdn; +system NonExistsinfComamdn 2> /dev/null; --enable_abort_on_error @@ -1026,4 +1026,3 @@ drop table t1; drop table t1; - From 2059a6c174424f4d7a421b13c6599df16070cfea Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Wed, 14 Dec 2005 15:09:12 +0100 Subject: [PATCH 036/154] bug#15682 - ndb incorrect handling of varchar in position/rnd_pos Commit for 5.0.17 release clone --- mysql-test/r/ndb_basic.result | 16 ++++++++++++++++ mysql-test/t/ndb_basic.test | 11 +++++++++++ sql/ha_ndbcluster.cc | 21 +++++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result index 55cbbd89b3c..9dd75f1390c 100644 --- a/mysql-test/r/ndb_basic.result +++ b/mysql-test/r/ndb_basic.result @@ -677,3 +677,19 @@ select * from atablewithareallylongandirritatingname; a 2 drop table atablewithareallylongandirritatingname; +create table t1 (f1 varchar(50), f2 text,f3 int, primary key(f1)) engine=NDB; +insert into t1 (f1,f2,f3)VALUES("111111","aaaaaa",1); +insert into t1 (f1,f2,f3)VALUES("222222","bbbbbb",2); +select * from t1 order by f1; +f1 f2 f3 +111111 aaaaaa 1 +222222 bbbbbb 2 +select * from t1 order by f2; +f1 f2 f3 +111111 aaaaaa 1 +222222 bbbbbb 2 +select * from t1 order by f3; +f1 f2 f3 +111111 aaaaaa 1 +222222 bbbbbb 2 +drop table t1; diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test index 0510651a417..12aca73d82b 100644 --- a/mysql-test/t/ndb_basic.test +++ b/mysql-test/t/ndb_basic.test @@ -623,3 +623,14 @@ create table atablewithareallylongandirritatingname (a int); insert into atablewithareallylongandirritatingname values (2); select * from atablewithareallylongandirritatingname; drop table atablewithareallylongandirritatingname; + +# +# Bug#15682 +# +create table t1 (f1 varchar(50), f2 text,f3 int, primary key(f1)) engine=NDB; +insert into t1 (f1,f2,f3)VALUES("111111","aaaaaa",1); +insert into t1 (f1,f2,f3)VALUES("222222","bbbbbb",2); +select * from t1 order by f1; +select * from t1 order by f2; +select * from t1 order by f3; +drop table t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 1156ba1317f..7beda755f9d 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2812,8 +2812,25 @@ void ha_ndbcluster::position(const byte *record) } *buff++= 0; } - memcpy(buff, record + key_part->offset, key_part->length); - buff += key_part->length; + size_t len = key_part->length; + const byte * ptr = record + key_part->offset; + Field *field = key_part->field; + if ((field->type() == MYSQL_TYPE_VARCHAR) && + ((Field_varstring*)field)->length_bytes == 1) + { + /** + * Keys always use 2 bytes length + */ + buff[0] = ptr[0]; + buff[1] = 0; + memcpy(buff+2, ptr + 1, len); + len += 2; + } + else + { + memcpy(buff, ptr, len); + } + buff += len; } } else From 138ec21cc91994c223668aa3c19618e1975cfbce Mon Sep 17 00:00:00 2001 From: "mskold@mysql.com" <> Date: Wed, 14 Dec 2005 16:29:56 +0100 Subject: [PATCH 037/154] Fix to make ndb_multi.test (Bug #15401 NDB lock problems) more predictable --- mysql-test/r/ndb_multi.result | 1 + mysql-test/t/ndb_multi.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/r/ndb_multi.result b/mysql-test/r/ndb_multi.result index 2080be241e8..bd3af223a65 100644 --- a/mysql-test/r/ndb_multi.result +++ b/mysql-test/r/ndb_multi.result @@ -30,6 +30,7 @@ create table t1 (a int) engine=ndbcluster; insert into t1 value (2); select * from t1; ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster +flush table t1; select * from t1; a 2 diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test index 760150c6f6a..1183f2b283f 100644 --- a/mysql-test/t/ndb_multi.test +++ b/mysql-test/t/ndb_multi.test @@ -40,6 +40,7 @@ connection server1; # Currently a retry is required remotely --error 1296 select * from t1; +flush table t1; select * from t1; # Connect to server2 and use the tables from there From 04cff0d055fd63d7f0a9395478171e735799f30b Mon Sep 17 00:00:00 2001 From: "ramil@mysql.com" <> Date: Wed, 14 Dec 2005 21:42:08 +0400 Subject: [PATCH 038/154] Fix for bug #15623: Test case rpl000001 and rpl_error_ignored_table failure on MacOSX and bug #15668: Test 'sp-error' crashes server on Mac OS X. --- mysql-test/r/rpl000001.result | 2 +- mysql-test/t/flush_read_lock_kill.test | 2 +- mysql-test/t/rpl000001.test | 2 +- mysql-test/t/rpl_error_ignored_table.test | 2 +- sql/sql_class.cc | 4 +++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result index 450e728090e..de9f6f16b2a 100644 --- a/mysql-test/r/rpl000001.result +++ b/mysql-test/r/rpl000001.result @@ -50,7 +50,7 @@ select (@id := id) - id from t2; 0 kill @id; drop table t2; -ERROR 08S01: Server shutdown in progress +Got one of the listed errors set global sql_slave_skip_counter=1; start slave; select count(*) from t1; diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test index de2576300dc..19a47b2893a 100644 --- a/mysql-test/t/flush_read_lock_kill.test +++ b/mysql-test/t/flush_read_lock_kill.test @@ -42,7 +42,7 @@ connection con1; # debug build running without our --debug=make_global..., will be # error 0 (no error). The only important thing to test is that on # debug builds with our --debug=make_global... we don't hang forever. ---error 0,1053 +--error 0,1053,2013 reap; connection con2; diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 3d03823d474..45d621b730f 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -92,7 +92,7 @@ kill @id; # We don't drop t3 as this is a temporary table drop table t2; connection master; ---error 1053 +--error 1053,2013 reap; connection slave; # The SQL slave thread should now have stopped because the query was killed on diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index cb4137c49e0..339d966dbb3 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -45,7 +45,7 @@ select (@id := id) - id from t3; kill @id; drop table t2,t3; connection master; ---error 0,1053 +--error 0,1053,2013 reap; connection master1; --replace_column 2 # 5 # diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 989b8142202..035018c91bc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -473,10 +473,12 @@ void THD::awake(THD::killed_state state_to_set) killed= state_to_set; if (state_to_set != THD::KILL_QUERY) + { thr_alarm_kill(real_id); #ifdef SIGNAL_WITH_VIO_CLOSE - close_active_vio(); + close_active_vio(); #endif + } if (mysys_var) { pthread_mutex_lock(&mysys_var->mutex); From 5bb966a9b61eeaac9677cfe09d21fd9bb5435f4c Mon Sep 17 00:00:00 2001 From: "jimw@mysql.com" <> Date: Wed, 14 Dec 2005 15:01:02 -0800 Subject: [PATCH 039/154] Fix crash when trying to open table using a disabled storage engine. (Bug #15185) --- sql/handler.cc | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 47010de3002..5a0e0d27b40 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -300,39 +300,56 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type) case DB_TYPE_HASH: return new (alloc) ha_hash(table); #endif + case DB_TYPE_MRG_MYISAM: case DB_TYPE_MRG_ISAM: return new (alloc) ha_myisammrg(table); #ifdef HAVE_BERKELEY_DB case DB_TYPE_BERKELEY_DB: - return new (alloc) ha_berkeley(table); + if (have_berkeley_db == SHOW_OPTION_YES) + return new (alloc) ha_berkeley(table); + return NULL; #endif #ifdef HAVE_INNOBASE_DB case DB_TYPE_INNODB: - return new (alloc) ha_innobase(table); + if (have_innodb == SHOW_OPTION_YES) + return new (alloc) ha_innobase(table); + return NULL; #endif #ifdef HAVE_EXAMPLE_DB case DB_TYPE_EXAMPLE_DB: - return new (alloc) ha_example(table); + if (have_example_db == SHOW_OPTION_YES) + return new (alloc) ha_example(table); + return NULL; #endif #if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) case DB_TYPE_ARCHIVE_DB: - return new (alloc) ha_archive(table); + if (have_archive_db == SHOW_OPTION_YES) + return new (alloc) ha_archive(table); + return NULL; #endif #ifdef HAVE_BLACKHOLE_DB case DB_TYPE_BLACKHOLE_DB: - return new (alloc) ha_blackhole(table); + if (have_blackhole_db == SHOW_OPTION_YES) + return new (alloc) ha_blackhole(table); + return NULL; #endif #ifdef HAVE_FEDERATED_DB case DB_TYPE_FEDERATED_DB: - return new (alloc) ha_federated(table); + if (have_federated_db == SHOW_OPTION_YES) + return new (alloc) ha_federated(table); + return NULL; #endif #ifdef HAVE_CSV_DB case DB_TYPE_CSV_DB: - return new (alloc) ha_tina(table); + if (have_csv_db == SHOW_OPTION_YES) + return new (alloc) ha_tina(table); + return NULL; #endif #ifdef HAVE_NDBCLUSTER_DB case DB_TYPE_NDBCLUSTER: - return new (alloc) ha_ndbcluster(table); + if (have_ndbcluster == SHOW_OPTION_YES) + return new (alloc) ha_ndbcluster(table); + return NULL; #endif case DB_TYPE_HEAP: return new (alloc) ha_heap(table); @@ -346,8 +363,6 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type) /* Fall back to MyISAM */ case DB_TYPE_MYISAM: return new (alloc) ha_myisam(table); - case DB_TYPE_MRG_MYISAM: - return new (alloc) ha_myisammrg(table); } } From f6d77ed18c75f5e6fd45c91244b1065b4d0c8d46 Mon Sep 17 00:00:00 2001 From: "rparranovo@mysql.com" <> Date: Thu, 15 Dec 2005 00:54:15 -0300 Subject: [PATCH 040/154] Makefile.am: - Modified zlib/Makefile.am to generate libz.so.1.2.3 instead of libz.so.0.0.0 --- zlib/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zlib/Makefile.am b/zlib/Makefile.am index e94d184a841..679adc0c997 100644 --- a/zlib/Makefile.am +++ b/zlib/Makefile.am @@ -18,6 +18,8 @@ pkglib_LTLIBRARIES=libz.la +libz_la_LDFLAGS= -version-info=3:3:2 + noinst_HEADERS= crc32.h deflate.h inffast.h inffixed.h inflate.h \ inftrees.h trees.h zconf.h zlib.h zutil.h From b21e1d418d1bcc566e6c27cfbad8b1c032aada0c Mon Sep 17 00:00:00 2001 From: "rparranovo@mysql.com" <> Date: Thu, 15 Dec 2005 02:11:21 -0300 Subject: [PATCH 041/154] Makefile.am: - libtool wants spaces on parameters for its command line options --- zlib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zlib/Makefile.am b/zlib/Makefile.am index 679adc0c997..11b1991fa62 100644 --- a/zlib/Makefile.am +++ b/zlib/Makefile.am @@ -18,7 +18,7 @@ pkglib_LTLIBRARIES=libz.la -libz_la_LDFLAGS= -version-info=3:3:2 +libz_la_LDFLAGS= -version-info 3:3:2 noinst_HEADERS= crc32.h deflate.h inffast.h inffixed.h inflate.h \ inftrees.h trees.h zconf.h zlib.h zutil.h From ea4c3481f2590510eba5ce915dad47f491f67054 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Thu, 15 Dec 2005 18:48:08 +0300 Subject: [PATCH 042/154] Fixed BUG #12440: "Incorrect processing of time values containing long fraction and/or large exponent part". --- mysql-test/r/type_time.result | 24 ++++++++++++++++++++++++ mysql-test/t/type_time.test | 14 ++++++++++++++ sql-common/my_time.c | 28 ++++++++++++++++++++++------ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index 025cf2a57f1..cb76f699cd9 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -85,3 +85,27 @@ sec_to_time(time_to_sec(t)) 13:00:00 09:00:00 drop table t1; +SELECT CAST(235959.123456 AS TIME); +CAST(235959.123456 AS TIME) +23:59:59.123456 +SELECT CAST(0.235959123456e+6 AS TIME); +CAST(0.235959123456e+6 AS TIME) +23:59:59.123456 +SELECT CAST(235959123456e-6 AS TIME); +CAST(235959123456e-6 AS TIME) +23:59:59.123456 +SELECT CAST(235959.1234567 AS TIME); +CAST(235959.1234567 AS TIME) +23:59:59.123456 +Warnings: +Warning 1292 Truncated incorrect time value: '235959.1234567' +SELECT CAST(0.2359591234567e6 AS TIME); +CAST(0.2359591234567e6 AS TIME) +23:59:59.123456 +Warnings: +Warning 1292 Truncated incorrect time value: '235959.1234567' +SELECT CAST(0.2359591234567e+30 AS TIME); +CAST(0.2359591234567e+30 AS TIME) +NULL +Warnings: +Warning 1292 Truncated incorrect time value: '2.359591234567e+29' diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 7ae3f65f7cc..9abfe914335 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -21,4 +21,18 @@ select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1; select sec_to_time(time_to_sec(t)) from t1; drop table t1; +# +# BUG #12440: Incorrect processing of time values containing +# long fraction part and/or large exponent part. +# +# These must return normal result: +SELECT CAST(235959.123456 AS TIME); +SELECT CAST(0.235959123456e+6 AS TIME); +SELECT CAST(235959123456e-6 AS TIME); +# These must cut fraction part and produce warning: +SELECT CAST(235959.1234567 AS TIME); +SELECT CAST(0.2359591234567e6 AS TIME); +# This must return NULL and produce warning: +SELECT CAST(0.2359591234567e+30 AS TIME); + # End of 4.1 tests diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 40d7799e274..3c46a944ba9 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -514,18 +514,34 @@ fractional: /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) { - uint field_length=5; + int field_length= 5; str++; value=(uint) (uchar) (*str - '0'); - while (++str != end && - my_isdigit(&my_charset_latin1,str[0]) && - field_length--) - value=value*10 + (uint) (uchar) (*str - '0'); - if (field_length) + while (++str != end && my_isdigit(&my_charset_latin1, *str)) + { + if (field_length-- > 0) + value= value*10 + (uint) (uchar) (*str - '0'); + } + if (field_length > 0) value*= (long) log_10_int[field_length]; + else if (field_length < 0) + *was_cut= 1; date[4]=value; } else date[4]=0; + + /* Check for exponent part: E | E */ + /* (may occur as result of %g formatting of time value) */ + if ((end - str) > 1 && + (*str == 'e' || *str == 'E') && + (my_isdigit(&my_charset_latin1, str[1]) || + ((str[1] == '-' || str[1] == '+') && + (end - str) > 2 && + my_isdigit(&my_charset_latin1, str[2])))) + { + *was_cut= 1; + return 1; + } if (internal_format_positions[7] != 255) { From 5e34b5da01125faec5814e66b14dab957d0be641 Mon Sep 17 00:00:00 2001 From: "ranger@regul.home.lan" <> Date: Fri, 16 Dec 2005 00:23:55 +0200 Subject: [PATCH 043/154] Fixed stress parts in shell and perl versions of mysql-test-run script to limit stress testing with 20 test loops in case when any limit parameter was specified --- mysql-test/lib/mtr_stress.pl | 8 ++++++++ mysql-test/mysql-test-run.pl | 2 +- mysql-test/mysql-test-run.sh | 12 ++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/mysql-test/lib/mtr_stress.pl b/mysql-test/lib/mtr_stress.pl index a57d94e8043..d3ed24db545 100644 --- a/mysql-test/lib/mtr_stress.pl +++ b/mysql-test/lib/mtr_stress.pl @@ -145,6 +145,14 @@ sub run_stress_test () mtr_add_arg($args, "--stress-init-file=%", $::opt_stress_init_file); } + if ( !$::opt_stress_loop_count && !$::opt_stress_test_count && + !$::opt_stress_test_duration ) + { + #Limit stress testing with 20 loops in case when any limit parameter + #was specified + $::opt_stress_test_count=20; + } + if ( $::opt_stress_loop_count ) { mtr_add_arg($args, "--loop-count=%s", $::opt_stress_loop_count); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 8ccd87fc7a8..0513d3d4a1a 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -276,7 +276,7 @@ our $opt_stress= ""; our $opt_stress_suite= "main"; our $opt_stress_mode= "random"; our $opt_stress_threads= 5; -our $opt_stress_test_count= 20; +our $opt_stress_test_count= ""; our $opt_stress_loop_count= ""; our $opt_stress_test_duration= ""; our $opt_stress_init_file= ""; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index c84763713e1..a115a82a6a4 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -279,7 +279,7 @@ DO_STRESS="" STRESS_SUITE="main" STRESS_MODE="random" STRESS_THREADS=5 -STRESS_TEST_COUNT=20 +STRESS_TEST_COUNT="" STRESS_LOOP_COUNT="" STRESS_TEST_DURATION="" STRESS_INIT_FILE="" @@ -1906,7 +1906,7 @@ run_stress_test() --stress-basedir=$STRESS_BASEDIR \ --server-logs-dir=$STRESS_BASEDIR \ --stress-mode=$STRESS_MODE \ - --mysqltest=$BASEDIR/client/mysqltest \ + --mysqltest=$CLIENT_BINDIR/mysqltest \ --threads=$STRESS_THREADS \ --verbose \ --cleanup \ @@ -1917,6 +1917,14 @@ run_stress_test() STRESS_TEST_ARGS="$STRESS_TEST_ARGS --stress-init-file=$STRESS_INIT_FILE" fi + if [ -z "$STRESS_LOOP_COUNT" -a -z "$STRESS_TEST_COUNT" -a + -z "$STRESS_TEST_DURATION" ] ; then + + #Limit stress testing with 20 loops in case when any limit parameter + #was specified + STRESS_TEST_COUNT=20 + fi + if [ -n "$STRESS_LOOP_COUNT" ] ; then STRESS_TEST_ARGS="$STRESS_TEST_ARGS --loop-count=$STRESS_LOOP_COUNT" fi From fb50e37c5ab9cce4b441eeb41da8412573baedd7 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Fri, 16 Dec 2005 09:38:30 +0100 Subject: [PATCH 044/154] BUG#15805: Disabled test type_time; fails in --ps-protocol mode. --- mysql-test/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 4722fac435c..0e7eabbed6d 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -13,3 +13,4 @@ sp-goto : GOTO is currently is disabled - will be fixed in the future kill : Unstable test case, bug#9712 subselect : Bug#15706 +type_time : Bug#15805 From 29f44a8c7795a5faec07c6ee33cfe07b68dfebf0 Mon Sep 17 00:00:00 2001 From: "ranger@regul.home.lan" <> Date: Fri, 16 Dec 2005 22:53:10 +0200 Subject: [PATCH 045/154] Fixed default values for counters to 0 --- mysql-test/mysql-test-run.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0513d3d4a1a..6e46a93dce9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -276,9 +276,9 @@ our $opt_stress= ""; our $opt_stress_suite= "main"; our $opt_stress_mode= "random"; our $opt_stress_threads= 5; -our $opt_stress_test_count= ""; -our $opt_stress_loop_count= ""; -our $opt_stress_test_duration= ""; +our $opt_stress_test_count= 0; +our $opt_stress_loop_count= 0; +our $opt_stress_test_duration= 0; our $opt_stress_init_file= ""; our $opt_stress_test_file= ""; From 297d80dc110d469374827a7f3aca400530f7818a Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sun, 18 Dec 2005 13:30:01 +0100 Subject: [PATCH 046/154] BUG#11336 - fulltext index corruption after repair_by_sort and mi_delete for uca collation isalnum and strnncollsp don't agree on whether 0xC2A0 is a space (strnncollsp is right, isalnum is wrong). they still don't, the bug was fixed by avoiding strnncollsp --- myisam/mi_delete.c | 2 +- mysql-test/r/fulltext2.result | 21 +++++++++++++++++++++ mysql-test/t/fulltext2.test | 32 +++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 833223221ec..6c302aecea1 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -157,7 +157,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo, goto err; } if ((error=d_search(info,keyinfo, - (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND + (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND | SEARCH_UPDATE : SEARCH_SAME), key,key_length,old_root,root_buff)) >0) { diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result index 0b1d8eb9a15..72c6b2d22ed 100644 --- a/mysql-test/r/fulltext2.result +++ b/mysql-test/r/fulltext2.result @@ -215,3 +215,24 @@ select count(*) from t1 where match a against ('aaazzz' in boolean mode); count(*) 262 drop table t1; +set names utf8; +create table t1(a text,fulltext(a)) collate=utf8_swedish_ci; +insert into t1 values('test test '),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'); +delete from t1 limit 1; +drop table t1; +set names latin1; diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test index bcd39b9ea04..7a7b572d58f 100644 --- a/mysql-test/t/fulltext2.test +++ b/mysql-test/t/fulltext2.test @@ -179,7 +179,37 @@ update t1 set a='aaaxxx' where a = 'aaayyy'; select count(*) from t1 where match a against ('aaaxxx' in boolean mode); select count(*) from t1 where match a against ('aaayyy' in boolean mode); select count(*) from t1 where match a against ('aaazzz' in boolean mode); - drop table t1; +# +# BUG#11336 +# +# for uca collation isalnum and strnncollsp don't agree on whether +# 0xC2A0 is a space (strnncollsp is right, isalnum is wrong). +# +# they still don't, the bug was fixed by avoiding strnncollsp +# + +set names utf8; +create table t1(a text,fulltext(a)) collate=utf8_swedish_ci; +insert into t1 values('test test '),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'), +('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'); +delete from t1 limit 1; +drop table t1; +set names latin1; + # End of 4.1 tests From d3b64781e16367b5b1917fc25d77d19f71a33712 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Sun, 18 Dec 2005 14:51:19 +0100 Subject: [PATCH 047/154] Makefile.am: Adjusted listing of files to put into source TAR --- BUILD/Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index 2414d4f3a44..859bc0c00c4 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -23,7 +23,9 @@ EXTRA_DIST = FINISH.sh \ compile-alpha-ccc \ compile-alpha-cxx \ compile-alpha-debug \ + compile-dist \ compile-ia64-debug-max \ + compile-irix-mips64-mipspro \ compile-pentium \ compile-pentium-debug \ compile-pentium-debug-max \ @@ -35,9 +37,10 @@ EXTRA_DIST = FINISH.sh \ compile-pentium-myodbc \ compile-pentium-mysqlfs-debug \ compile-pentium-pgcc \ + compile-pentium-valgrind-max \ + compile-pentium64-debug-max \ compile-solaris-sparc \ compile-solaris-sparc-debug \ - compile-irix-mips64-mipspro \ compile-solaris-sparc-forte \ compile-solaris-sparc-purify From 16d66d2a1e4157dad48d509c91316d27c1e6f5a7 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Sun, 18 Dec 2005 15:07:58 +0100 Subject: [PATCH 048/154] Makefile.am: Added 5.0 specific build scripts --- BUILD/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index 2d58486e0ba..a5f3623c25e 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -37,11 +37,15 @@ EXTRA_DIST = FINISH.sh \ compile-pentium-debug \ compile-pentium-debug-max \ compile-pentium-debug-max-no-embedded \ + compile-pentium-debug-max-no-ndb \ compile-pentium-debug-no-bdb \ compile-pentium-debug-openssl \ compile-pentium-debug-yassl \ compile-pentium-gcov \ compile-pentium-gprof \ + compile-pentium-icc \ + compile-pentium-icc-valgrind-max \ + compile-pentium-icc-yassl \ compile-pentium-max \ compile-pentium-myodbc \ compile-pentium-mysqlfs-debug \ @@ -53,6 +57,7 @@ EXTRA_DIST = FINISH.sh \ compile-ppc \ compile-ppc-debug \ compile-ppc-debug-max \ + compile-ppc-debug-max-no-ndb \ compile-ppc-max \ compile-solaris-sparc \ compile-solaris-sparc-debug \ From f2b1e403837e1b544f87fae9584b61077da90e9a Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Mon, 19 Dec 2005 03:39:25 +0100 Subject: [PATCH 049/154] mysql-test-run.pl: Script "my_print_defaults" is to be searched for as executable --- mysql-test/mysql-test-run.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6e46a93dce9..d64a487758d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -964,7 +964,7 @@ sub executable_setup () { $exe_mysql_fix_system_tables= mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables"); $exe_my_print_defaults= - mtr_script_exists("$glob_basedir/extra/my_print_defaults"); + mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } @@ -982,7 +982,7 @@ sub executable_setup () { mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", "$glob_basedir/scripts/mysql_fix_privilege_tables"); $exe_my_print_defaults= - mtr_script_exists("$path_client_bindir/my_print_defaults"); + mtr_exe_exists("$path_client_bindir/my_print_defaults"); $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", "$glob_basedir/share/english/"); From c8631b414bf449453634e63a3d7e07d14abc2e5b Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Mon, 19 Dec 2005 14:46:54 +0400 Subject: [PATCH 050/154] Bug#12770 DESC cannot display the info. about temporary table Bug#14387 SHOW COLUMNS doesn't work on temporary tables. Bug#15224 SHOW INDEX from temporary table doesn't work. Restore thd->temporary_tables to be able to process temporary tables(only for 'show index' & 'show columns'). This should be changed when processing of temporary tables for I_S tables will be done. --- mysql-test/r/information_schema.result | 11 +++++++++++ mysql-test/t/information_schema.test | 11 +++++++++++ sql/sql_show.cc | 8 ++++++++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 6224b30b70e..5e34c41dfb2 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1056,3 +1056,14 @@ where table_name="v1"; table_type VIEW drop view v1; +create temporary table t1(f1 int, index(f1)); +show columns from t1; +Field Type Null Key Default Extra +f1 int(11) YES MUL NULL +describe t1; +Field Type Null Key Default Extra +f1 int(11) YES MUL NULL +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 f1 1 f1 A NULL NULL NULL YES BTREE +drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index acbc62f1364..b982047cec7 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -748,3 +748,14 @@ drop table t1; select table_type from information_schema.tables where table_name="v1"; drop view v1; + +# +# Bug #14387 SHOW COLUMNS doesn't work on temporary tables +# Bug #15224 SHOW INDEX from temporary table doesn't work +# Bug #12770 DESC cannot display the info. about temporary table +# +create temporary table t1(f1 int, index(f1)); +show columns from t1; +describe t1; +show indexes from t1; +drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 82870d46e6c..dc6c141bef7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2069,6 +2069,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) bool res; lex->all_selects_list= lsel; + /* + Restore thd->temporary_tables to be able to process + temporary tables(only for 'show index' & 'show columns'). + This should be changed when processing of temporary tables for + I_S tables will be done. + */ + thd->temporary_tables= open_tables_state_backup.temporary_tables; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); /* @@ -2088,6 +2095,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) show_table_list->view_db.str : show_table_list->db), show_table_list->alias)); + thd->temporary_tables= 0; close_thread_tables(thd); show_table_list->table= 0; goto err; From f4b052844f20004a96bd1ccd4a88897726265f06 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Mon, 19 Dec 2005 15:36:03 +0400 Subject: [PATCH 051/154] Fix for bug#14861 aliased column names are not preserved. Create tmp table filed using original item name when it's necessary --- mysql-test/r/view.result | 16 ++++++++++++++++ mysql-test/t/view.test | 19 +++++++++++++++++++ sql/sql_select.cc | 12 +++++++----- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index e4f2671eb34..7e7d0617b51 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2456,3 +2456,19 @@ f1() 42 drop view v2,v1; drop function f1; +create table t1 (id numeric, warehouse_id numeric); +create view v1 as select id from t1; +create view v2 as +select t1.warehouse_id, v1.id as receipt_id +from t1, v1 where t1.id = v1.id; +insert into t1 (id, warehouse_id) values(3, 2); +insert into t1 (id, warehouse_id) values(4, 2); +insert into t1 (id, warehouse_id) values(5, 1); +select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2 +order by v2.receipt_id; +alias1 alias2 +3 3 +4 4 +5 5 +drop view v2, v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 6d2afb908a4..718e1a9932b 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2319,3 +2319,22 @@ CREATE VIEW v2 AS SELECT f1(); select * from v2; drop view v2,v1; drop function f1; + +# +# Bug#14861: aliased column names are not preserved. +# +create table t1 (id numeric, warehouse_id numeric); +create view v1 as select id from t1; +create view v2 as +select t1.warehouse_id, v1.id as receipt_id +from t1, v1 where t1.id = v1.id; + +insert into t1 (id, warehouse_id) values(3, 2); +insert into t1 (id, warehouse_id) values(4, 2); +insert into t1 (id, warehouse_id) values(5, 1); + +select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2 +order by v2.receipt_id; + +drop view v2, v1; +drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9b5b4b90ccb..1485f88610a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8189,7 +8189,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, uint convert_blob_length) { Item::Type orig_type= type; - Item *orig_item; + Item *orig_item= 0; if (type != Item::FIELD_ITEM && item->real_item()->type() == Item::FIELD_ITEM && @@ -8240,10 +8240,12 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, } else result= create_tmp_field_from_field(thd, (*from_field= field->field), - item->name, table, - modify_item ? field : - NULL, - convert_blob_length); + orig_item ? orig_item->name : + item->name, + table, + modify_item ? field : + NULL, + convert_blob_length); if (orig_type == Item::REF_ITEM && orig_modify) ((Item_ref*)orig_item)->set_result_field(result); return result; From f206a123a1035f1faf8ca6fa50a656cb2ece5091 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Mon, 19 Dec 2005 15:52:10 +0400 Subject: [PATCH 052/154] Bug#15581: COALESCE function truncates mutli-byte TINYTEXT values field.cc: BLOB variations have number-in-bytes limit, unlike CHAR/VARCHAR which have number-of-characters limits. A tinyblob column can store up to 255 bytes. In the case of basic Latin letters (which use 1 byte per character) we can store up to 255 characters in a tinyblob column. When passing an utf8 tinyblob column as an argument into a function (e.g. COALESCE) we need to reserve 3*255 bytes. I.e. multiply length in bytes to mbcharlen for the character set. Although in reality a tinyblob column can never be 3*255 bytes long, we need to set max_length to multiply to make fix_length_and_dec() of the function-caller (e.g. COALESCE) calculate the correct max_length for the column being created. ctype_utf8.result, ctype_utf8.test: Adding test case. --- mysql-test/r/ctype_utf8.result | 8 ++++++++ mysql-test/t/ctype_utf8.test | 10 ++++++++++ sql/field.cc | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 03d3ab9f22e..cf9426e6b21 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1070,3 +1070,11 @@ char(a) 1 2 drop table t1; +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +LENGTH(bug) +100 +DROP TABLE t2; +DROP TABLE t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 8c0e03c0cd3..01bffe9492e 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -882,4 +882,14 @@ set names utf8; select distinct char(a) from t1; drop table t1; +# +# Bug#15581: COALESCE function truncates mutli-byte TINYTEXT values +# +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +DROP TABLE t2; +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/field.cc b/sql/field.cc index abb5297f458..b1d9167aee2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6949,11 +6949,11 @@ uint32 Field_blob::max_length() switch (packlength) { case 1: - return 255; + return 255 * field_charset->mbmaxlen; case 2: - return 65535; + return 65535 * field_charset->mbmaxlen; case 3: - return 16777215; + return 16777215 * field_charset->mbmaxlen; case 4: return (uint32) 4294967295U; default: From f9ef0df0d3aaab15b1a7245f8bf6785d24622c86 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Mon, 19 Dec 2005 16:21:02 +0400 Subject: [PATCH 053/154] Fix for bug#14271 I_S: columns has no size for (var)binary columns set character_octet_length, character_maximum_length for binary and varbinary field types --- mysql-test/r/information_schema.result | 7 +++++++ mysql-test/t/information_schema.test | 8 ++++++++ sql/sql_show.cc | 4 +++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 5e34c41dfb2..e8d343ad711 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1067,3 +1067,10 @@ show indexes from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 f1 1 f1 A NULL NULL NULL YES BTREE drop table t1; +create table t1(f1 binary(32), f2 varbinary(64)); +select character_maximum_length, character_octet_length +from information_schema.columns where table_name='t1'; +character_maximum_length character_octet_length +32 32 +64 64 +drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b982047cec7..b05798b781f 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -759,3 +759,11 @@ show columns from t1; describe t1; show indexes from t1; drop table t1; + +# +# Bug#14271 I_S: columns has no size for (var)binary columns +# +create table t1(f1 binary(32), f2 varbinary(64)); +select character_maximum_length, character_octet_length +from information_schema.columns where table_name='t1'; +drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index dc6c141bef7..1b31e8f7dc3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2616,7 +2616,9 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); is_blob= (field->type() == FIELD_TYPE_BLOB); - if (field->has_charset() || is_blob) + if (field->has_charset() || is_blob || + field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type + field->real_type() == MYSQL_TYPE_STRING) // For binary type { longlong char_max_len= is_blob ? (longlong) field->max_length() / field->charset()->mbminlen : From e50c0fdc3b3b042c62df41cc0e7f637126772975 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 20 Dec 2005 00:47:50 +0100 Subject: [PATCH 054/154] Bug #15772 Aborted YaSSL connections force threads into busyloops - Report error when there is nothing to read after wait. --- extra/yassl/src/handshake.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 45dfb6fa032..d7df438b8df 100644 --- a/extra/yassl/src/handshake.cpp +++ b/extra/yassl/src/handshake.cpp @@ -656,7 +656,11 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr buffered) { ssl.getSocket().wait(); // wait for input if blocking uint ready = ssl.getSocket().get_ready(); - if (!ready) return buffered; + if (!ready) { + // Nothing to receive after blocking wait => error + ssl.SetError(receive_error); + return buffered= null_buffer; + } // add buffered data if its there uint buffSz = buffered.get() ? buffered.get()->get_size() : 0; From 7d6f1e470944f944c24a7980ec00442f9b88d504 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 21 Dec 2005 00:18:58 +1100 Subject: [PATCH 055/154] build fix --- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 733d0fc9951..6bb499eff18 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -11020,7 +11020,7 @@ void Dbdih::initCommonData() ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas); if (cnoReplicas > 4) { - progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, + progError(__LINE__, ERR_INVALID_CONFIG, "Only up to four replicas are supported. Check NoOfReplicas."); } From 90bbcc9b4ddb1a3a69c1dba7fe6a2fc8d38d5c20 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 20 Dec 2005 15:34:58 +0100 Subject: [PATCH 056/154] Store the each column from a multi column result set into a separate variable. --- client/mysqltest.c | 68 +++++++++++++++++++++++++++-------- mysql-test/r/mysqltest.result | 19 ++++++++++ mysql-test/t/mysqltest.test | 36 +++++++++++++++++++ 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 7ba8dc31405..e709dc64ef4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1137,26 +1137,50 @@ static void do_exec(struct st_query *query) DBUG_VOID_RETURN; } +/* + Set variable from the result of a query -int var_query_set(VAR* v, const char *p, const char** p_end) + SYNOPSIS + var_query_set() + var variable to set from query + query start of query string to execute + query_end end of the query string to execute + + + DESCRIPTION + let @ = `` + + Execute the query and assign the first row of result to var as + a tab separated strings + + Also assign each column of the result set to + variable "$_" + Thus the tab separated output can be read from $ and + and each individual column can be read as $_ + +*/ + +int var_query_set(VAR* var, const char *query, const char** query_end) { - char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p)); + char* end = (char*)((query_end && *query_end) ? + *query_end : query + strlen(query)); MYSQL_RES *res; MYSQL_ROW row; MYSQL* mysql = &cur_con->mysql; LINT_INIT(res); - while (end > p && *end != '`') + while (end > query && *end != '`') --end; - if (p == end) + if (query == end) die("Syntax error in query, missing '`'"); - ++p; + ++query; - if (mysql_real_query(mysql, p, (int)(end - p)) || + if (mysql_real_query(mysql, query, (int)(end - query)) || !(res = mysql_store_result(mysql))) { *end = 0; - die("Error running query '%s': %s", p, mysql_error(mysql)); + die("Error running query '%s': %d: %s", query, + mysql_errno(mysql) ,mysql_error(mysql)); } if ((row = mysql_fetch_row(res)) && row[0]) @@ -1169,21 +1193,39 @@ int var_query_set(VAR* v, const char *p, const char** p_end) uint i; ulong *lengths; char *end; + MYSQL_FIELD *fields= mysql_fetch_fields(res); init_dynamic_string(&result, "", 16384, 65536); lengths= mysql_fetch_lengths(res); for (i=0; i < mysql_num_fields(res); i++) { if (row[0]) + { + /* Add to _ */ + uint j; + char var_col_name[MAX_VAR_NAME]; + uint length= snprintf(var_col_name, MAX_VAR_NAME, + "$%s_%s", var->name, fields[i].name); + /* Convert characters not allowed in variable names to '_' */ + for (j= 1; j < length; j++) + { + if (!my_isvar(charset_info,var_col_name[j])) + var_col_name[j]= '_'; + } + var_set(var_col_name, var_col_name + length, + row[i], row[i] + lengths[i]); + + /* Add column to tab separated string */ dynstr_append_mem(&result, row[i], lengths[i]); + } dynstr_append_mem(&result, "\t", 1); } end= result.str + result.length-1; - eval_expr(v, result.str, (const char**) &end); + eval_expr(var, result.str, (const char**) &end); dynstr_free(&result); } else - eval_expr(v, "", 0); + eval_expr(var, "", 0); mysql_free_result(res); return 0; @@ -4129,12 +4171,10 @@ static VAR *var_init(VAR *v, const char *name, int name_len, const char *val, if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) die("Out of memory"); - memcpy(tmp_var->name, name, name_len); + if (name) + strmake(tmp_var->name, name, name_len); if (val) - { - memcpy(tmp_var->str_val, val, val_len); - tmp_var->str_val[val_len]=0; - } + strmake(tmp_var->str_val, val, val_len); tmp_var->name_len = name_len; tmp_var->str_val_len = val_len; tmp_var->alloced_len = val_alloc_len; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 0109436fac9..bf3821555cc 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -222,6 +222,25 @@ mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Variable name in =hi does not start with '$' mysqltest: At line 1: Missing assignment operator in let +var1 +hi 1 hi there +hi +1 +hi there +var2 +2 + + +var2 again +2 + +2 + +var3 two columns with same name +1 2 3 +2 +2 +3 mysqltest: At line 1: Missing file name in source mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 3d851605823..ae28a66c685 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -539,6 +539,42 @@ echo $novar1; --error 1 --exec echo "let hi;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test to assign let from query +# let $=``; +# ---------------------------------------------------------------------------- + +echo var1; +let $var1= `select "hi" as "Col", 1 as "Column1", "hi there" as Col3`; +echo $var1; +echo $var1_Col; +echo $var1_Column1; +echo $var1_Col3; + +echo var2; +let $var2= `select 2 as "Column num 2"`; +echo $var2; +echo $var2_Column num 2; +echo $var2_Column; + +echo var2 again; +let $var2= `select 2 as "Column num 2"`; +echo $var2; +echo $var2_Column num 2; +echo $var2_Column_num_2; +echo $var2_Column; + +echo var3 two columns with same name; +let $var3= `select 1 as "Col", 2 as "Col", 3 as "var3"`; +echo $var3; +echo $var3_Col; +echo $var3_Col; +echo $var3_var3; + +#echo failing query in let; +#--error 1 +#--exec echo "let $var2= `failing query;`" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- # Test source command # ---------------------------------------------------------------------------- From b0e84cb99913024ca6a1b1023c859e3ba2b7bac5 Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Tue, 20 Dec 2005 16:35:05 +0100 Subject: [PATCH 057/154] BUG#5390 - problems with merge tables Problem #1: INSERT...SELECT, Version for 5.0. Extended the unique table check by a check of lock data. Merge sub-tables cannot be detected by doing name checks only. --- mysql-test/r/create.result | 15 ----- mysql-test/r/merge.result | 49 ++++++++++++++ mysql-test/t/create.test | 7 -- mysql-test/t/merge.test | 26 ++++++++ sql/lock.cc | 128 ++++++++++++++++++++++++++++++++++++- sql/mysql_priv.h | 4 +- sql/sql_base.cc | 10 +-- sql/sql_delete.cc | 4 +- sql/sql_insert.cc | 4 +- sql/sql_load.cc | 2 +- sql/sql_parse.cc | 4 +- sql/sql_update.cc | 7 +- 12 files changed, 219 insertions(+), 41 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index c981d3092a7..7dabdfe0ef5 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -259,21 +259,6 @@ select * from t1; 0 1 2 0 0 1 drop table t1; -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; -Warnings: -Note 1050 Table 't1' already exists -create table if not exists t1 select 1,2,3,4; -ERROR 21S01: Column count doesn't match value count at row 1 -create table if not exists t1 select 1; -Warnings: -Note 1050 Table 't1' already exists -select * from t1; -1 2 3 -1 2 3 -0 1 2 -0 0 1 -drop table t1; create table t1 (a int not null, b int, primary key (a)); insert into t1 values (1,1); create table if not exists t1 select 2; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index e028e58acf5..7e3ccc83d73 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -719,3 +719,52 @@ SELECT b FROM t2; b 3 DROP TABLE t1, t2; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +a +1 +2 +insert t2 select * from t2; +select * from t2; +a +2 +2 +insert t3 select * from t1; +select * from t3; +a +1 +1 +2 +2 +insert t1 select * from t3; +select * from t1; +a +1 +1 +1 +1 +2 +2 +select * from t2; +a +2 +2 +select * from t3; +a +1 +1 +1 +1 +2 +2 +2 +2 +check table t1, t2; +Table Op Msg_type Msg_text +test.t1 check status OK +test.t2 check status OK +drop table t1, t2, t3; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 6f3bc67cb30..4e99b0c4b8b 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -211,13 +211,6 @@ drop table t1; # bug #1434 # -create table t1 select 1,2,3; -create table if not exists t1 select 1,2; ---error 1136 -create table if not exists t1 select 1,2,3,4; -create table if not exists t1 select 1; -select * from t1; -drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; --error 1136 diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index ff05867b7c1..060f1ea167b 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -352,4 +352,30 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3; SELECT b FROM t2; DROP TABLE t1, t2; + +# +# BUG#5390 - problems with merge tables +# Problem #1: INSERT...SELECT +# +#drop table if exists t1, t2, t3; +create table t1(a int); +create table t2(a int); +insert into t1 values (1); +insert into t2 values (2); +create table t3 (a int) engine=merge union=(t1, t2) insert_method=first; +select * from t3; +# +insert t2 select * from t2; +select * from t2; +# +insert t3 select * from t1; +select * from t3; +# +insert t1 select * from t3; +select * from t1; +select * from t2; +select * from t3; +check table t1, t2; +drop table t1, t2, t3; + # End of 4.1 tests diff --git a/sql/lock.cc b/sql/lock.cc index fe8dcb3aa5e..947fa4ea53f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -423,6 +423,127 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) } +/* + Find duplicate lock in tables. + + SYNOPSIS + mysql_lock_have_duplicate() + thd The current thread. + needle The table to check for duplicate lock. + haystack The list of tables to search for the dup lock. + + NOTE + This is mainly meant for MERGE tables in INSERT ... SELECT + situations. The 'real', underlying tables can be found only after + the table is opened. The easier way is to check this after the + tables are locked. + + RETURN + 1 A table from 'tables' matches a lock on 'table'. + 0 No duplicate lock is present. + -1 Error. +*/ + +TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, + TABLE_LIST *haystack) +{ + uint count; + uint dup_pos; + TABLE *write_lock_used; /* dummy */ + TABLE **tables1; + TABLE **tables2; + TABLE **table_ptr; + TABLE_LIST *tlist_ptr; + MYSQL_LOCK *sql_lock1; + MYSQL_LOCK *sql_lock2; + THR_LOCK_DATA **lock_data1; + THR_LOCK_DATA **end_data1; + THR_LOCK_DATA **lock_data2; + THR_LOCK_DATA **end_data2; + THR_LOCK *lock1; + DBUG_ENTER("mysql_lock_have_duplicate"); + + /* Table may not be defined for derived or view tables. */ + if (! needle->table) + DBUG_RETURN(NULL); + + /* Get lock(s) for needle. */ + tables1= &needle->table; + if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used))) + goto err0; + + /* Count real tables in list. */ + count=0; + for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global) + if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table) + count++; + /* Allocate a table array. */ + if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count))) + goto err1; + table_ptr= tables2; + /* Assign table pointers. */ + for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global) + if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table) + *(table_ptr++)= tlist_ptr->table; + /* Get lock(s) for haystack. */ + if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used))) + goto err1; + + /* Initialize duplicate position to an impossible value. */ + dup_pos= UINT_MAX; + /* + Find a duplicate lock. + In case of merge tables, sql_lock1 can have more than 1 lock. + */ + for (lock_data1= sql_lock1->locks, + end_data1= lock_data1 + sql_lock1->lock_count; + lock_data1 < end_data1; + lock_data1++) + { + lock1= (*lock_data1)->lock; + for (lock_data2= sql_lock2->locks, + end_data2= lock_data2 + sql_lock2->lock_count; + lock_data2 < end_data2; + lock_data2++) + { + if ((*lock_data2)->lock == lock1) + { + DBUG_PRINT("ingo", ("duplicate lock found")); + /* Change duplicate position to the real value. */ + dup_pos= lock_data2 - sql_lock2->locks; + goto end; + } + } + } + + end: + tlist_ptr= NULL; /* In case that no duplicate was found. */ + if (dup_pos != UINT_MAX) + { + /* Duplicate found. Search the matching TABLE_LIST object. */ + count= 0; + for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global) + { + if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table) + { + count+= tlist_ptr->table->file->lock_count(); + if (count > dup_pos) + break; + } + } + } + my_free((gptr) sql_lock2, MYF(0)); + my_free((gptr) sql_lock1, MYF(0)); + DBUG_RETURN(tlist_ptr); + + err1: + my_free((gptr) sql_lock1, MYF(0)); + err0: + /* This non-null but special value indicates error, if caller cares. */ + DBUG_RETURN(needle); +} + + /* unlock a set of external */ static int unlock_external(THD *thd, TABLE **table,uint count) @@ -460,6 +581,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, MYSQL_LOCK *sql_lock; THR_LOCK_DATA **locks; TABLE **to; + DBUG_ENTER("get_lock_data"); *write_lock_used=0; for (i=tables=lock_count=0 ; i < count ; i++) @@ -488,7 +610,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, my_malloc(sizeof(*sql_lock)+ sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count, MYF(0)))) - return 0; + DBUG_RETURN(0); locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); to=sql_lock->table=(TABLE**) (locks+tables); sql_lock->table_count=lock_count; @@ -508,7 +630,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias); my_free((gptr) sql_lock,MYF(0)); - return 0; + DBUG_RETURN(0); } } THR_LOCK_DATA **org_locks = locks; @@ -518,7 +640,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, for ( ; org_locks != locks ; org_locks++) (*org_locks)->debug_print_param= (void *) table; } - return sql_lock; + DBUG_RETURN(sql_lock); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3f4ed137a59..ee41acfc6a5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -981,7 +981,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, uint offset_to_list, const char *db_name, const char *table_name); -TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list); +TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list); TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name); bool close_temporary_table(THD *thd, const char *db, const char *table_name); void close_temporary(TABLE *table, bool delete_table); @@ -1269,6 +1269,8 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); +TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, + TABLE_LIST *haystack); bool lock_global_read_lock(THD *thd); void unlock_global_read_lock(THD *thd); bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0e1c1525c9e..92aab055aac 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -698,6 +698,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, SYNOPSIS unique_table() + thd thread handle table table which should be checked table_list list of tables @@ -723,7 +724,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, 0 if table is unique */ -TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list) +TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list) { TABLE_LIST *res; const char *d_name, *t_name; @@ -758,9 +759,10 @@ TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list) DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name)); for (;;) { - if (!(res= find_table_in_global_list(table_list, d_name, t_name)) || - (!res->table || res->table != table->table) && - (res->select_lex && !res->select_lex->exclude_from_table_unique_test)) + if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) && + (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) || + ((!res->table || res->table != table->table) && + res->select_lex && !res->select_lex->exclude_from_table_unique_test)) break; /* If we found entry of this table or or table of SELECT which already diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 983f0931ef9..b77acbcbd2a 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -348,7 +348,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) } { TABLE_LIST *duplicate; - if ((duplicate= unique_table(table_list, table_list->next_global))) + if ((duplicate= unique_table(thd, table_list, table_list->next_global))) { update_non_unique_table_error(table_list, "DELETE", duplicate); DBUG_RETURN(TRUE); @@ -438,7 +438,7 @@ bool mysql_multi_delete_prepare(THD *thd) */ { TABLE_LIST *duplicate; - if ((duplicate= unique_table(target_tbl->correspondent_table, + if ((duplicate= unique_table(thd, target_tbl->correspondent_table, lex->query_tables))) { update_non_unique_table_error(target_tbl->correspondent_table, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8903f28be11..e4d70e8f1bb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -870,7 +870,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, { Item *fake_conds= 0; TABLE_LIST *duplicate; - if ((duplicate= unique_table(table_list, table_list->next_global))) + if ((duplicate= unique_table(thd, table_list, table_list->next_global))) { update_non_unique_table_error(table_list, "INSERT", duplicate); DBUG_RETURN(TRUE); @@ -2171,7 +2171,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) query */ if (!(lex->current_select->options & OPTION_BUFFER_RESULT) && - unique_table(table_list, table_list->next_global)) + unique_table(thd, table_list, table_list->next_global)) { /* Using same table for INSERT and SELECT */ lex->current_select->options|= OPTION_BUFFER_RESULT; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 2a0145af9c7..4f3bfee5d3a 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -178,7 +178,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table is marked to be 'used for insert' in which case we should never mark this table as as 'const table' (ie, one that has only one row). */ - if (unique_table(table_list, table_list->next_global)) + if (unique_table(thd, table_list, table_list->next_global)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); DBUG_RETURN(TRUE); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1428e50253a..a8a60772e47 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2835,7 +2835,7 @@ mysql_execute_command(THD *thd) if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) { TABLE_LIST *duplicate; - if ((duplicate= unique_table(create_table, select_tables))) + if ((duplicate= unique_table(thd, create_table, select_tables))) { update_non_unique_table_error(create_table, "CREATE", duplicate); res= 1; @@ -2851,7 +2851,7 @@ mysql_execute_command(THD *thd) tab= tab->next_local) { TABLE_LIST *duplicate; - if ((duplicate= unique_table(tab, select_tables))) + if ((duplicate= unique_table(thd, tab, select_tables))) { update_non_unique_table_error(tab, "CREATE", duplicate); res= 1; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 94c00036540..e38848bc821 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -616,7 +616,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, /* Check that we are not using table that we are updating in a sub select */ { TABLE_LIST *duplicate; - if ((duplicate= unique_table(table_list, table_list->next_global))) + if ((duplicate= unique_table(thd, table_list, table_list->next_global))) { update_non_unique_table_error(table_list, "UPDATE", duplicate); my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); @@ -839,7 +839,7 @@ reopen_tables: tl->lock_type != TL_READ_NO_INSERT) { TABLE_LIST *duplicate; - if ((duplicate= unique_table(tl, table_list))) + if ((duplicate= unique_table(thd, tl, table_list))) { update_non_unique_table_error(table_list, "UPDATE", duplicate); DBUG_RETURN(TRUE); @@ -1026,8 +1026,7 @@ int multi_update::prepare(List ¬_used_values, { TABLE *table=table_ref->table; if (!(tables_to_update & table->map) && - find_table_in_local_list(update_tables, table_ref->db, - table_ref->table_name)) + unique_table(thd, table_ref, update_tables)) table->no_cache= 1; // Disable row cache } DBUG_RETURN(thd->is_fatal_error != 0); From 94d05ebc375041e656fd282ab9ee717ad61ed443 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 20 Dec 2005 17:06:20 +0100 Subject: [PATCH 058/154] Avoid implicit commits by using a different connection when creating/dropping sp's and views. --- client/mysqltest.c | 74 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index e709dc64ef4..16ae7702857 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -247,6 +247,8 @@ typedef struct struct connection { MYSQL mysql; + /* Used when creating views and sp, to avoid implicit commit */ + MYSQL* util_mysql; char *name; MYSQL_STMT* stmt; }; @@ -551,6 +553,8 @@ static void close_cons() mysql_stmt_close(next_con->stmt); next_con->stmt= 0; mysql_close(&next_con->mysql); + if (next_con->util_mysql) + mysql_close(next_con->util_mysql); my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR)); } DBUG_VOID_RETURN; @@ -1948,6 +1952,9 @@ int close_connection(struct st_query *q) } #endif mysql_close(&con->mysql); + if (con->util_mysql) + mysql_close(con->util_mysql); + con->util_mysql= 0; my_free(con->name, MYF(0)); /* When the connection is closed set name to "closed_connection" @@ -2040,16 +2047,15 @@ void init_manager() 0 - success, non-0 - failure */ -int safe_connect(MYSQL* con, const char *host, const char *user, - const char *pass, - const char *db, int port, const char *sock) +int safe_connect(MYSQL* mysql, const char *host, const char *user, + const char *pass, const char *db, int port, const char *sock) { int con_error= 1; my_bool reconnect= 1; int i; for (i= 0; i < MAX_CON_TRIES; ++i) { - if (mysql_real_connect(con, host,user, pass, db, port, sock, + if (mysql_real_connect(mysql, host,user, pass, db, port, sock, CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) { con_error= 0; @@ -2061,7 +2067,7 @@ int safe_connect(MYSQL* con, const char *host, const char *user, TODO: change this to 0 in future versions, but the 'kill' test relies on existing behavior */ - mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect); + mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); return con_error; } @@ -2305,10 +2311,10 @@ int do_connect(struct st_query *q) con_db= 0; if (q->abort_on_error) { - if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass, - con_db, con_port, con_sock ? con_sock: 0))) - die("Could not open connection '%s': %s", con_name, - mysql_error(&next_con->mysql)); + if (safe_connect(&next_con->mysql, con_host, con_user, con_pass, + con_db, con_port, con_sock ? con_sock: 0)) + die("Could not open connection '%s': %d %s", con_name, + mysql_errno(&next_con->mysql), mysql_error(&next_con->mysql)); } else error= connect_n_handle_errors(q, &next_con->mysql, con_host, con_user, @@ -3785,6 +3791,39 @@ end: } + +/* + Create a util connection if one does not already exists + and use that to run the query + This is done to avoid implict commit when creating/dropping objects such + as view, sp etc. +*/ + +static int util_query(MYSQL* org_mysql, const char* query){ + + MYSQL* mysql; + DBUG_ENTER("util_query"); + + if(!(mysql= cur_con->util_mysql)) + { + DBUG_PRINT("info", ("Creating util_mysql")); + if (!(mysql= mysql_init(mysql))) + die("Failed in mysql_init()"); + + if (safe_connect(mysql, org_mysql->host, org_mysql->user, + org_mysql->passwd, org_mysql->db, org_mysql->port, + org_mysql->unix_socket)) + die("Could not open util connection: %d %s", + mysql_errno(mysql), mysql_error(mysql)); + + cur_con->util_mysql= mysql; + } + + return mysql_query(mysql, query); +} + + + /* Run query @@ -3865,7 +3904,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ", query_len+64, 256); dynstr_append_mem(&query_str, query, query_len); - if (mysql_query(mysql, query_str.str)) + if (util_query(mysql, query_str.str)) { /* Failed to create the view, this is not fatal @@ -3892,7 +3931,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) Collect warnings from create of the view that should otherwise have been produced when the SELECT was executed */ - append_warnings(&ds_warnings, mysql); + append_warnings(&ds_warnings, cur_con->util_mysql); } dynstr_free(&query_str); @@ -3909,12 +3948,12 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) */ DYNAMIC_STRING query_str; init_dynamic_string(&query_str, - "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;\n", + "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;", query_len+64, 256); - mysql_query(mysql, query_str.str); + util_query(mysql, query_str.str); dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n"); dynstr_append_mem(&query_str, query, query_len); - if (mysql_query(mysql, query_str.str)) + if (util_query(mysql, query_str.str)) { /* Failed to create the stored procedure for this query, @@ -3958,13 +3997,13 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) if (sp_created) { - if (mysql_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) + if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); } if (view_created) { - if (mysql_query(mysql, "DROP VIEW mysqltest_tmp_v ")) + if (util_query(mysql, "DROP VIEW mysqltest_tmp_v ")) die("Failed to drop view: %d: %s", mysql_errno(mysql), mysql_error(mysql)); } @@ -4299,7 +4338,8 @@ int main(int argc, char **argv) die("Out of memory"); if (safe_connect(&cur_con->mysql, host, user, pass, db, port, unix_sock)) - die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql)); + die("Could not open connection '%s': %d %s", cur_con->name, + mysql_errno(&cur_con->mysql), mysql_error(&cur_con->mysql)); init_var_hash(&cur_con->mysql); From 1b106bf4fcb4b816b77f8e1391fd56841cad5786 Mon Sep 17 00:00:00 2001 From: "paul@snake-hub.snake.net" <> Date: Tue, 20 Dec 2005 12:42:35 -0600 Subject: [PATCH 059/154] errmsg.txt: Fix typo. --- sql/share/errmsg.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index efa7860f251..185b4326c5c 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5375,7 +5375,7 @@ ER_WSAS_FAILED eng "WSAStartup Failed" ger "WSAStartup fehlgeschlagen" ER_DIFF_GROUPS_PROC - eng "Can't handle procedures with differents groups yet" + eng "Can't handle procedures with different groups yet" ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten" ER_NO_GROUP_FOR_PROC eng "Select must have a group with this procedure" From f5cc3fd619f524c2c7a8d880ac1152d68875eaf9 Mon Sep 17 00:00:00 2001 From: "paul@snake-hub.snake.net" <> Date: Tue, 20 Dec 2005 12:47:44 -0600 Subject: [PATCH 060/154] mysql.cc: Typo in help message. --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index 14a27413687..d76195535a3 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -254,7 +254,7 @@ static COMMANDS commands[] = { { "quit", 'q', com_quit, 0, "Quit mysql." }, { "rehash", '#', com_rehash, 0, "Rebuild completion hash." }, { "source", '.', com_source, 1, - "Execute a SQL script file. Takes a file name as an argument."}, + "Execute an SQL script file. Takes a file name as an argument."}, { "status", 's', com_status, 0, "Get status information from the server."}, #ifdef USE_POPEN { "system", '!', com_shell, 1, "Execute a system shell command."}, From 9dceb4f32ea02d021b48d7dceb6795a366ebe6ce Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Wed, 21 Dec 2005 15:19:11 +0100 Subject: [PATCH 061/154] BUG#15842: Change in "item.cc" adding Item_sp_variable breaks compile on HP-UX 11.23 Fix: make explicit conversion to non-constant string (char *). Backported from 5.1 changeset 1.1968 05/12/19 17:36:20 kent@mysql.com +2 -0 --- sql/item.cc | 2 +- sql/sql_trigger.cc | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 659970f2a91..210e5014f44 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -949,7 +949,7 @@ void Item_splocal::print(String *str) *****************************************************************************/ Item_case_expr::Item_case_expr(int case_expr_id) - :Item_sp_variable(STRING_WITH_LEN("case_expr")), + :Item_sp_variable((char *) STRING_WITH_LEN("case_expr")), m_case_expr_id(case_expr_id) { } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 779b044696e..55f8d4801bd 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -21,7 +21,7 @@ #include "parse_file.h" static const LEX_STRING triggers_file_type= - {STRING_WITH_LEN("TRIGGERS")}; + {(char *) STRING_WITH_LEN("TRIGGERS")}; const char * const triggers_file_ext= ".TRG"; @@ -34,17 +34,17 @@ const char * const triggers_file_ext= ".TRG"; static File_option triggers_file_parameters[]= { { - {STRING_WITH_LEN("triggers") }, + {(char *) STRING_WITH_LEN("triggers") }, offsetof(class Table_triggers_list, definitions_list), FILE_OPTIONS_STRLIST }, { - {STRING_WITH_LEN("sql_modes") }, + {(char *) STRING_WITH_LEN("sql_modes") }, offsetof(class Table_triggers_list, definition_modes_list), FILE_OPTIONS_ULLLIST }, { - {STRING_WITH_LEN("definers") }, + {(char *) STRING_WITH_LEN("definers") }, offsetof(class Table_triggers_list, definers_list), FILE_OPTIONS_STRLIST }, @@ -71,7 +71,7 @@ struct st_trigname }; static const LEX_STRING trigname_file_type= - {STRING_WITH_LEN("TRIGGERNAME")}; + {(char *) STRING_WITH_LEN("TRIGGERNAME")}; const char * const trigname_file_ext= ".TRN"; @@ -82,7 +82,7 @@ static File_option trigname_file_parameters[]= FIXME: Length specified for "trigger_table" key is erroneous, problem caused by this are reported as BUG#14090 and should be fixed ASAP. */ - {STRING_WITH_LEN("trigger_table")}, + {(char *) STRING_WITH_LEN("trigger_table")}, offsetof(struct st_trigname, trigger_table), FILE_OPTIONS_ESTRING }, @@ -1236,7 +1236,7 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, (char *)path, "TRIGGER"); File_option sql_modes_parameters= { - {STRING_WITH_LEN("sql_modes") }, + {(char *) STRING_WITH_LEN("sql_modes") }, offsetof(class Table_triggers_list, definition_modes_list), FILE_OPTIONS_ULLLIST }; From 1d4ab650f014f1c0c9c5b155af81e614c8613686 Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Wed, 21 Dec 2005 16:31:58 +0100 Subject: [PATCH 062/154] bug#15908 - ndb When scan is completed, but lqhkeyreq is outstanding on primary replica and starting node dies, scan will not be closed leading to error handling of failed node not completing --- ndb/src/kernel/blocks/ERROR_codes.txt | 4 +++- ndb/src/kernel/blocks/dblqh/DblqhMain.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 5d7c8d758fc..62481837c14 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -3,7 +3,7 @@ Next NDBCNTR 1000 Next NDBFS 2000 Next DBACC 3002 Next DBTUP 4013 -Next DBLQH 5042 +Next DBLQH 5043 Next DBDICT 6006 Next DBDIH 7174 Next DBTC 8037 @@ -312,6 +312,8 @@ LQH: 5026 Crash when receiving COPY_ACTIVEREQ 5027 Crash when receiving STAT_RECREQ +5042 Crash starting node, when scan is finished on primary replica + Test Crashes in handling take over ---------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index fc6a470e0ef..c8460630d62 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -9220,6 +9220,15 @@ void Dblqh::nextScanConfCopyLab(Signal* signal) // completion. Signal completion through scanCompletedStatus-flag. /*---------------------------------------------------------------------------*/ scanptr.p->scanCompletedStatus = ZTRUE; + scanptr.p->scanState = ScanRecord::WAIT_LQHKEY_COPY; + if (ERROR_INSERTED(5042)) + { + CLEAR_ERROR_INSERT_VALUE; + tcConnectptr.p->copyCountWords = ~0; + signal->theData[0] = 9999; + sendSignal(numberToRef(CMVMI, scanptr.p->scanNodeId), + GSN_NDB_TAMPER, signal, 1, JBA); + } return; }//if From 4e37b62ff92383ceae3420a2bd0d74842c9a3205 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Wed, 21 Dec 2005 18:50:06 +0100 Subject: [PATCH 063/154] Increment the version number to 5.0.19 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index b3d4a587bea..b5c31361b26 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.18) +AM_INIT_AUTOMAKE(mysql, 5.0.19) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -18,7 +18,7 @@ SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=18 +NDB_VERSION_BUILD=19 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From e5281df9f7e11c5f7913496835048c6f6b79d753 Mon Sep 17 00:00:00 2001 From: "paul@frost.snake.net" <> Date: Thu, 22 Dec 2005 13:02:53 -0600 Subject: [PATCH 064/154] mysqltest.c: Put options in order. Add #ifdef around --debug for non-debug builds. --- client/mysqltest.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index ba1b92b31a3..3a4ce5ce7cf 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2731,10 +2731,8 @@ end: static struct my_option my_long_options[] = { - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test, @@ -2742,13 +2740,17 @@ static struct my_option my_long_options[] = {"compress", 'C', "Use the compressed server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef DBUG_OFF + {"debug", '#', "This is a non-debug version. Catch this and exit", + 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#else + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.", - (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0, - 0, 0, 0, 0, 0}, {"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.", (gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -2757,6 +2759,9 @@ static struct my_option my_long_options[] = {"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.", (gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG, MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0}, + {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.", + (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0, + 0, 0, 0, 0, 0}, {"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT, "Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout, (gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0}, From 7f843ffe870c71b1dce84a267af580ddadfa33be Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Fri, 23 Dec 2005 14:20:00 +0400 Subject: [PATCH 065/154] ctype_uca.result, ctype_uca.test: Adding test case. charset-def.c: Initialize new collation. ctype-uca.c: Adding simplified Hungarian collation. --- mysql-test/r/ctype_uca.result | 106 ++++++++++++++++++++++++++++++++++ mysql-test/t/ctype_uca.test | 1 + mysys/charset-def.c | 4 ++ strings/ctype-uca.c | 73 +++++++++++++++++++++++ 4 files changed, 184 insertions(+) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 4b245c69d2a..3e286c77c00 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2015,6 +2015,112 @@ Z,z,Ź,ź,Å»,ż,Ž,ž Ç Ç‚ ǃ +select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci; +group_concat(c1 order by c1) +÷ +× +A,a,À,Ã,Â,Ã,Ä,Ã…,à,á,â,ã,ä,Ã¥,Ä€,Ä,Ä‚,ă,Ä„,Ä…,Ç,ÇŽ,Çž,ÇŸ,Ç ,Ç¡,Ǻ,Ç» +AA,Aa,aA,aa +Æ,æ,Ç¢,Ç£,Ǽ,ǽ +B,b +Æ€ +Æ +Æ‚,ƃ +C,c,Ç,ç,Ć,ć,Ĉ,ĉ,ÄŠ,Ä‹,ÄŒ,Ä +CH,Ch,cH,ch +Ƈ,ƈ +D,d,ÄŽ,Ä +DZ,Dz,dZ,dz,Ç„,Ç…,dž,DZ,Dz,dz +Ä,Ä‘ +Ɖ +ÆŠ +Æ‹,ÆŒ +Ã,ð +E,e,È,É,Ê,Ë,è,é,ê,ë,Ä’,Ä“,Ä”,Ä•,Ä–,Ä—,Ę,Ä™,Äš,Ä› +ÆŽ,Ç +Æ +Æ +F,f +Æ‘,Æ’ +G,g,Äœ,Ä,Äž,ÄŸ,Ä ,Ä¡,Ä¢,Ä£,Ǧ,ǧ,Ç´,ǵ +Ǥ,Ç¥ +Æ“ +Æ” +Æ¢,Æ£ +H,h,Ĥ,Ä¥ +Æ•,Ƕ +Ħ,ħ +I,i,ÃŒ,Ã,ÃŽ,Ã,ì,í,î,ï,Ĩ,Ä©,Ī,Ä«,Ĭ,Ä­,Ä®,į,İ,Ç,Ç +IJ,Ij,iJ,ij,IJ,ij +ı +Æ— +Æ– +J,j,Ä´,ĵ,ǰ +K,k,Ķ,Ä·,Ǩ,Ç© +Ƙ,Æ™ +L,l,Ĺ,ĺ,Ä»,ļ,Ľ,ľ +Ä¿,Å€ +LJ,Lj,lJ,lj,LJ,Lj,lj +LL,Ll,lL,ll +Å,Å‚ +Æš +Æ› +M,m +N,n,Ñ,ñ,Ń,Å„,Å…,ņ,Ň,ň,Ǹ,ǹ +NJ,Nj,nJ,nj,ÇŠ,Ç‹,ÇŒ +Æ +Æž +ÅŠ,Å‹ +O,o,Ã’,Ó,Ô,Õ,ò,ó,ô,õ,ÅŒ,Å,ÅŽ,Å,Æ ,Æ¡,Ç‘,Ç’,Ǫ,Ç«,Ǭ,Ç­ +OE,Oe,oE,oe,Å’,Å“ +Ö,ö,Å,Å‘ +Ø,ø,Ǿ,Ç¿ +Ɔ +ÆŸ +P,p +Ƥ,Æ¥ +Q,q +ĸ +R,r,Å”,Å•,Å–,Å—,Ř,Å™ +RR,Rr,rR,rr +Ʀ +S,s,Åš,Å›,Åœ,Å,Åž,ÅŸ,Å ,Å¡,Å¿ +SS,Ss,sS,ss,ß +Æ© +ƪ +T,t,Å¢,Å£,Ť,Å¥ +ƾ +Ŧ,ŧ +Æ« +Ƭ,Æ­ +Æ® +U,u,Ù,Ú,Û,ù,ú,û,Ũ,Å©,Ū,Å«,Ŭ,Å­,Å®,ů,Ų,ų,Ư,ư,Ç“,Ç”,Ç•,Ç–,Ç—,ǘ,Ç™,Çš,Ç›,Çœ +Ü,ü,Ű,ű +Æœ +Ʊ +V,v +Ʋ +W,w,Å´,ŵ +X,x +Y,y,Ã,ý,ÿ,Ŷ,Å·,Ÿ +Ƴ,Æ´ +Z,z,Ź,ź,Å»,ż,Ž,ž +Æ +Ƶ,ƶ +Æ·,Ç®,ǯ +Ƹ,ƹ +ƺ +Þ,þ +Æ¿,Ç· +Æ» +Ƨ,ƨ +Ƽ,ƽ +Æ„,Æ… +ʼn +Ç€ +Ç +Ç‚ +ǃ drop table t1; SET NAMES utf8; CREATE TABLE t1 (c varchar(255) NOT NULL COLLATE utf8_general_ci, INDEX (c)); diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 6d8713f4910..3e49b9de883 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -212,6 +212,7 @@ select group_concat(c1 order by c1) from t1 group by c1 collate utf8_slovak_ci; select group_concat(c1 order by c1) from t1 group by c1 collate utf8_spanish2_ci; select group_concat(c1 order by c1) from t1 group by c1 collate utf8_roman_ci; select group_concat(c1 order by c1) from t1 group by c1 collate utf8_esperanto_ci; +select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci; drop table t1; diff --git a/mysys/charset-def.c b/mysys/charset-def.c index 5b30d1ee135..0559fe59d06 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -43,6 +43,7 @@ extern CHARSET_INFO my_charset_ucs2_spanish2_uca_ci; extern CHARSET_INFO my_charset_ucs2_roman_uca_ci; extern CHARSET_INFO my_charset_ucs2_persian_uca_ci; extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci; +extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci; #endif #ifdef HAVE_CHARSET_utf8 @@ -64,6 +65,7 @@ extern CHARSET_INFO my_charset_utf8_spanish2_uca_ci; extern CHARSET_INFO my_charset_utf8_roman_uca_ci; extern CHARSET_INFO my_charset_utf8_persian_uca_ci; extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci; +extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci; #ifdef HAVE_UTF8_GENERAL_CS extern CHARSET_INFO my_charset_utf8_general_cs; #endif @@ -151,6 +153,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_roman_uca_ci); add_compiled_collation(&my_charset_ucs2_persian_uca_ci); add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci); + add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci); #endif #endif @@ -184,6 +187,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_roman_uca_ci); add_compiled_collation(&my_charset_utf8_persian_uca_ci); add_compiled_collation(&my_charset_utf8_esperanto_uca_ci); + add_compiled_collation(&my_charset_utf8_hungarian_uca_ci); #endif #endif diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 4768e42a0b0..b18e5ee59d2 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -6705,6 +6705,14 @@ static const char esperanto[]= "& S < \\u015d <<< \\u015c" "& U < \\u016d <<< \\u016c"; +/* + A simplified version of Hungarian, without consonant contractions. +*/ +static const char hungarian[]= + "&O < \\u00F6 <<< \\u00D6 << \\u0151 <<< \\u0150" + "&U < \\u00FC <<< \\u00DC << \\u0171 <<< \\u0170"; + + /* Unicode Collation Algorithm: Collation element (weight) scanner, @@ -8627,6 +8635,39 @@ CHARSET_INFO my_charset_ucs2_esperanto_uca_ci= }; +CHARSET_INFO my_charset_ucs2_hungarian_uca_ci= +{ + 146,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "ucs2", /* cs name */ + "ucs2_hungarian_ci",/* name */ + "", /* comment */ + hungarian, /* tailoring */ + NULL, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 2, /* mbminlen */ + 2, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_ucs2_handler, + &my_collation_ucs2_uca_handler +}; + + #endif @@ -9252,6 +9293,38 @@ CHARSET_INFO my_charset_utf8_esperanto_uca_ci= &my_collation_any_uca_handler }; +CHARSET_INFO my_charset_utf8_hungarian_uca_ci= +{ + 210,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE, + "utf8", /* cs name */ + "utf8_hungarian_ci",/* name */ + "", /* comment */ + hungarian, /* tailoring */ + ctype_utf8, /* ctype */ + NULL, /* to_lower */ + NULL, /* to_upper */ + NULL, /* sort_order */ + NULL, /* contractions */ + NULL, /* sort_order_big*/ + NULL, /* tab_to_uni */ + NULL, /* tab_from_uni */ + my_unicase_default, /* caseinfo */ + NULL, /* state_map */ + NULL, /* ident_map */ + 8, /* strxfrm_multiply */ + 1, /* caseup_multiply */ + 1, /* casedn_multiply */ + 1, /* mbminlen */ + 3, /* mbmaxlen */ + 9, /* min_sort_char */ + 0xFFFF, /* max_sort_char */ + ' ', /* pad char */ + 0, /* escape_with_backslash_is_dangerous */ + &my_charset_utf8_handler, + &my_collation_any_uca_handler +}; + #endif /* HAVE_CHARSET_utf8 */ #endif /* HAVE_UCA_COLLATIONS */ From 7b049bf2cd050d07713b51b67a0c015066c1f6ae Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 23 Dec 2005 12:38:22 +0100 Subject: [PATCH 066/154] correct help text --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cc9bec35242..7b9e7d54d8f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4370,7 +4370,7 @@ Disable with --skip-bdb (will save memory).", {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, - "Don't use client side character set value sent during handshake.", + "Don't ignore client side character set value sent during handshake.", (gptr*) &opt_character_set_client_handshake, (gptr*) &opt_character_set_client_handshake, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, From c0638190759a616adc447207e18c155c81132ee9 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 23 Dec 2005 20:50:28 +0100 Subject: [PATCH 067/154] locking issues, test for LONGLONG_MIN in decimal.c --- myisam/mi_create.c | 5 +++-- mysys/thr_alarm.c | 26 +++++++++-------------- server-tools/instance-manager/instance.cc | 3 +++ strings/decimal.c | 7 +++--- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 6d4106afda5..1a17febe94a 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -72,7 +72,6 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, } LINT_INIT(dfile); LINT_INIT(file); - pthread_mutex_lock(&THR_LOCK_myisam); errpos=0; options=0; bzero((byte*) &share,sizeof(share)); @@ -135,7 +134,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, pack_reclength++; min_pack_length++; /* We must test for 257 as length includes pack-length */ - if (test(rec->length >= 257)) + if (test(rec->length >= 257)) { long_varchar_count++; pack_reclength+= 2; /* May be packed on 3 bytes */ @@ -542,6 +541,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if (! (flags & HA_DONT_TOUCH_DATA)) share.state.create_time= (long) time((time_t*) 0); + pthread_mutex_lock(&THR_LOCK_myisam); + if (ci->index_file_name) { fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4); diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index e5b77de5e38..41914080a9d 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -401,7 +401,7 @@ void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); if (alarm_aborted != 1) /* If memory not freed */ - { + { pthread_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); alarm_aborted= -1; /* mark aborted */ @@ -415,13 +415,10 @@ void end_thr_alarm(my_bool free_structures) if (free_structures) { struct timespec abstime; - /* - The following test is just for safety, the caller should not - depend on this - */ - DBUG_ASSERT(!alarm_queue.elements); - /* Wait until alarm thread dies */ + DBUG_ASSERT(!alarm_queue.elements); + + /* Wait until alarm thread dies */ set_timespec(abstime, 10); /* Wait up to 10 seconds */ while (alarm_thread_running) { @@ -429,16 +426,13 @@ void end_thr_alarm(my_bool free_structures) if (error == ETIME || error == ETIMEDOUT) break; /* Don't wait forever */ } - if (!alarm_queue.elements) + delete_queue(&alarm_queue); + alarm_aborted= 1; + pthread_mutex_unlock(&LOCK_alarm); + if (!alarm_thread_running) /* Safety */ { - delete_queue(&alarm_queue); - alarm_aborted= 1; - pthread_mutex_unlock(&LOCK_alarm); - if (!alarm_thread_running) /* Safety */ - { - pthread_mutex_destroy(&LOCK_alarm); - pthread_cond_destroy(&COND_alarm); - } + pthread_mutex_destroy(&LOCK_alarm); + pthread_cond_destroy(&COND_alarm); } } else diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index 3d54d000d5f..3d04403f830 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -255,7 +255,10 @@ static void start_and_monitor_instance(Instance_options *old_instance_options, log_info("starting instance %s", instance_name_buff); if (start_process(old_instance_options, &process_info)) + { + instance_map->unlock(); return; /* error is logged */ + } /* allow users to delete instances */ instance_map->unlock(); diff --git a/strings/decimal.c b/strings/decimal.c index 0c1f03016e0..5fb37d374a2 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1069,9 +1069,9 @@ int decimal2longlong(decimal_t *from, longlong *to) } } /* boundary case: 9223372036854775808 */ - if (unlikely(from->sign==0 && x < 0 && -x < 0)) + if (unlikely(from->sign==0 && x == LONGLONG_MIN)) { - *to= -1-x; + *to= LONGLONG_MAX; return E_DEC_OVERFLOW; } @@ -2675,7 +2675,8 @@ void test_pr(const char *s1, int prec, int dec, char filler, const char *orig, int slen= sizeof(s2); int res; - sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); + sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'", + s1, prec, dec, filler); end= strend(s1); string2decimal(s1, &a, &end); res= decimal2string(&a, s2, &slen, prec, dec, filler); From d5d6b51422cdaf785eaad49e8e528b55211694c4 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sat, 24 Dec 2005 14:32:50 +0100 Subject: [PATCH 068/154] remove "defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)" unmaintainably scattered all over the source --- include/config-netware.h | 3 ++- sql/ha_archive.cc | 2 +- sql/handler.cc | 6 +++--- sql/mysqld.cc | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/config-netware.h b/include/config-netware.h index 7def0053bf2..f517e3c34d3 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -72,9 +72,10 @@ extern "C" { #undef HAVE_CRYPT #endif /* HAVE_OPENSSL */ -/* Configure can't detect this because it uses AC_TRY_RUN */ +/* Netware has an ancient zlib */ #undef HAVE_COMPRESS #define HAVE_COMPRESS +#undef HAVE_ARCHIVE_DB /* include the old function apis */ #define USE_OLD_FUNCTIONS 1 diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 2747f678cc3..c60d40c2685 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -20,7 +20,7 @@ #include "mysql_priv.h" -#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) +#if defined(HAVE_ARCHIVE_DB) #include "ha_archive.h" #include diff --git a/sql/handler.cc b/sql/handler.cc index 47010de3002..4c60f460a23 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -60,7 +60,7 @@ handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HTON_NO_FLAGS }; #endif -#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) +#if defined(HAVE_ARCHIVE_DB) #include "ha_archive.h" extern handlerton archive_hton; #else @@ -314,7 +314,7 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type) case DB_TYPE_EXAMPLE_DB: return new (alloc) ha_example(table); #endif -#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) +#if defined(HAVE_ARCHIVE_DB) case DB_TYPE_ARCHIVE_DB: return new (alloc) ha_archive(table); #endif @@ -513,7 +513,7 @@ int ha_panic(enum ha_panic_function flag) if (have_federated_db == SHOW_OPTION_YES) error|= federated_db_end(); #endif -#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) +#if defined(HAVE_ARCHIVE_DB) if (have_archive_db == SHOW_OPTION_YES) error|= archive_db_end(); #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index aaa467603f5..2705615111a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6323,7 +6323,7 @@ static void mysql_init_variables(void) #else have_example_db= SHOW_OPTION_NO; #endif -#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__) +#if defined(HAVE_ARCHIVE_DB) have_archive_db= SHOW_OPTION_YES; #else have_archive_db= SHOW_OPTION_NO; From 14384b840168f8cedfda0ec728e7d406b1b515bb Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Tue, 27 Dec 2005 02:01:58 +0200 Subject: [PATCH 069/154] Avoiding conditional jump on uninitialized variable (BUG#14904). --- mysys/my_copy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 072492172e3..2fb022a25f2 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -53,7 +53,7 @@ struct utimbuf { int my_copy(const char *from, const char *to, myf MyFlags) { uint Count; - my_bool new_file_stat; /* 1 if we could stat "to" */ + my_bool new_file_stat= 0; /* 1 if we could stat "to" */ int create_flag; File from_file,to_file; char buff[IO_SIZE]; @@ -62,7 +62,6 @@ int my_copy(const char *from, const char *to, myf MyFlags) DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags)); from_file=to_file= -1; - LINT_INIT(new_file_stat); DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */ if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */ new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0))); From cb25f0f039f48c5c29e9a6f74e0dcc6a71d52e75 Mon Sep 17 00:00:00 2001 From: "stewart@mysql.com" <> Date: Wed, 28 Dec 2005 01:32:03 +1100 Subject: [PATCH 070/154] 5.0 ndb build fix. --- ndb/src/kernel/blocks/dbdih/DbdihMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index ebfb46c7043..2a28c4db770 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -11137,7 +11137,7 @@ void Dbdih::initCommonData() ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas); if (cnoReplicas > 4) { - progError(__LINE__, ERR_INVALID_CONFIG, + progError(__LINE__, NDBD_EXIT_INVALID_CONFIG, "Only up to four replicas are supported. Check NoOfReplicas."); } From a4fc69dbfb7574c2e11be3cb8309ec0d064e2548 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Tue, 27 Dec 2005 16:57:50 +0100 Subject: [PATCH 071/154] ndb - wl#2972 (5.0) fix detached trigger opType + new pgm test_event_merge --- ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp | 2 + ndb/src/ndbapi/NdbEventOperationImpl.cpp | 2 +- ndb/test/ndbapi/Makefile.am | 5 +- ndb/test/ndbapi/test_event_merge.cpp | 1286 +++++++++++++++++++ 4 files changed, 1293 insertions(+), 2 deletions(-) create mode 100644 ndb/test/ndbapi/test_event_merge.cpp diff --git a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index 470b98fd04c..e16d3df6d8d 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -445,6 +445,7 @@ Dbtup::commitRecord(Signal* signal, befOpPtr.p->changeMask.bitOR(attributeMask); befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; checkDetachedTriggers(signal, befOpPtr.p, @@ -483,6 +484,7 @@ Dbtup::commitRecord(Signal* signal, befOpPtr.p->pageIndex = befOpPtr.p->pageIndexC; befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; checkDetachedTriggers(signal, befOpPtr.p, diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 208525bfc15..9c147be9f16 100644 --- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -250,10 +250,10 @@ NdbEventOperationImpl::execute() int hasSubscriber; int r= m_bufferHandle->prepareAddSubscribeEvent(this, hasSubscriber /*return value*/); - m_error.code= 4709; if (r < 0) { + m_error.code= 4709; DBUG_RETURN(-1); } diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am index d83e9614eb5..0533493ba09 100644 --- a/ndb/test/ndbapi/Makefile.am +++ b/ndb/test/ndbapi/Makefile.am @@ -35,7 +35,8 @@ testPartitioning \ testBitfield \ DbCreate DbAsyncGenerator \ test_event_multi_table \ -testSRBank +testSRBank \ +test_event_merge #flexTimedAsynch #testBlobs @@ -80,6 +81,7 @@ DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterfa DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp test_event_multi_table_SOURCES = test_event_multi_table.cpp testSRBank_SOURCES = testSRBank.cpp +test_event_merge_SOURCES = test_event_merge.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel @@ -160,3 +162,4 @@ testScan.dsp: Makefile \ @$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES) @$(top_srcdir)/ndb/config/win-sources $@ $(testScan_SOURCES) @$(top_srcdir)/ndb/config/win-libraries $@ LINK $(LDADD) + diff --git a/ndb/test/ndbapi/test_event_merge.cpp b/ndb/test/ndbapi/test_event_merge.cpp new file mode 100644 index 00000000000..1332455cdc5 --- /dev/null +++ b/ndb/test/ndbapi/test_event_merge.cpp @@ -0,0 +1,1286 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include +#include +#include + +#if NDB_VERSION_D < MAKE_VERSION(5, 1, 0) +#define version50 +#else +#undef version50 +#endif + +#if !defined(min) || !defined(max) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +/* + * Test composite operations on same PK via events. The merge of event + * data can happen in 2 places: + * + * 1) In TUP at commit, the detached triggers report a single composite + * operation and its post/pre data + * + * 2) In event API version >= 5.1 separate commits within same GCI are + * by default merged. This is required to read blob data via NdbBlob. + * + * This test program ignores Blob columns in version 5.0. + * + * There are 5 ways (ignoring NUL operand) to compose 2 ops: + * 5.0 bugs 5.1 bugs + * INS o DEL = NUL + * INS o UPD = INS 5.1 + * DEL o INS = UPD type=INS 5.1 + * UPD o DEL = DEL no event + * UPD o UPD = UPD + */ + +struct Opts { + my_bool abort_on_error; + int loglevel; + uint loop; + uint maxops; + uint maxpk; + const char* opstr; + uint seed; + my_bool separate_events; + my_bool use_table; +}; + +static Opts g_opts; +static const uint g_maxops = 10000; +static const uint g_maxpk = 100; + +static Ndb_cluster_connection* g_ncc = 0; +static Ndb* g_ndb = 0; +static NdbDictionary::Dictionary* g_dic = 0; +static NdbTransaction* g_con = 0; +static NdbOperation* g_op = 0; + +static const char* g_tabname = "tem1"; +static const char* g_evtname = "tem1ev1"; +static const uint g_charlen = 5; +static const char* g_csname = "latin1_swedish_ci"; + +static const NdbDictionary::Table* g_tab = 0; +static const NdbDictionary::Event* g_evt = 0; + +static NdbEventOperation* g_evt_op = 0; + +static uint +urandom(uint n) +{ + uint r = (uint)random(); + if (n != 0) + r = r % n; + return r; +} + +static int& g_loglevel = g_opts.loglevel; // default log level + +#define chkdb(x) \ + do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; errdb(); if (g_opts.abort_on_error) abort(); return -1; } while (0) + +#define chkrc(x) \ + do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; if (g_opts.abort_on_error) abort(); return -1; } while (0) + +#define reqrc(x) \ + do { if (x) break; ndbout << "line " << __LINE__ << " ASSERT " << #x << endl; abort(); } while (0) + +#define ll0(x) \ + do { if (g_loglevel < 0) break; ndbout << x << endl; } while (0) + +#define ll1(x) \ + do { if (g_loglevel < 1) break; ndbout << x << endl; } while (0) + +#define ll2(x) \ + do { if (g_loglevel < 2) break; ndbout << x << endl; } while (0) + +static void +errdb() +{ + uint any = 0; + if (g_ndb != 0) { + const NdbError& e = g_ndb->getNdbError(); + if (e.code != 0) + ll0(++any << " ndb: error " << e); + } + if (g_dic != 0) { + const NdbError& e = g_dic->getNdbError(); + if (e.code != 0) + ll0(++any << " dic: error " << e); + } + if (g_con != 0) { + const NdbError& e = g_con->getNdbError(); + if (e.code != 0) + ll0(++any << " con: error " << e); + } + if (g_op != 0) { + const NdbError& e = g_op->getNdbError(); + if (e.code != 0) + ll0(++any << " op: error " << e); + } + if (g_evt_op != 0) { + const NdbError& e = g_evt_op->getNdbError(); + if (e.code != 0) + ll0(++any << " evt_op: error " << e); + } + if (! any) + ll0("unknown db error"); +} + +struct Col { + uint no; + const char* name; + NdbDictionary::Column::Type type; + bool pk; + bool nullable; + uint length; + uint size; +}; + +static Col g_col[] = { + { 0, "pk1", NdbDictionary::Column::Unsigned, true, false, 1, 4 }, + { 1, "pk2", NdbDictionary::Column::Char, true, false, g_charlen, g_charlen }, + { 2, "seq", NdbDictionary::Column::Unsigned, false, false, 1, 4 }, + { 3, "cc1", NdbDictionary::Column::Char, false, true, g_charlen, g_charlen } +}; + +static const uint g_ncol = sizeof(g_col)/sizeof(g_col[0]); + +static const Col& +getcol(uint i) +{ + if (i < g_ncol) + return g_col[i]; + assert(false); + return g_col[g_ncol]; +} + +static const Col& +getcol(const char* name) +{ + uint i; + for (i = 0; i < g_ncol; i++) + if (strcmp(g_col[i].name, name) == 0) + break; + return getcol(i); +} + +static int +createtable() +{ + g_tab = 0; + NdbDictionary::Table tab(g_tabname); + tab.setLogging(false); + CHARSET_INFO* cs; + chkrc((cs = get_charset_by_name(g_csname, MYF(0))) != 0); + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = g_col[i]; + NdbDictionary::Column col(c.name); + col.setType(c.type); + col.setPrimaryKey(c.pk); + if (! c.pk) + col.setNullable(true); + col.setLength(c.length); + switch (c.type) { + case NdbDictionary::Column::Unsigned: + break; + case NdbDictionary::Column::Char: + col.setLength(c.length); + col.setCharset(cs); + break; + default: + assert(false); + break; + } + tab.addColumn(col); + } + g_dic = g_ndb->getDictionary(); + if (! g_opts.use_table) { + if (g_dic->getTable(g_tabname) != 0) + chkdb(g_dic->dropTable(g_tabname) == 0); + chkdb(g_dic->createTable(tab) == 0); + } + chkdb((g_tab = g_dic->getTable(g_tabname)) != 0); + g_dic = 0; + if (! g_opts.use_table) { + // extra row for GCI probe + chkdb((g_con = g_ndb->startTransaction()) != 0); + chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0); + chkdb(g_op->insertTuple() == 0); + Uint32 pk1; + char pk2[g_charlen]; + pk1 = g_maxpk; + memset(pk2, 0x20, g_charlen); + chkdb(g_op->equal("pk1", (char*)&pk1) == 0); + chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0); + chkdb(g_con->execute(Commit) == 0); + g_ndb->closeTransaction(g_con); + g_op = 0; + g_con = 0; + } + return 0; +} + +static int +droptable() +{ + if (! g_opts.use_table) { + g_dic = g_ndb->getDictionary(); + chkdb(g_dic->dropTable(g_tab->getName()) == 0); + g_tab = 0; + g_dic = 0; + } + return 0; +} + +struct Data { + Uint32 pk1; + char pk2[g_charlen]; + Uint32 seq; + char cc1[g_charlen]; + void* ptr[g_ncol]; + int ind[g_ncol]; // -1 = no data, 1 = NULL, 0 = not NULL + void init() { + uint i; + pk1 = 0; + memset(pk2, 0, sizeof(pk2)); + seq = 0; + memset(cc1, 0, sizeof(cc1)); + ptr[0] = &pk1; + ptr[1] = pk2; + ptr[2] = &seq; + ptr[3] = cc1; + for (i = 0; i < g_ncol; i++) + ind[i] = -1; + } +}; + +static NdbOut& +operator<<(NdbOut& out, const Data& d) +{ + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = getcol(i); + out << (i == 0 ? "" : " ") << c.name << "="; + if (d.ind[i] == -1) + continue; + if (d.ind[i] == 1) { + out << "NULL"; + continue; + } + switch (c.type) { + case NdbDictionary::Column::Unsigned: + out << *(Uint32*)d.ptr[i]; + break; + case NdbDictionary::Column::Char: + { + char buf[g_charlen + 1]; + memcpy(buf, d.ptr[i], g_charlen); + uint n = g_charlen; + while (1) { + buf[n] = 0; + if (n == 0 || buf[n - 1] != 0x20) + break; + n--; + } + out << buf; + } + break; + default: + out << "?"; + break; + } + } + return out; +} + +static const uint g_optypes = 3; // real ops 0-2 + +/* + * Represents single or composite operation or received event. The + * post/pre data is either computed here for operations or received from + * the event. + */ +struct Op { // single or composite + enum Kind { OP = 1, EV = 2 }; + enum Type { NUL = -1, INS, DEL, UPD }; + Kind kind; + Type type; + Op* next_op; // within one commit + Op* next_com; // next commit chain or next event + uint num_op; + uint num_com; + Data data[2]; // 0-post 1-pre + bool match; // matched to event + void init() { + assert(kind == OP || kind == EV); + type = NUL; + next_op = next_com = 0; + num_op = num_com = 0; + data[0].init(); + data[1].init(); + match = false; + } +}; + +static NdbOut& +operator<<(NdbOut& out, Op::Type t) +{ + switch (t) { + case Op::NUL: + out << "NUL"; + break; + case Op::INS: + out << "INS"; + break; + case Op::DEL: + out << "DEL"; + break; + case Op::UPD: + out << "UPD"; + break; + default: + out << (int)t; + break; + } + return out; +} + +static NdbOut& +operator<<(NdbOut& out, const Op& op) +{ + out << "t=" << op.type; + out << " " << op.data[0]; + out << " [" << op.data[1] << "]"; + return out; +} + +static int +seteventtype(Op* ev, NdbDictionary::Event::TableEvent te) +{ + Op::Type t = Op::NUL; + switch (te) { + case NdbDictionary::Event::TE_INSERT: + t = Op::INS; + break; + case NdbDictionary::Event::TE_DELETE: + t = Op::DEL; + break; + case NdbDictionary::Event::TE_UPDATE: + t = Op::UPD; + break; + default: + ll0("EVT: " << *ev << ": bad event type" << (int)te); + return -1; + } + ev->type = t; + return 0; +} + +static uint g_usedops = 0; +static uint g_usedevs = 0; +static Op g_oplist[g_maxops]; +static Op g_evlist[g_maxops]; +static uint g_maxcom = 8; // max ops per commit + +static Op* g_pk_op[g_maxpk]; +static Op* g_pk_ev[g_maxpk]; +static uint g_seq = 0; + +static NdbRecAttr* g_ra[2][g_ncol]; // 0-post 1-pre +static Op* g_rec_ev; +static uint g_ev_cnt[g_maxpk]; + +static uint +getfreeops() +{ + assert(g_opts.maxops >= g_usedops); + return g_opts.maxops - g_usedops; +} + +static uint +getfreeevs() +{ + assert(g_opts.maxops >= g_usedevs); + return g_opts.maxops - g_usedevs; +} + +static Op* +getop() +{ + if (g_usedops < g_opts.maxops) { + Op* op = &g_oplist[g_usedops++]; + op->kind = Op::OP; + op->init(); + return op; + } + assert(false); + return 0; +} + +static Op* +getev() +{ + if (g_usedevs < g_opts.maxops) { + Op* ev = &g_evlist[g_usedevs++]; + ev->kind = Op::EV; + ev->init(); + return ev; + } + assert(false); + return 0; +} + +static void +resetmem() +{ + int i, j; + for (j = 0; j < 2; j++) + for (i = 0; i < g_ncol; i++) + g_ra[j][i] = 0; + g_rec_ev = 0; + for (i = 0; i < g_opts.maxpk; i++) + g_pk_op[i] = 0; + for (i = 0; i < g_opts.maxpk; i++) + g_ev_cnt[i] = 0; + g_seq = 0; + g_usedops = 0; + g_usedevs = 0; +} + +struct Comp { + Op::Type t1, t2, t3; +}; + +static Comp +g_comp[] = { + { Op::INS, Op::DEL, Op::NUL }, + { Op::INS, Op::UPD, Op::INS }, + { Op::DEL, Op::INS, Op::UPD }, + { Op::UPD, Op::DEL, Op::DEL }, + { Op::UPD, Op::UPD, Op::UPD } +}; + +static const uint g_ncomp = sizeof(g_comp)/sizeof(g_comp[0]); + +static int +checkop(const Op* op, Uint32& pk1) +{ + const Data (&d)[2] = op->data; + Op::Type t = op->type; + chkrc(t == Op::NUL || t == Op::INS || t == Op::DEL || t == Op::UPD); + { const Col& c = getcol("pk1"); + chkrc(d[0].ind[c.no] == 0); + pk1 = d[0].pk1; + chkrc(pk1 < g_opts.maxpk); + } + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = getcol(i); + if (t != Op::NUL) { + if (c.pk) { + chkrc(d[0].ind[i] == 0); // even DEL has PK in post data + if (t == Op::INS) { + chkrc(d[1].ind[i] == -1); + } else if (t == Op::DEL) { +#ifdef ndb_event_cares_about_pk_pre_data + chkrc(d[1].ind[i] == -1); +#endif + } else { +#ifdef ndb_event_cares_about_pk_pre_data + chkrc(d[1].ind[i] == 0); +#endif + } + } else { + if (t == Op::INS) { + chkrc(d[0].ind[i] >= 0); + chkrc(d[1].ind[i] == -1); + } else if (t == Op::DEL) { + chkrc(d[0].ind[i] == -1); + chkrc(d[1].ind[i] >= 0); + } else if (op->kind == Op::OP) { + chkrc(d[0].ind[i] >= 0); + chkrc(d[1].ind[i] >= 0); + } + } + } + } + return 0; +} + +static Comp* +comptype(Op::Type t1, Op::Type t2) // only non-NUL +{ + uint i; + for (i = 0; i < g_ncomp; i++) + if (g_comp[i].t1 == t1 && g_comp[i].t2 == t2) + return &g_comp[i]; + return 0; +} + +static void +copycol(const Col& c, const Data& d1, Data& d3) +{ + if ((d3.ind[c.no] = d1.ind[c.no]) != -1) + memmove(d3.ptr[c.no], d1.ptr[c.no], c.size); +} + +static void +copykeys(const Data& d1, Data& d3) +{ + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = g_col[i]; + if (c.pk) + copycol(c, d1, d3); + } +} + +static void +copydata(const Data& d1, Data& d3) +{ + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = g_col[i]; + copycol(c, d1, d3); + } +} + +static void +copyop(const Op* op1, Op* op3) +{ + op3->type = op1->type; + copydata(op1->data[0], op3->data[0]); + copydata(op1->data[1], op3->data[1]); + Uint32 pk1_tmp; + reqrc(checkop(op3, pk1_tmp) == 0); +} + +// not needed for ops +static void +compdata(const Data& d1, const Data& d2, Data& d3) // d2 overrides d1 +{ + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = g_col[i]; + const Data* d = 0; + if (d1.ind[i] == -1 && d2.ind[i] == -1) + d3.ind[i] = -1; + else if (d1.ind[i] == -1 && d2.ind[i] != -1) + d = &d2; + else if (d1.ind[i] != -1 && d2.ind[i] == -1) + d = &d1; + else + d = &d2; + if (d != 0) + copycol(c, *d, d3); + } +} + +static int +compop(const Op* op1, const Op* op2, Op* op3) // op1 o op2 = op3 +{ + Comp* comp; + if (op2->type == Op::NUL) { + copyop(op1, op3); + return 0; + } + if (op1->type == Op::NUL) { + copyop(op2, op3); + return 0; + } + chkrc((comp = comptype(op1->type, op2->type)) != 0); + op3->type = comp->t3; + copykeys(op2->data[0], op3->data[0]); + if (op3->type != Op::DEL) + copydata(op2->data[0], op3->data[0]); + if (op3->type != Op::INS) + copydata(op1->data[1], op3->data[1]); + Uint32 pk1_tmp; + reqrc(checkop(op3, pk1_tmp) == 0); + // not eliminating identical post-pre fields + return 0; +} + +static int +createevent() +{ + ll1("createevent"); + g_evt = 0; + g_dic = g_ndb->getDictionary(); + NdbDictionary::Event evt(g_evtname); + evt.setTable(*g_tab); + evt.addTableEvent(NdbDictionary::Event::TE_ALL); + // pk always + evt.addEventColumn("pk1"); + evt.addEventColumn("pk2"); + // simple cols + evt.addEventColumn("seq"); + evt.addEventColumn("cc1"); + if (g_dic->getEvent(evt.getName()) != 0) + chkdb(g_dic->dropEvent(evt.getName()) == 0); + chkdb(g_dic->createEvent(evt) == 0); + chkdb((g_evt = g_dic->getEvent(evt.getName())) != 0); + g_dic = 0; + return 0; +} + +static int +dropevent() +{ + ll1("dropevent"); + g_dic = g_ndb->getDictionary(); + chkdb(g_dic->dropEvent(g_evt->getName()) == 0); + g_evt = 0; + g_dic = 0; + return 0; +} + +static int +createeventop() +{ + ll1("createeventop"); +#ifdef version50 + uint bsz = 10 * g_opts.maxops; + chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName(), bsz)) != 0); +#else + chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName())) != 0); +#endif + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = g_col[i]; + Data (&d)[2] = g_rec_ev->data; + switch (c.type) { + case NdbDictionary::Column::Unsigned: + case NdbDictionary::Column::Char: + chkdb((g_ra[0][i] = g_evt_op->getValue(c.name, (char*)d[0].ptr[i])) != 0); + chkdb((g_ra[1][i] = g_evt_op->getPreValue(c.name, (char*)d[1].ptr[i])) != 0); + break; + default: + assert(false); + break; + } + } + return 0; +} + +static int +dropeventop() +{ + ll1("dropeventop"); + chkdb(g_ndb->dropEventOperation(g_evt_op) == 0); + g_evt_op = 0; + return 0; +} + +static int +waitgci() // wait for event to be installed and for at least 1 GCI to pass +{ + const uint ngci = 3; + ll1("waitgci " << ngci); + Uint32 gci[2]; + uint i = 0; + while (1) { + chkdb((g_con = g_ndb->startTransaction()) != 0); + { // forced to exec a dummy op + Uint32 pk1; + char pk2[g_charlen]; + pk1 = g_maxpk; + memset(pk2, 0x20, g_charlen); + chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0); + chkdb(g_op->readTuple() == 0); + chkdb(g_op->equal("pk1", (char*)&pk1) == 0); + chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0); + chkdb(g_con->execute(Commit) == 0); + g_op = 0; + } + gci[i] = g_con->getGCI(); + g_ndb->closeTransaction(g_con); + g_con = 0; + if (i == 1 && gci[0] + ngci <= gci[1]) { + ll1("waitgci: " << gci[0] << " " << gci[1]); + break; + } + i = 1; + } + return 0; +} + +static int +makeop(Op* op, Uint32 pk1, Op::Type t, const Op* prev_op) +{ + op->type = t; + if (t != Op::INS) + copydata(prev_op->data[0], op->data[1]); + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = getcol(i); + Data (&d)[2] = op->data; + if (i == getcol("pk1").no) { + d[0].pk1 = pk1; + d[0].ind[i] = 0; + continue; + } + if (i == getcol("pk2").no) { + sprintf(d[0].pk2, "%-*u", g_charlen, d[0].pk1); + d[0].ind[i] = 0; + continue; + } + if (t == Op::DEL) { + d[0].ind[i] = -1; + continue; + } + if (i == getcol("seq").no) { + d[0].seq = g_seq++; + d[0].ind[i] = 0; + continue; + } + uint u; + u = urandom(100); + if (c.nullable && u < 20) { + d[0].ind[i] = 1; + continue; + } + switch (c.type) { + case NdbDictionary::Column::Unsigned: + { + u = urandom(0); + Uint32* p = (Uint32*)d[0].ptr[i]; + *p = u; + } + break; + case NdbDictionary::Column::Char: + { + u = urandom(g_charlen); + char* p = (char*)d[0].ptr[i]; + uint j; + for (j = 0; j < g_charlen; j++) { + uint v = urandom(3); + p[j] = j < u ? "abcde"[v] : 0x20; + } + } + break; + default: + assert(false); + break; + } + d[0].ind[i] = 0; + } + Uint32 pk1_tmp = ~(Uint32)0; + chkrc(checkop(op, pk1_tmp) == 0); + reqrc(pk1 == pk1_tmp); + return 0; +} + +static void +makeop(Op* tot_op, Op* com_op, Uint32 pk1, Op::Type t) +{ + Op tmp_op; + tmp_op.kind = Op::OP; + Op* op = getop(); + reqrc(makeop(op, pk1, t, tot_op) == 0); + // add to end + Op* last_op = com_op; + while (last_op->next_op != 0) + last_op = last_op->next_op; + last_op->next_op = op; + // merge into chain head + tmp_op.init(); + reqrc(compop(com_op, op, &tmp_op) == 0); + copyop(&tmp_op, com_op); + // merge into total op + tmp_op.init(); + reqrc(compop(tot_op, op, &tmp_op) == 0); + copyop(&tmp_op, tot_op); + // counts + com_op->num_op += 1; + tot_op->num_op += 1; +} + +static void +makeops() +{ + ll1("makeops"); + uint resv = g_opts.opstr == 0 ? 2 * g_opts.maxpk : 0; // for final deletes + uint next = g_opts.opstr == 0 ? g_maxcom : strlen(g_opts.opstr); + Op tmp_op; + tmp_op.kind = Op::OP; + Uint32 pk1 = 0; + while (getfreeops() >= resv + 2 + next && pk1 < g_opts.maxpk) { + if (g_opts.opstr == 0) + pk1 = urandom(g_opts.maxpk); + ll2("makeops: pk1=" << pk1 << " free=" << getfreeops()); + // total op on the pk so far + // optype either NUL=initial/deleted or INS=created + Op* tot_op = g_pk_op[pk1]; + if (tot_op == 0) + tot_op = g_pk_op[pk1] = getop(); //1 + assert(tot_op->type == Op::NUL || tot_op->type == Op::INS); + // add new commit chain to end + Op* last_com = tot_op; + while (last_com->next_com != 0) + last_com = last_com->next_com; + Op* com_op = getop(); //2 + last_com->next_com = com_op; + // length of random chain + uint len = ~0; + if (g_opts.opstr == 0) + len = 1 + urandom(g_maxcom - 1); + ll2("makeops: com chain"); + uint n = 0; + while (1) { + // random or from g_opts.opstr + Op::Type t; + if (g_opts.opstr == 0) { + if (n == len) + break; + do { + t = (Op::Type)urandom(g_optypes); + } while (tot_op->type == Op::NUL && (t == Op::DEL || t == Op::UPD) || + tot_op->type == Op::INS && t == Op::INS); + } else { + uint m = strlen(g_opts.opstr); + uint k = tot_op->num_com + tot_op->num_op; + assert(k < m); + char c = g_opts.opstr[k]; + if (c == 'c') { + if (k + 1 == m) + pk1 += 1; + break; + } + const char* p = "idu"; + const char* q = strchr(p, c); + assert(q != 0); + t = (Op::Type)(q - p); + } + makeop(tot_op, com_op, pk1, t); + assert(tot_op->type == Op::NUL || tot_op->type == Op::INS); + n++; + } + tot_op->num_com += 1; + } + assert(getfreeops() >= resv); + // terminate with DEL if necessary + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + Op* tot_op = g_pk_op[pk1]; + if (tot_op == 0) + continue; + if (tot_op->type == Op::NUL) + continue; + assert(g_opts.opstr == 0); + Op* last_com = tot_op; + while (last_com->next_com != 0) + last_com = last_com->next_com; + Op* com_op = getop(); //1 + last_com->next_com = com_op; + makeop(tot_op, com_op, pk1, Op::DEL); + assert(tot_op->type == Op::NUL); + tot_op->num_com += 1; + } +} + +static int +addndbop(Op* op) +{ + chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0); + switch (op->type) { + case Op::INS: + chkdb(g_op->insertTuple() == 0); + break; + case Op::DEL: + chkdb(g_op->deleteTuple() == 0); + break; + case Op::UPD: + chkdb(g_op->updateTuple() == 0); + break; + default: + assert(false); + break; + } + uint i; + for (i = 0; i < g_ncol; i++) { + const Col& c = getcol(i); + const Data& d = op->data[0]; + if (! c.pk) + continue; + chkdb(g_op->equal(c.name, (char*)d.ptr[i]) == 0); + } + if (op->type != Op::DEL) { + for (i = 0; i < g_ncol; i++) { + const Col& c = getcol(i); + const Data& d = op->data[0]; + if (c.pk) + continue; + if (d.ind[i] == -1) + continue; + const char* ptr = d.ind[i] == 0 ? (char*)d.ptr[i] : 0; + chkdb(g_op->setValue(c.name, ptr) == 0); + } + } + g_op = 0; + return 0; +} + +static int +runops() +{ + ll1("runops"); + Uint32 pk1; + const Op* com_op[g_maxpk]; + uint left = 0; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + com_op[pk1] = 0; + // total op on the pk + Op* tot_op = g_pk_op[pk1]; + if (tot_op == 0) + continue; + // first commit chain + assert(tot_op->next_com != 0); + com_op[pk1] = tot_op->next_com; + left++; + } + while (left != 0) { + pk1 = urandom(g_opts.maxpk); + if (com_op[pk1] == 0) + continue; + // do the ops in one transaction + ll2("runops: pk1=" << pk1); + chkdb((g_con = g_ndb->startTransaction()) != 0); + // first op in chain + Op* op = com_op[pk1]->next_op; + assert(op != 0); + while (op != 0) { + ll2("add op:" << *op); + chkrc(addndbop(op) == 0); + op = op->next_op; + } + chkdb(g_con->execute(Commit) == 0); + g_ndb->closeTransaction(g_con); + g_con = 0; + // next chain + com_op[pk1] = com_op[pk1]->next_com; + if (com_op[pk1] == 0) { + assert(left != 0); + left--; + } + } + assert(left == 0); + return 0; +} + +static int +matchevent(Op* ev) +{ + Op::Type t = ev->type; + Data (&d)[2] = ev->data; + // get PK + Uint32 pk1 = d[0].pk1; + chkrc(pk1 < g_opts.maxpk); + // on error repeat and print details + uint loop = 0; + while (loop <= 1) { + uint g_loglevel = loop == 0 ? g_opts.loglevel : 2; + ll1("matchevent: pk1=" << pk1 << " type=" << t); + ll2("EVT: " << *ev); + Op* tot_op = g_pk_op[pk1]; + Op* com_op = tot_op ? tot_op->next_com : 0; + uint cnt = 0; + bool ok = false; + while (com_op != 0) { + ll2("COM: " << *com_op); + Op* op = com_op->next_op; + assert(op != 0); + while (op != 0) { + ll2("---: " << *op); + op = op->next_op; + } + if (com_op->type != Op::NUL) { + if (com_op->type == t) { + const Data (&d2)[2] = com_op->data; + if (t == Op::INS && d2[0].seq == d[0].seq || + t == Op::DEL && d2[1].seq == d[1].seq || + t == Op::UPD && d2[0].seq == d[0].seq) { + if (cnt == g_ev_cnt[pk1]) { + if (! com_op->match) { + ll2("match pos " << cnt); + ok = com_op->match = true; + } else { + ll2("duplicate match"); + } + } else { + ll2("match bad pos event=" << g_ev_cnt[pk1] << " op=" << cnt); + } + } + } + cnt++; + } + com_op = com_op->next_com; + } + if (ok) + return 0; + ll2("no match"); + if (g_loglevel >= 2) + return -1; + loop++; + } + return 0; +} + +static int +matchevents() +{ + uint nomatch = 0; + Uint32 pk1; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + Op* tot_ev = g_pk_ev[pk1]; + if (tot_ev == 0) + continue; + Op* com_ev = tot_ev->next_com; + while (com_ev != 0) { + if (matchevent(com_ev) < 0) + nomatch++; + g_ev_cnt[pk1]++; + com_ev = com_ev->next_com; + } + } + chkrc(nomatch == 0); + return 0; +} + +static int +matchops() +{ + Uint32 pk1; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + Op* tot_op = g_pk_op[pk1]; + if (tot_op == 0) + continue; + Op* com_op = tot_op->next_com; + while (com_op != 0) { + if (com_op->type != Op::NUL && ! com_op->match) { + ll0("COM: " << *com_op); + Op* op = com_op->next_op; + assert(op != 0); + while (op != 0) { + ll0("---: " << *op); + op = op->next_op; + } + ll0("no matching event"); + return -1; + } + com_op = com_op->next_com; + } + } + return 0; +} + +static int +runevents() +{ + ll1("runevents"); + NdbEventOperation* evt_op; + uint npoll = 3; + while (npoll != 0) { + npoll--; + int ret; + ll1("poll"); + ret = g_ndb->pollEvents(1000); + if (ret <= 0) + continue; + while (1) { + g_rec_ev->init(); + Data (&d)[2] = g_rec_ev->data; +#ifdef version50 + int overrun = g_opts.maxops; + chkdb((ret = g_evt_op->next(&overrun)) >= 0); + chkrc(overrun == 0); + if (ret == 0) + break; +#else + NdbEventOperation* tmp_op = g_ndb->nextEvent(); + if (tmp_op == 0) + break; + reqrc(g_evt_op == tmp_op); +#endif + chkrc(seteventtype(g_rec_ev, g_evt_op->getEventType()) == 0); + // get indicators + { int i, j; + for (j = 0; j < 2; j++) + for (i = 0; i < g_ncol; i++) + d[j].ind[i] = g_ra[j][i]->isNULL(); + } + ll2("runevents: EVT: " << *g_rec_ev); + // check basic sanity + Uint32 pk1 = ~(Uint32)0; + chkrc(checkop(g_rec_ev, pk1) == 0); + // add to events + chkrc(getfreeevs() >= 2); + Op* tot_ev = g_pk_ev[pk1]; + if (tot_ev == 0) + tot_ev = g_pk_ev[pk1] = getev(); //1 + Op* last_com = tot_ev; + while (last_com->next_com != 0) + last_com = last_com->next_com; + // copy and add + Op* ev = getev(); //3 + copyop(g_rec_ev, ev); + last_com->next_com = ev; + } + } + chkrc(matchevents() == 0); + chkrc(matchops() == 0); + return 0; +} + +static void +setseed(int n) +{ + uint seed; + if (n == -1) { + if (g_opts.seed == 0) + return; + if (g_opts.seed != -1) + seed = (uint)g_opts.seed; + else + seed = 1 + (ushort)getpid(); + } else { + if (g_opts.seed != 0) + return; + seed = n; + } + ll0("seed=" << seed); + srandom(seed); +} + +static int +runtest() +{ + setseed(-1); + chkrc(createtable() == 0); + chkrc(createevent() == 0); + uint n; + for (n = 0; n < g_opts.loop; n++) { + ll0("loop " << n); + setseed(n); + resetmem(); + g_rec_ev = getev(); + chkrc(createeventop() == 0); + chkdb(g_evt_op->execute() == 0); + chkrc(waitgci() == 0); + makeops(); + chkrc(runops() == 0); + chkrc(runevents() == 0); + chkrc(dropeventop() == 0); + } + chkrc(dropevent() == 0); + chkrc(droptable() == 0); + return 0; +} + +NDB_STD_OPTS_VARS; + +static struct my_option +my_long_options[] = +{ + NDB_STD_OPTS("test_event_merge"), + { "abort-on-error", 1008, "Do abort() on any error", + (gptr*)&g_opts.abort_on_error, (gptr*)&g_opts.abort_on_error, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "loglevel", 1001, "Logging level in this program (default 0)", + (gptr*)&g_opts.loglevel, (gptr*)&g_opts.loglevel, 0, + GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "loop", 1002, "Number of test loops (default 1, 0=forever)", + (gptr*)&g_opts.loop, (gptr*)&g_opts.loop, 0, + GET_INT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0 }, + { "maxops", 1003, "Number of PK operations (default 2000)", + (gptr*)&g_opts.maxops, (gptr*)&g_opts.maxops, 0, + GET_UINT, REQUIRED_ARG, 2000, 0, g_maxops, 0, 0, 0 }, + { "maxpk", 1004, "Number of different PK values (default 10)", + (gptr*)&g_opts.maxpk, (gptr*)&g_opts.maxpk, 0, + GET_UINT, REQUIRED_ARG, 10, 1, g_maxpk, 0, 0, 0 }, + { "opstr", 1005, "Ops to run e.g. idiucdc (c = commit, default random)", + (gptr*)&g_opts.opstr, (gptr*)&g_opts.opstr, 0, + GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "seed", 1006, "Random seed (0=loop number, default -1=random)", + (gptr*)&g_opts.seed, (gptr*)&g_opts.seed, 0, + GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 }, + { "separate-events", 1007, "Do not combine events per GCI >5.0", + (gptr*)&g_opts.separate_events, (gptr*)&g_opts.separate_events, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "use-table", 1008, "Use existing table 'tem1'", + (gptr*)&g_opts.use_table, (gptr*)&g_opts.use_table, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, + 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 } +}; + +static void +usage() +{ + my_print_help(my_long_options); +} + +static int +checkopts() +{ + if (g_opts.opstr != 0) { + const char* s = g_opts.opstr; + uint n = strlen(s); + if (n < 3 || s[0] != 'i' || s[n-2] != 'd' || s[n-1] != 'c') + return -1; + while (*s != 0) + if (strchr("iduc", *s++) == 0) + return -1; + } + return 0; +} + +int +main(int argc, char** argv) +{ + ndb_init(); + const char* progname = + strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]; + uint i; + ndbout << progname; + for (i = 1; i < argc; i++) + ndbout << " " << argv[i]; + ndbout << endl; + int ret; + ret = handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option); + if (ret != 0 || argc != 0 || checkopts() != 0) + return NDBT_ProgramExit(NDBT_WRONGARGS); + g_ncc = new Ndb_cluster_connection(); + if (g_ncc->connect(30) == 0) { + g_ndb = new Ndb(g_ncc, "TEST_DB"); + if (g_ndb->init() == 0 && g_ndb->waitUntilReady(30) == 0) { + if (runtest() == 0) + return NDBT_ProgramExit(NDBT_OK); + } + } + delete g_ndb; + delete g_ncc; + return NDBT_ProgramExit(NDBT_FAILED); +} From d91cbf34ffcb5f91129a8b67347aa0c828a90afd Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Tue, 27 Dec 2005 20:16:59 +0300 Subject: [PATCH 072/154] Fix bug#14583 When InnoDB compares varchar field in ucs2 with given key using bin collation, it calls my_strnncollsp_ucs2_bin() to perform comparison. Because field length was lesser than length of key field should be padded with trailing spaces in order to get correct result. Because my_strnncollsp_ucs2_bin() was calling my_strnncollp_ucs2_bin(), which doesn't pads field, wrong comparison result was returned. This results in wrong result set. my_strnncollsp_ucs2_bin() now compares fields like my_strnncollsp_ucs2 do, but using binary collation. --- mysql-test/r/ctype_ucs.result | 7 ++++++ mysql-test/t/ctype_ucs.test | 8 +++++++ strings/ctype-ucs2.c | 41 +++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 619ad750ff3..3ca56548de9 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -677,3 +677,10 @@ hex(a) 005B 803D drop table t1; +create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB; +insert into t1 values('a'); +create index t1f1 on t1(f1); +select f1 from t1 where f1 like 'a%'; +f1 +a +drop table t1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 2c9e71ddff5..3b3c2c70f32 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -419,4 +419,12 @@ insert into t1 values (0x005b); select hex(a) from t1; drop table t1; +# +# Bug #14583 Bug on query using a LIKE on indexed field with ucs2_bin collation +# +create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB; +insert into t1 values('a'); +create index t1f1 on t1(f1); +select f1 from t1 where f1 like 'a%'; +drop table t1; # End of 4.1 tests diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index ad07fd9903c..d8985a890d9 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1352,11 +1352,48 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs, return t_is_prefix ? (int) (t - te) : (int) ((se-s) - (te-t)); } -static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs, +static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)), const uchar *s, uint slen, const uchar *t, uint tlen) { - return my_strnncoll_ucs2_bin(cs,s,slen,t,tlen,0); + const uchar *se, *te; + uint minlen; + + /* extra safety to make sure the lengths are even numbers */ + slen= (slen >> 1) << 1; + tlen= (tlen >> 1) << 1; + + se= s + slen; + te= t + tlen; + + for (minlen= min(slen, tlen); minlen; minlen-= 2) + { + int s_wc= s[0] * 256 + s[1]; + int t_wc= t[0] * 256 + t[1]; + if ( s_wc != t_wc ) + return s_wc > t_wc ? 1 : -1; + + s+= 2; + t+= 2; + } + + if (slen != tlen) + { + int swap= 1; + if (slen < tlen) + { + s= t; + se= te; + swap= -1; + } + + for ( ; s < se ; s+= 2) + { + if (s[0] || s[1] != ' ') + return (s[0] == 0 && s[1] < ' ') ? -swap : swap; + } + } + return 0; } From 2fb6cb5a5a4d7abbde495c9dc4032c7df76e125b Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 28 Dec 2005 09:23:27 +0100 Subject: [PATCH 073/154] BUG#15775 "drop user" command does not refresh acl_check_hosts - DROP USER command didn't reload the acl_check_hosts cache causing subsequent connect's via TCP to fail randomly. - 4.1 version --- mysql-test/r/grant2.result | 12 ++++++++++++ mysql-test/t/grant2.test | 33 +++++++++++++++++++++++++++++++++ sql/sql_acl.cc | 16 ++++++++++++---- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 6b6bb697306..85963705718 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -131,3 +131,15 @@ lock table mysql.user write; revoke all on *.* from 'mysqltest_1'@'localhost'; unlock tables; drop user 'mysqltest_1'@'localhost'; +insert into mysql.user (user, host) values +('mysqltest_1', 'host1'), +('mysqltest_2', 'host2'), +('mysqltest_3', 'host3'), +('mysqltest_4', 'host4'), +('mysqltest_5', 'host5'), +('mysqltest_6', 'host6'), +('mysqltest_7', 'host7'); +flush privileges; +drop user mysqltest_3@host3; +drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4, +mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7; diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index cb00c41a0ca..79ea7f70712 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -206,4 +206,37 @@ drop user 'mysqltest_1'@'localhost'; disconnect con2root; disconnect con3root; +# +# Bug #15775: "drop user" command does not refresh acl_check_hosts +# + +# Create some test users +insert into mysql.user (user, host) values + ('mysqltest_1', 'host1'), + ('mysqltest_2', 'host2'), + ('mysqltest_3', 'host3'), + ('mysqltest_4', 'host4'), + ('mysqltest_5', 'host5'), + ('mysqltest_6', 'host6'), + ('mysqltest_7', 'host7'); +flush privileges; + +# Drop one user +drop user mysqltest_3@host3; + +# This connect failed before fix since the acl_check_hosts list was corrupted by the "drop user" +connect (con8,127.0.0.1,root,,test,$MASTER_MYPORT,); +disconnect con8; +connection default; + +# Clean up - Drop all of the remaining users at once +drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4, + mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7; + +# Check that it's still possible to connect +connect (con9,127.0.0.1,root,,test,$MASTER_MYPORT,); +disconnect con9; +connection default; + + # End of 4.1 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1ade6ce3064..0ee83424d9f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1151,7 +1151,7 @@ static void init_check_host(void) if (j == acl_wild_hosts.elements) // If new (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host); } - else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host, + else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname, (uint) strlen(acl_user->host.hostname))) { if (my_hash_insert(&acl_check_hosts,(byte*) acl_user)) @@ -3719,17 +3719,25 @@ int mysql_drop_user(THD *thd, List &list) record[0]))) { tables[0].table->file->print_error(error, MYF(0)); - DBUG_RETURN(-1); + result= -1; + goto end; } delete_dynamic_element(&acl_users, acl_userd); } } + if (result) + my_error(ER_DROP_USER, MYF(0)); + +end: + /* Reload acl_check_hosts as its memory is mapped to acl_user */ + delete_dynamic(&acl_wild_hosts); + hash_free(&acl_check_hosts); + init_check_host(); + VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_error(ER_DROP_USER, MYF(0)); DBUG_RETURN(result); } From e1ef24e38ce6426688a5f4ca69bfc5426ce39f9a Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 28 Dec 2005 14:43:50 +0100 Subject: [PATCH 074/154] Bug #15775 "drop user" command does not refresh acl_check_hosts - Update patch for 5.0 - Added common function to be called when 'acl_users' has been modified --- mysql-test/r/grant2.result | 15 +++++++-------- mysql-test/t/grant2.test | 15 +++++++-------- sql/sql_acl.cc | 33 +++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index bda470832b3..246aaa3a93e 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -107,14 +107,13 @@ delete from mysql.columns_priv where user like 'mysqltest\_%'; flush privileges; drop database mysqltest; use test; -insert into mysql.user (user, host) values -('mysqltest_1', 'host1'), -('mysqltest_2', 'host2'), -('mysqltest_3', 'host3'), -('mysqltest_4', 'host4'), -('mysqltest_5', 'host5'), -('mysqltest_6', 'host6'), -('mysqltest_7', 'host7'); +create user mysqltest_1@host1; +create user mysqltest_2@host2; +create user mysqltest_3@host3; +create user mysqltest_4@host4; +create user mysqltest_5@host5; +create user mysqltest_6@host6; +create user mysqltest_7@host7; flush privileges; drop user mysqltest_3@host3; drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4, diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 84820b02ba3..c19bb1482d6 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -161,14 +161,13 @@ use test; # # Create some test users -insert into mysql.user (user, host) values - ('mysqltest_1', 'host1'), - ('mysqltest_2', 'host2'), - ('mysqltest_3', 'host3'), - ('mysqltest_4', 'host4'), - ('mysqltest_5', 'host5'), - ('mysqltest_6', 'host6'), - ('mysqltest_7', 'host7'); +create user mysqltest_1@host1; +create user mysqltest_2@host2; +create user mysqltest_3@host3; +create user mysqltest_4@host4; +create user mysqltest_5@host5; +create user mysqltest_6@host6; +create user mysqltest_7@host7; flush privileges; # Drop one user diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index cd83efcac2c..110b529fffc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -68,6 +68,7 @@ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); +static void rebuild_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user, my_bool exact); static bool update_user_table(THD *thd, TABLE *table, @@ -1095,10 +1096,8 @@ static void acl_insert_user(const char *user, const char *host, qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, sizeof(ACL_USER),(qsort_cmp) acl_compare); - /* We must free acl_check_hosts as its memory is mapped to acl_user */ - delete_dynamic(&acl_wild_hosts); - hash_free(&acl_check_hosts); - init_check_host(); + /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ + rebuild_check_host(); } @@ -1283,7 +1282,7 @@ static void init_check_host(void) if (j == acl_wild_hosts.elements) // If new (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host); } - else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host, + else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname, (uint) strlen(acl_user->host.hostname))) { if (my_hash_insert(&acl_check_hosts,(byte*) acl_user)) @@ -1300,6 +1299,22 @@ static void init_check_host(void) } +/* + Rebuild lists used for checking of allowed hosts + + We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding, + dropping or renaming user, since they contain pointers to elements of + 'acl_user' array, which are invalidated by drop operation, and use + ACL_USER::host::hostname as a key, which is changed by rename. +*/ +void rebuild_check_host(void) +{ + delete_dynamic(&acl_wild_hosts); + hash_free(&acl_check_hosts); + init_check_host(); +} + + /* Return true if there is no users that can match the given host */ bool acl_check_host(const char *host, const char *ip) @@ -5241,6 +5256,9 @@ bool mysql_drop_user(THD *thd, List &list) } } + /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ + rebuild_check_host(); + VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5265,7 +5283,7 @@ bool mysql_drop_user(THD *thd, List &list) bool mysql_rename_user(THD *thd, List &list) { - int result= 0; + int result; String wrong_users; LEX_USER *user_from; LEX_USER *user_to; @@ -5297,6 +5315,9 @@ bool mysql_rename_user(THD *thd, List &list) } } + /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ + rebuild_check_host(); + VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); close_thread_tables(thd); From eaffb7eb73b13f2275fe0fc2af490df2ac521fa8 Mon Sep 17 00:00:00 2001 From: "kent@mysql.com" <> Date: Wed, 28 Dec 2005 18:35:22 +0100 Subject: [PATCH 075/154] config-win.h: Backported Windows MAX_INDEXES handling from 5.1 --- include/config-win.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/config-win.h b/include/config-win.h index 528bc8a8cdd..b825d34f1ee 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -61,6 +61,10 @@ functions */ #define __WIN__ /* To make it easier in VC++ */ #endif +#ifndef MAX_INDEXES +#define MAX_INDEXES 64 +#endif + /* File and lock constants */ #define O_SHARE 0x1000 /* Open file in sharing mode */ #ifdef __BORLANDC__ From b1214d232ea13c6bcc51d7686b8a51f306be037d Mon Sep 17 00:00:00 2001 From: "ingo@mysql.com" <> Date: Wed, 28 Dec 2005 20:30:57 +0100 Subject: [PATCH 076/154] Bug#15591 Occasional test suite abort due to port in use If the server is started with --port-open-timeout=# retry to bind the TCP port if it fails with EADDRINUSE. Use the new option in mysql-test-run.sh. --- mysql-test/mysql-test-run.sh | 3 +++ sql/mysqld.cc | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index a115a82a6a4..982aed9c633 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1261,6 +1261,7 @@ start_master() --server-id=$id \ --basedir=$MY_BASEDIR \ --port=$this_master_myport \ + --port-open-timeout=380 \ --local-infile \ --exit-info=256 \ --core \ @@ -1285,6 +1286,7 @@ start_master() --server-id=$id --rpl-recovery-rank=1 \ --basedir=$MY_BASEDIR --init-rpl-role=master \ --port=$this_master_myport \ + --port-open-timeout=380 \ --local-infile \ --datadir=$MASTER_MYDDIR$1 \ --pid-file=$MASTER_MYPID$1 \ @@ -1417,6 +1419,7 @@ start_slave() --datadir=$slave_datadir \ --pid-file=$slave_pid \ --port=$slave_port \ + --port-open-timeout=380 \ --socket=$slave_sock \ --character-sets-dir=$CHARSETSDIR \ --default-character-set=$CHARACTER_SET \ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6e4ab50515b..14cbaf28ae3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -385,6 +385,7 @@ my_bool sp_automatic_privileges= 1; static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */ #endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; +uint mysqld_port_timeout; uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; @@ -1357,7 +1358,12 @@ static void network_init(void) struct sockaddr_un UNIXaddr; #endif int arg=1; + int ret; + uint waited; + uint this_wait; + uint retry; DBUG_ENTER("server_init"); + LINT_INIT(ret); set_ports(); @@ -1383,8 +1389,26 @@ static void network_init(void) */ (void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg)); #endif /* __WIN__ */ - if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr), - sizeof(IPaddr)) < 0) + /* + Sometimes the port is not released fast enough when stopping and + restarting the server. This happens quite often with the test suite + on busy Linux systems. Retry to bind the address at these intervals: + Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ... + Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ... + Limit the sequence by mysqld_port_timeout (set --port-open-timeout=#). + */ + for (waited= 0, retry= 1; ; retry++, waited+= this_wait) + { + if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr), + sizeof(IPaddr))) >= 0) || + (socket_errno != EADDRINUSE) || + (waited >= mysqld_port_timeout)) + break; + sql_print_information("Retrying bind on TCP/IP port %u", mysqld_port); + this_wait= retry * retry / 3 + 1; + sleep(this_wait); + } + if (ret < 0) { DBUG_PRINT("error",("Got error: %d from bind",socket_errno)); sql_perror("Can't start server: Bind on TCP/IP port"); @@ -4552,7 +4576,8 @@ enum options_mysqld OPT_TIMED_MUTEXES, OPT_OLD_STYLE_USER_LIMITS, OPT_LOG_SLOW_ADMIN_STATEMENTS, - OPT_TABLE_LOCK_WAIT_TIMEOUT + OPT_TABLE_LOCK_WAIT_TIMEOUT, + OPT_PORT_OPEN_TIMEOUT }; @@ -5092,6 +5117,10 @@ Disable with --skip-ndbcluster (will save memory).", REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port, (gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT, + "Maximum time in seconds to wait for the port to become free. " + "(Default: no wait)", (gptr*) &mysqld_port_timeout, + (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relay-log", OPT_RELAY_LOG, "The location and name to use for relay logs.", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, From 43a559ac70279dcf06a60ccb74bbb6aaa993b973 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 29 Dec 2005 09:48:43 +0100 Subject: [PATCH 077/154] Improved error message for failing with wrong error --- client/mysqltest.c | 9 +++++---- mysql-test/r/mysqltest.result | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 16ae7702857..7e7f2699ac7 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3549,11 +3549,12 @@ static void handle_error(const char *query, struct st_query *q, if (i) { if (q->expected_errno[0].type == ERR_ERRNO) - die("query '%s' failed with wrong errno %d instead of %d...", - q->query, err_errno, q->expected_errno[0].code.errnum); + die("query '%s' failed with wrong errno %d: '%s', instead of %d...", + q->query, err_errno, err_error, q->expected_errno[0].code.errnum); else - die("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); + die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...", + q->query, err_sqlstate, err_error, + q->expected_errno[0].code.sqlstate); } DBUG_VOID_RETURN; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index bf3821555cc..2657fb8a409 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -16,7 +16,7 @@ otto mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded - should have failed with sqlstate 42S22... select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' -mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22 instead of 00000... +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22: 'Unknown column 'friedrich' in 'field list'', instead of 00000... select otto from (select 1 as otto) as t1; otto 1 @@ -133,7 +133,7 @@ ERROR 42S02: Table 'test.t1' doesn't exist select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1000... garbage ; 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 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -141,7 +141,7 @@ after_--enable_abort_on_error 1064 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064... +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1064... hello hello ;;;;;;;; @@ -374,7 +374,7 @@ mysqltest: At line 1: Missing connection user mysqltest: At line 1: Missing connection user mysqltest: At line 1: Missing connection password mysqltest: At line 1: Missing connection db -mysqltest: At line 1: Could not open connection 'con2': Unknown database 'illegal_db' +mysqltest: At line 1: Could not open connection 'con2': 1049 Unknown database 'illegal_db' mysqltest: At line 1: Illegal argument for port: 'illegal_port' mysqltest: At line 1: Illegal option to connect: SMTP OK From ec753efd43b5a41fee179a430662431e93dd0a58 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Sat, 31 Dec 2005 10:54:36 +0100 Subject: [PATCH 078/154] ndb - wl#2972 (4.1) copy detached trigger fix from 5.0 --- ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index 470b98fd04c..e16d3df6d8d 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -445,6 +445,7 @@ Dbtup::commitRecord(Signal* signal, befOpPtr.p->changeMask.bitOR(attributeMask); befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; checkDetachedTriggers(signal, befOpPtr.p, @@ -483,6 +484,7 @@ Dbtup::commitRecord(Signal* signal, befOpPtr.p->pageIndex = befOpPtr.p->pageIndexC; befOpPtr.p->gci = regOperPtr->gci; + befOpPtr.p->optype = opType; operPtr.p = befOpPtr.p; checkDetachedTriggers(signal, befOpPtr.p, From 805655d8891cd421362f6894c28d8528c2e5922b Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Mon, 2 Jan 2006 14:38:38 +0100 Subject: [PATCH 079/154] bug#16125 - ndb bitfield of exact 32 bits, incorrect assertion (i.e. only noticable in debug compiled) --- mysql-test/r/ndb_bitfield.result | 6 ++++++ mysql-test/t/ndb_bitfield.test | 8 ++++++++ ndb/include/util/Bitmask.hpp | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ndb_bitfield.result b/mysql-test/r/ndb_bitfield.result index bf5a9b1ade1..9a941862854 100644 --- a/mysql-test/r/ndb_bitfield.result +++ b/mysql-test/r/ndb_bitfield.result @@ -208,3 +208,9 @@ b bit(9), key(b) ) engine=ndbcluster; ERROR HY000: Can't create table './test/t1.frm' (errno: 743) +create table t1 ( +pk1 int primary key, +b bit(32) not null +) engine=ndbcluster; +insert into t1 values (1,1); +drop table t1; diff --git a/mysql-test/t/ndb_bitfield.test b/mysql-test/t/ndb_bitfield.test index 0256ecf89ed..59d6e56577e 100644 --- a/mysql-test/t/ndb_bitfield.test +++ b/mysql-test/t/ndb_bitfield.test @@ -112,3 +112,11 @@ create table t1 ( key(b) ) engine=ndbcluster; +# bug#16125 +create table t1 ( + pk1 int primary key, + b bit(32) not null +) engine=ndbcluster; + +insert into t1 values (1,1); +drop table t1; diff --git a/ndb/include/util/Bitmask.hpp b/ndb/include/util/Bitmask.hpp index ade57a5ee57..7957bf7a48d 100644 --- a/ndb/include/util/Bitmask.hpp +++ b/ndb/include/util/Bitmask.hpp @@ -814,7 +814,7 @@ inline void BitmaskImpl::getField(unsigned size, const Uint32 src[], unsigned pos, unsigned len, Uint32 dst[]) { - assert(pos + len < (size << 5)); + assert(pos + len <= (size << 5)); src += (pos >> 5); Uint32 offset = pos & 31; @@ -833,7 +833,7 @@ inline void BitmaskImpl::setField(unsigned size, Uint32 dst[], unsigned pos, unsigned len, const Uint32 src[]) { - assert(pos + len < (size << 5)); + assert(pos + len <= (size << 5)); dst += (pos >> 5); Uint32 offset = pos & 31; From 8ce6f3e6ca7fedd2142e784e9aeab72ec2e49951 Mon Sep 17 00:00:00 2001 From: "gluh@eagle.intranet.mysql.r18.ru" <> Date: Tue, 3 Jan 2006 14:25:19 +0400 Subject: [PATCH 080/154] Fix for bug#15533 crash, information_schema, function, view enable view prepared mode during getting metedata for I_S table --- mysql-test/r/information_schema.result | 16 ++++++++++++++++ mysql-test/t/information_schema.test | 23 +++++++++++++++++++++++ sql/sql_show.cc | 3 +++ 3 files changed, 42 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index e8d343ad711..05f2118a8c7 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1074,3 +1074,19 @@ character_maximum_length character_octet_length 32 32 64 64 drop table t1; +CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT); +INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1; +CREATE FUNCTION func2() RETURNS BIGINT RETURN 1; +CREATE FUNCTION func1() RETURNS BIGINT +BEGIN +RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS); +END// +CREATE VIEW v1 AS SELECT 1 FROM t1 +WHERE f3 = (SELECT func2 ()); +SELECT func1(); +func1() +1 +DROP TABLE t1; +DROP VIEW v1; +DROP FUNCTION func1; +DROP FUNCTION func2; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b05798b781f..f835a7148a2 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -767,3 +767,26 @@ create table t1(f1 binary(32), f2 varbinary(64)); select character_maximum_length, character_octet_length from information_schema.columns where table_name='t1'; drop table t1; + +# +# Bug#15533 crash, information_schema, function, view +# +CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT); +INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1; + +CREATE FUNCTION func2() RETURNS BIGINT RETURN 1; + +delimiter //; +CREATE FUNCTION func1() RETURNS BIGINT +BEGIN + RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS); +END// +delimiter ;// + +CREATE VIEW v1 AS SELECT 1 FROM t1 + WHERE f3 = (SELECT func2 ()); +SELECT func1(); +DROP TABLE t1; +DROP VIEW v1; +DROP FUNCTION func1; +DROP FUNCTION func2; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1b31e8f7dc3..089314078a6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2045,6 +2045,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) int error= 1; db_type not_used; Open_tables_state open_tables_state_backup; + bool save_view_prepare_mode= lex->view_prepare_mode; + lex->view_prepare_mode= TRUE; DBUG_ENTER("get_all_tables"); LINT_INIT(end); @@ -2230,6 +2232,7 @@ err: lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; lex->query_tables_last= save_query_tables_last; + lex->view_prepare_mode= save_view_prepare_mode; *save_query_tables_last= 0; lex->sql_command= save_sql_command; DBUG_RETURN(error); From 14f94dc0cad1419e74047956c059c1cf9c3e7a2c Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 3 Jan 2006 17:54:54 +0100 Subject: [PATCH 081/154] many warnings (practically safe but annoying) corrected --- client/mysqladmin.cc | 1 + client/mysqlbinlog.cc | 9 +- client/mysqldump.c | 27 +++--- cmd-line-utils/libedit/history.c | 4 +- include/my_base.h | 3 +- libmysql/libmysql.c | 2 +- myisam/mi_delete.c | 3 +- myisam/myisampack.c | 2 +- myisam/sort.c | 3 + mysys/default_modify.c | 2 +- mysys/mf_iocache2.c | 10 +- mysys/my_bitmap.c | 2 +- mysys/my_error.c | 3 + server-tools/instance-manager/parse.cc | 2 +- sql-common/client.c | 2 +- sql/field.cc | 22 ++--- sql/field.h | 4 +- sql/ha_myisam.cc | 17 ++-- sql/item.cc | 8 +- sql/item_func.cc | 13 ++- sql/log_event.cc | 4 + sql/opt_range.cc | 7 +- sql/opt_range.h | 2 +- sql/repl_failsafe.cc | 3 +- sql/set_var.cc | 1 - sql/slave.cc | 38 +++++--- sql/slave.h | 2 +- sql/sql_acl.cc | 6 +- sql/sql_db.cc | 114 ++++++++++++----------- sql/sql_handler.cc | 8 +- sql/sql_help.cc | 2 +- sql/sql_insert.cc | 3 +- sql/sql_parse.cc | 12 ++- sql/sql_repl.cc | 12 ++- sql/sql_show.cc | 23 ++--- sql/sql_test.cc | 2 +- sql/table.cc | 5 +- sql/uniques.cc | 122 ++++++++++++------------- 38 files changed, 274 insertions(+), 231 deletions(-) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 8d2e040b21f..5b52d524f8e 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -569,6 +569,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return -1; } mysql_close(mysql); /* Close connection to avoid error messages */ + argc=1; /* force SHUTDOWN to be the last command */ if (got_pidfile) { if (opt_verbose) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index ae482a155d5..b1a931a9df1 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1266,12 +1266,13 @@ at offset %lu ; this could be a log format error or read error", } else if (buf[4] == ROTATE_EVENT) { + Log_event *ev; my_b_seek(file, tmp_pos); /* seek back to event's start */ - if (!Log_event::read_log_event(file, *description_event)) + if (!(ev= Log_event::read_log_event(file, *description_event))) /* EOF can't be hit here normally, so it's a real error */ - die("Could not read a Rotate_log_event event \ -at offset %lu ; this could be a log format error or read error", - tmp_pos); + die("Could not read a Rotate_log_event event at offset %lu ;" + " this could be a log format error or read error", tmp_pos); + delete ev; } else break; diff --git a/client/mysqldump.c b/client/mysqldump.c index 454fc0df84e..64daa39feee 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1306,7 +1306,7 @@ static uint dump_routines_for_db(char *db) fprintf(sql_file, "DELIMITER ;\n"); if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); DBUG_RETURN(0); } @@ -2095,7 +2095,10 @@ static void dump_table(char *table, char *db) else res=mysql_store_result(sock); if (!res) + { DB_error(sock, "when retrieving data from server"); + goto err; + } if (verbose) fprintf(stderr, "-- Retrieving rows...\n"); if (mysql_num_fields(res) != num_fields) @@ -2625,7 +2628,7 @@ static int dump_all_tables_in_db(char *database) check_io(md_result_file); } if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); return 0; } /* dump_all_tables_in_db */ @@ -2680,23 +2683,23 @@ static my_bool dump_all_views_in_db(char *database) check_io(md_result_file); } if (lock_tables) - mysql_query(sock,"UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); return 0; } /* dump_all_tables_in_db */ /* - get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual - table name from the server for the table name given on the command line. - we do this because the table name given on the command line may be a + get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual + table name from the server for the table name given on the command line. + we do this because the table name given on the command line may be a different case (e.g. T1 vs t1) - + RETURN int - 0 if a tablename was retrieved. 1 if not */ -static int get_actual_table_name(const char *old_table_name, - char *new_table_name, +static int get_actual_table_name(const char *old_table_name, + char *new_table_name, int buf_size) { int retval; @@ -2708,7 +2711,7 @@ static int get_actual_table_name(const char *old_table_name, /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); - my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", + my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", quote_for_like(old_table_name, show_name_buff)); if (mysql_query_with_error_report(sock, 0, query)) @@ -2717,7 +2720,7 @@ static int get_actual_table_name(const char *old_table_name, } retval = 1; - + if ((table_res= mysql_store_result(sock))) { my_ulonglong num_rows= mysql_num_rows(table_res); @@ -2839,7 +2842,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) check_io(md_result_file); } if (lock_tables) - mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); DBUG_RETURN(0); } /* dump_selected_tables */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 1da6a864181..c0fa7cc717d 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -676,8 +676,8 @@ history_load(History *h, const char *fname) (void) strunvis(ptr, line); line[sz] = c; if (HENTER(h, &ev, ptr) == -1) { - h_free((ptr_t)ptr); - return -1; + i = -1; + goto oomem; } } oomem: diff --git a/include/my_base.h b/include/my_base.h index 8eab79a96fd..77cd60fda92 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -404,7 +404,8 @@ enum ha_base_keytype { enum en_fieldtype { FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO, - FIELD_VARCHAR,FIELD_CHECK + FIELD_VARCHAR,FIELD_CHECK, + FIELD_enum_val_count }; enum data_file_type { diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 11ee7284cbf..0c74dc9121c 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -818,7 +818,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) if ((*options->local_infile_init)(&li_ptr, net_filename, options->local_infile_userdata)) { - my_net_write(net,"",0); /* Server needs one packet */ + VOID(my_net_write(net,"",0)); /* Server needs one packet */ net_flush(net); strmov(net->sqlstate, unknown_sqlstate); net->last_errno= (*options->local_infile_error)(li_ptr, diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index bf99830b37f..daac2c4e17e 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -276,7 +276,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (subkeys == -1) { /* the last entry in sub-tree */ - _mi_dispose(info, keyinfo, root,DFLT_INIT_HITS); + if (_mi_dispose(info, keyinfo, root,DFLT_INIT_HITS)) + DBUG_RETURN(-1); /* fall through to normal delete */ } else diff --git a/myisam/myisampack.c b/myisam/myisampack.c index d691c24e890..e80a3ffacd9 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -1159,7 +1159,7 @@ static int compare_huff_elements(void *not_used __attribute__((unused)), static void check_counts(HUFF_COUNTS *huff_counts, uint trees, my_off_t records) { - uint space_fields,fill_zero_fields,field_count[(int) FIELD_VARCHAR+1]; + uint space_fields,fill_zero_fields,field_count[(int) FIELD_enum_val_count]; my_off_t old_length,new_length,length; DBUG_ENTER("check_counts"); diff --git a/myisam/sort.c b/myisam/sort.c index c3eaddb3e92..c9562461f56 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -376,7 +376,10 @@ pthread_handler_t thr_find_all_keys(void *arg) { if (my_init_dynamic_array(&info->buffpek, sizeof(BUFFPEK), maxbuffer, maxbuffer/2)) + { my_free((gptr) sort_keys,MYF(0)); + sort_keys= (uchar **) NULL; /* for err: label */ + } else break; } diff --git a/mysys/default_modify.c b/mysys/default_modify.c index de03d783c68..0f58b8a930c 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -197,7 +197,7 @@ int modify_defaults_file(const char *file_location, const char *option, goto err; } if (my_fclose(cnf_file, MYF(MY_WME))) - goto err; + DBUG_RETURN(1); my_free(file_buffer, MYF(0)); DBUG_RETURN(0); diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 1f3db84304e..e181ccfb88d 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -79,7 +79,7 @@ my_off_t my_b_safe_tell(IO_CACHE *info) void my_b_seek(IO_CACHE *info,my_off_t pos) { - my_off_t offset; + my_off_t offset; DBUG_ENTER("my_b_seek"); DBUG_PRINT("enter",("pos: %lu", (ulong) pos)); @@ -91,10 +91,10 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) b) see if there is a better way to make it work */ if (info->type == SEQ_READ_APPEND) - flush_io_cache(info); - + VOID(flush_io_cache(info)); + offset=(pos - info->pos_in_file); - + if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND) { /* TODO: explain why this works if pos < info->pos_in_file */ @@ -119,7 +119,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) info->write_pos = info->write_buffer + offset; DBUG_VOID_RETURN; } - flush_io_cache(info); + VOID(flush_io_cache(info)); /* Correct buffer end so that we write in increments of IO_SIZE */ info->write_end=(info->write_buffer+info->buffer_length- (pos & (IO_SIZE-1))); diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 4a917fc8287..e2875d9e53e 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -69,7 +69,7 @@ my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, (thread_safe ? sizeof(pthread_mutex_t) : 0), MYF(MY_WME | MY_ZEROFILL)))) - return 1; + DBUG_RETURN(1); map->bitmap_size=bitmap_size; #ifdef THREAD if (thread_safe) diff --git a/mysys/my_error.c b/mysys/my_error.c index 0c18bbf6e8b..d7177e7a047 100644 --- a/mysys/my_error.c +++ b/mysys/my_error.c @@ -189,7 +189,10 @@ int my_error_register(const char **errmsgs, int first, int last) /* Error numbers must be unique. No overlapping is allowed. */ if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last)) + { + my_free((gptr)meh_p, MYF(0)); return 1; + } /* Insert header into the chain. */ meh_p->meh_next= *search_meh_pp; diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc index d83af2b9cf0..a79a6ad6742 100644 --- a/server-tools/instance-manager/parse.cc +++ b/server-tools/instance-manager/parse.cc @@ -107,7 +107,7 @@ Token shift_token(const char **text, uint *word_len) int get_text_id(const char **text, uint *word_len, const char **id) { get_word(text, word_len); - if (word_len == 0) + if (*word_len == 0) return 1; *id= *text; return 0; diff --git a/sql-common/client.c b/sql-common/client.c index 4c2debd41ff..824d3705c23 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -599,7 +599,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); #ifdef MYSQL_SERVER - if (vio_was_interrupted(net->vio)) + if (net->vio && vio_was_interrupted(net->vio)) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); diff --git a/sql/field.cc b/sql/field.cc index 3903d8323ad..cc8f57fb564 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1570,7 +1570,6 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table, bool Field::quote_data(String *unquoted_string) { char escaped_string[IO_SIZE]; - char *unquoted_string_buffer= (char *)(unquoted_string->ptr()); DBUG_ENTER("Field::quote_data"); if (!needs_quotes()) @@ -4541,8 +4540,6 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; } } - if (error > 1) - error= 2; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -7064,7 +7061,7 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type) } get_ptr(&blob); gobj= Geometry::construct(&buffer, blob, blob_length); - if (gobj->get_mbr(&mbr, &dummy)) + if (!gobj || gobj->get_mbr(&mbr, &dummy)) bzero(buff, SIZEOF_STORED_DOUBLE*4); else { @@ -7393,7 +7390,7 @@ void Field_geom::get_key_image(char *buff, uint length, imagetype type) } get_ptr(&blob); gobj= Geometry::construct(&buffer, blob, blob_length); - if (gobj->get_mbr(&mbr, &dummy)) + if (!gobj || gobj->get_mbr(&mbr, &dummy)) bzero(buff, SIZEOF_STORED_DOUBLE*4); else { @@ -8151,17 +8148,14 @@ const char *Field_bit::unpack(char *to, const char *from) */ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg, - uchar *null_ptr_arg, uchar null_bit_arg, - uchar *bit_ptr_arg, uchar bit_ofs_arg, - enum utype unireg_check_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg) - : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, bit_ptr_arg, - bit_ofs_arg, unireg_check_arg, field_name_arg, table_arg), + : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, + 0, unireg_check_arg, field_name_arg, table_arg), create_length(len_arg) { - bit_ptr= 0; - bit_ofs= 0; bit_len= 0; field_length= ((len_arg + 7) & ~7) / 8; } @@ -8518,8 +8512,8 @@ Field *make_field(char *ptr, uint32 field_length, return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset); case FIELD_TYPE_BIT: return f_bit_as_char(pack_flag) ? - new Field_bit_as_char(ptr, field_length, null_pos, null_bit, bit_ptr, - bit_offset, unireg_check, field_name, table) : + new Field_bit_as_char(ptr, field_length, null_pos, null_bit, + unireg_check, field_name, table) : new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr, bit_offset, unireg_check, field_name, table); default: // Impossible (Wrong version) diff --git a/sql/field.h b/sql/field.h index ed6bf1c0a9c..5d722fccb18 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1336,12 +1336,12 @@ public: } }; - + class Field_bit_as_char: public Field_bit { public: uchar create_length; Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, - uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, + uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg); enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 08fd2d9a8e3..ff6431fa0f3 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -266,7 +266,8 @@ int ha_myisam::dump(THD* thd, int fd) if (fd < 0) { - my_net_write(net, "", 0); + if (my_net_write(net, "", 0)) + error = errno ? errno : EPIPE; net_flush(net); } @@ -365,12 +366,14 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) { uint old_testflag=param.testflag; param.testflag|=T_MEDIUM; - init_io_cache(¶m.read_cache, file->dfile, - my_default_record_cache_size, READ_CACHE, - share->pack.header_length, 1, MYF(MY_WME)); - error |= chk_data_link(¶m, file, param.testflag & T_EXTEND); - end_io_cache(&(param.read_cache)); - param.testflag=old_testflag; + if (!(error= init_io_cache(¶m.read_cache, file->dfile, + my_default_record_cache_size, READ_CACHE, + share->pack.header_length, 1, MYF(MY_WME)))) + { + error= chk_data_link(¶m, file, param.testflag & T_EXTEND); + end_io_cache(&(param.read_cache)); + } + param.testflag= old_testflag; } } if (!error) diff --git a/sql/item.cc b/sql/item.cc index c15fd948b5a..6b756ff9d60 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -931,9 +931,9 @@ void Item_splocal::cleanup() void Item_splocal::print(String *str) { - str->reserve(m_name.length+8); - str->append(m_name.str, m_name.length); - str->append('@'); + VOID(str->reserve(m_name.length+8)); + VOID(str->append(m_name.str, m_name.length)); + VOID(str->append('@')); str->qs_append(m_offset); } @@ -3784,7 +3784,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table); case MYSQL_TYPE_BIT: - return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0, + return new Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, name, table); default: /* This case should never be chosen */ diff --git a/sql/item_func.cc b/sql/item_func.cc index 89561e8eb17..11f4ea0439a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -888,7 +888,7 @@ String *Item_decimal_typecast::val_str(String *str) my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); if (null_value) return NULL; - my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); + my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str); return str; } @@ -4709,7 +4709,7 @@ Item_func_sp::sp_result_field(void) const { char *empty_name= (char *) ""; TABLE_SHARE *share; - dummy_table->s= share= &dummy_table->share_not_to_be_used; + dummy_table->s= share= &dummy_table->share_not_to_be_used; dummy_table->alias = empty_name; dummy_table->maybe_null = maybe_null; dummy_table->in_use= current_thd; @@ -4742,8 +4742,13 @@ Item_func_sp::execute(Field **flp) } if (!(f= *flp)) { - *flp= f= sp_result_field(); - f->move_field((f->pack_length() > sizeof(result_buf)) ? + if (!(*flp= f= sp_result_field())) + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + return 0; + } + + f->move_field((f->pack_length() > sizeof(result_buf)) ? sql_alloc(f->pack_length()) : result_buf); f->null_ptr= (uchar *)&null_value; f->null_bit= 1; diff --git a/sql/log_event.cc b/sql/log_event.cc index 056bcca1a02..e977016ea21 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3253,6 +3253,10 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) case INSERT_ID_EVENT: msg="INSERT_ID"; break; + case INVALID_INT_EVENT: + default: // cannot happen + msg="INVALID_INT"; + break; } fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); fflush(file); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d9a608eb064..9a44b6e1cab 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -652,7 +652,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, bool allow_null_cond, int *error) - { SQL_SELECT *select; DBUG_ENTER("make_select"); @@ -5774,10 +5773,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, if (!quick) return 0; /* no ranges found */ if (quick->init()) - { - delete quick; goto err; - } quick->records= records; if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error || @@ -7111,7 +7107,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) ha_rows cur_records; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; - uint cur_param_idx; + uint cur_param_idx=MAX_KEY; key_map cur_used_key_parts; uint pk= param->table->s->primary_key; @@ -7327,6 +7323,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) { + DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY); index_info= cur_index_info; index= cur_index; best_read_cost= cur_read_cost; diff --git a/sql/opt_range.h b/sql/opt_range.h index f84058f3b64..cdb00ea7d0c 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -705,7 +705,7 @@ class SQL_SELECT :public Sql_alloc { class FT_SELECT: public QUICK_RANGE_SELECT { public: FT_SELECT(THD *thd, TABLE *table, uint key) : - QUICK_RANGE_SELECT (thd, table, key, 1) { init(); } + QUICK_RANGE_SELECT (thd, table, key, 1) { VOID(init()); } ~FT_SELECT() { file->ft_end(); } int init() { return error=file->ft_init(); } int reset() { return 0; } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index d76be2ec2e4..5cdd24afba4 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -929,7 +929,8 @@ bool load_master_data(THD* thd) host was specified; there could have been a problem when replication started, which led to relay log's IO_CACHE to not be inited. */ - flush_master_info(active_mi, 0); + if (flush_master_info(active_mi, 0)) + sql_print_error("Failed to flush master info file"); } mysql_free_result(master_status_res); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 632c37d2296..f10da4ad9ba 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2518,7 +2518,6 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) bool sys_var_sync_binlog_period::update(THD *thd, set_var *var) { - pthread_mutex_t *lock_log= mysql_bin_log.get_log_lock(); sync_binlog_period= (ulong) var->save_result.ulonglong_value; return 0; } diff --git a/sql/slave.cc b/sql/slave.cc index 5e1c838730c..3795cbaf7c0 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2017,7 +2017,8 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) " to the relay log, " "SHOW SLAVE STATUS may be inaccurate"); rli->relay_log.harvest_bytes_written(&rli->log_space_total); - flush_master_info(mi, 1); + if (flush_master_info(mi, 1)) + sql_print_error("Failed to flush master info file"); delete ev; } else @@ -2555,7 +2556,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); - + if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(TRUE); } @@ -2563,8 +2564,13 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) DBUG_RETURN(FALSE); } - -bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) +/* + RETURN + 2 - flush relay log failed + 1 - flush master info failed + 0 - all ok +*/ +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) { IO_CACHE* file = &mi->file; char lbuf[22]; @@ -2583,8 +2589,9 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) When we come to this place in code, relay log may or not be initialized; the caller is responsible for setting 'flush_relay_log_cache' accordingly. */ - if (flush_relay_log_cache) - flush_io_cache(mi->rli.relay_log.get_log_file()); + if (flush_relay_log_cache && + flush_io_cache(mi->rli.relay_log.get_log_file())) + DBUG_RETURN(2); /* We flushed the relay log BEFORE the master.info file, because if we crash @@ -2596,13 +2603,13 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) */ /* - In certain cases this code may create master.info files that seems - corrupted, because of extra lines filled with garbage in the end - file (this happens if new contents take less space than previous - contents of file). But because of number of lines in the first line + In certain cases this code may create master.info files that seems + corrupted, because of extra lines filled with garbage in the end + file (this happens if new contents take less space than previous + contents of file). But because of number of lines in the first line of file we don't care about this garbage. */ - + my_b_seek(file, 0L); my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", LINES_IN_MASTER_INFO_WITH_SSL, @@ -2611,8 +2618,7 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache) mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key); - flush_io_cache(file); - DBUG_RETURN(0); + DBUG_RETURN(-flush_io_cache(file)); } @@ -3644,7 +3650,11 @@ reconnect done to recover from failed read"); sql_print_error("Slave I/O thread could not queue event from master"); goto err; } - flush_master_info(mi, 1); /* sure that we can flush the relay log */ + if (flush_master_info(mi, 1)) + { + sql_print_error("Failed to flush master info file"); + goto err; + } /* See if the relay logs take too much space. We don't lock mi->rli.log_space_lock here; this dirty read saves time diff --git a/sql/slave.h b/sql/slave.h index 4d3c338680d..040ce4eaf85 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -500,7 +500,7 @@ typedef struct st_table_rule_ent int init_slave(); void init_slave_skip_errors(const char* arg); -bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); +int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache); bool flush_relay_log_info(RELAY_LOG_INFO* rli); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index cd83efcac2c..b07a034dfd7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -937,7 +937,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'", (host ? host : "(NULL)"), (ip ? ip : "(NULL)"), - (user ? user : "(NULL)"), (db ? db : "(NULL)"))); + user, (db ? db : "(NULL)"))); sctx->user= user; sctx->host= host; sctx->ip= ip; @@ -966,7 +966,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, for (i=0 ; i < acl_users.elements ; i++) { acl_user= dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user->user && (!user || !user[0])) || + if ((!acl_user->user && !user[0]) || (acl_user->user && strcmp(user, acl_user->user) == 0)) { if (compare_hostname(&acl_user->host, host, ip)) @@ -4939,8 +4939,6 @@ static int handle_grant_struct(uint struct_no, bool drop, } if (! user) user= ""; - if (! host) - host= ""; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'", struct_no, idx, user, host)); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index bde6522a38b..cff28864ebe 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -287,7 +287,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) } -/* +/* Load database options file load_db_opt() @@ -313,68 +313,72 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) bzero((char*) create,sizeof(*create)); create->default_table_charset= thd->variables.collation_server; - + /* Check if options for this database are already in the hash */ if (!get_dbopt(path, create)) - DBUG_RETURN(0); - - /* Otherwise, load options from the .opt file */ - if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) - { - IO_CACHE cache; - init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)); + DBUG_RETURN(0); - while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) + /* Otherwise, load options from the .opt file */ + if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) + goto err1; + + IO_CACHE cache; + if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0))) + goto err2; + + while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) + { + char *pos= buf+nbytes-1; + /* Remove end space and control characters */ + while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1])) + pos--; + *pos=0; + if ((pos= strchr(buf, '='))) { - char *pos= buf+nbytes-1; - /* Remove end space and control characters */ - while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1])) - pos--; - *pos=0; - if ((pos= strchr(buf, '='))) + if (!strncmp(buf,"default-character-set", (pos-buf))) { - if (!strncmp(buf,"default-character-set", (pos-buf))) - { - /* - Try character set name, and if it fails - try collation name, probably it's an old - 4.1.0 db.opt file, which didn't have - separate default-character-set and - default-collation commands. - */ - if (!(create->default_table_charset= - get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) && - !(create->default_table_charset= - get_charset_by_name(pos+1, MYF(0)))) - { - sql_print_error("Error while loading database options: '%s':",path); - sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); - create->default_table_charset= default_charset_info; - } - } - else if (!strncmp(buf,"default-collation", (pos-buf))) - { - if (!(create->default_table_charset= get_charset_by_name(pos+1, - MYF(0)))) - { - sql_print_error("Error while loading database options: '%s':",path); - sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1); - create->default_table_charset= default_charset_info; - } - } + /* + Try character set name, and if it fails + try collation name, probably it's an old + 4.1.0 db.opt file, which didn't have + separate default-character-set and + default-collation commands. + */ + if (!(create->default_table_charset= + get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) && + !(create->default_table_charset= + get_charset_by_name(pos+1, MYF(0)))) + { + sql_print_error("Error while loading database options: '%s':",path); + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); + create->default_table_charset= default_charset_info; + } + } + else if (!strncmp(buf,"default-collation", (pos-buf))) + { + if (!(create->default_table_charset= get_charset_by_name(pos+1, + MYF(0)))) + { + sql_print_error("Error while loading database options: '%s':",path); + sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1); + create->default_table_charset= default_charset_info; + } } } - end_io_cache(&cache); - my_close(file,MYF(0)); - /* - Put the loaded value into the hash. - Note that another thread could've added the same - entry to the hash after we called get_dbopt(), - but it's not an error, as put_dbopt() takes this - possibility into account. - */ - error= put_dbopt(path, create); } + /* + Put the loaded value into the hash. + Note that another thread could've added the same + entry to the hash after we called get_dbopt(), + but it's not an error, as put_dbopt() takes this + possibility into account. + */ + error= put_dbopt(path, create); + + end_io_cache(&cache); +err2: + my_close(file,MYF(0)); +err1: DBUG_RETURN(error); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index da72d283259..ef0f4243d89 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -377,10 +377,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, address of the 'next' pointer referencing this table for close_thread_table(). */ - for (table_ptr= &(thd->handler_tables); - *table_ptr && (*table_ptr != table); - table_ptr= &(*table_ptr)->next) - {} + for (table_ptr= &(thd->handler_tables); *table_ptr != table; + table_ptr= &(*table_ptr)->next) /* no-op */ ; (*table_ptr)->file->ha_index_or_rnd_end(); VOID(pthread_mutex_lock(&LOCK_open)); if (close_thread_table(thd, table_ptr)) @@ -750,7 +748,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) /* Mark table as closed, ready for re-open. */ hash_tables->table= NULL; } - } + } safe_mutex_assert_owner(&LOCK_open); (*table_ptr)->file->ha_index_or_rnd_end(); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index b47412981ea..d6d1a6ed119 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -567,7 +567,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error); if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) || - (res->quick && res->quick->reset())) + (res && res->quick && res->quick->reset())) { delete res; res=0; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8903f28be11..4f61891fb09 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -666,7 +666,8 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) DBUG_ASSERT(view->table != 0 && view->field_translation != 0); - bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0); + VOID(bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, + 0)); bitmap_clear_all(&used_fields); view->contain_auto_increment= 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dc5237d9b7d..7e53d435400 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1593,6 +1593,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_other, &LOCK_status); thd->enable_slow_log= opt_log_slow_admin_statements; db= thd->alloc(db_len + tbl_len + 2); + if (!db) + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + break; + } tbl_name= strmake(db, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); mysql_table_dump(thd, db, tbl_name, -1); @@ -1606,14 +1611,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.com_other, &LOCK_status); char *user= (char*) packet; char *passwd= strend(user)+1; - /* + /* Old clients send null-terminated string ('\0' for empty string) for password. New clients send the size (1 byte) + string (not null terminated, so also '\0' for empty string). */ - char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + char db_buff[NAME_LEN+1]; // buffer to store db in utf8 char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? *passwd++ : strlen(passwd); db+= passwd_len + 1; #ifndef EMBEDDED_LIBRARY @@ -6865,6 +6870,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #ifdef HAVE_REPLICATION if (options & REFRESH_MASTER) { + DBUG_ASSERT(thd); tmp_write_to_binlog= 0; if (reset_master(thd)) { diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index cd293fc21c7..07678d97800 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1197,7 +1197,12 @@ bool change_master(THD* thd, MASTER_INFO* mi) Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never a slave before). */ - flush_master_info(mi, 0); + if (flush_master_info(mi, 0)) + { + my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file"); + unlock_slave_threads(mi); + DBUG_RETURN(TRUE); + } if (need_relay_log_purge) { relay_log_purge= 1; @@ -1307,14 +1312,15 @@ bool mysql_show_binlog_events(THD* thd) bool ret = TRUE; IO_CACHE log; File file = -1; - Format_description_log_event *description_event= new - Format_description_log_event(3); /* MySQL 4.0 by default */ Log_event::init_show_field_list(&field_list); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + Format_description_log_event *description_event= new + Format_description_log_event(3); /* MySQL 4.0 by default */ + if (mysql_bin_log.is_open()) { LEX_MASTER_INFO *lex_mi= &thd->lex->mi; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 82870d46e6c..7a1535edcac 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -663,7 +663,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) it's a keyword */ - packet->reserve(length*2 + 2); + VOID(packet->reserve(length*2 + 2)); quote_char= (char) q; packet->append("e_char, 1, system_charset_info); @@ -950,13 +950,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (key_part->field) append_identifier(thd,packet,key_part->field->field_name, strlen(key_part->field->field_name)); - if (!key_part->field || + if (key_part->field && (key_part->length != table->field[key_part->fieldnr-1]->key_length() && !(key_info->flags & HA_FULLTEXT))) { buff[0] = '('; - char* end=int10_to_str((long) key_part->length / + char* end=int10_to_str((long) key_part->length / key_part->field->charset()->mbmaxlen, buff + 1,10); *end++ = ')'; @@ -1732,7 +1732,8 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, { MEM_ROOT *mem= thd->mem_root; if (allocate_lex_string) - lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)); + if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)))) + return 0; lex_str->str= strmake_root(mem, str, length); lex_str->length= length; return lex_str; @@ -2933,7 +2934,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, /* I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS rather than in SHOW KEYS - */ + */ if (!tables->view) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); @@ -2946,7 +2947,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, { TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++,key_info++) @@ -2958,7 +2959,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, restore_record(table, s->default_values); table->field[1]->store(base_name, strlen(base_name), cs); table->field[2]->store(file_name, strlen(file_name), cs); - table->field[3]->store((longlong) ((key_info->flags & + table->field[3]->store((longlong) ((key_info->flags & HA_NOSAME) ? 0 : 1), TRUE); table->field[4]->store(base_name, strlen(base_name), cs); table->field[5]->store(key_info->name, strlen(key_info->name), cs); @@ -2981,12 +2982,12 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, table->field[9]->store((longlong) records, TRUE); table->field[9]->set_notnull(); } - if (!(key_info->flags & HA_FULLTEXT) && - (!key_part->field || - key_part->length != + if (!(key_info->flags & HA_FULLTEXT) && + (key_part->field && + key_part->length != show_table->field[key_part->fieldnr-1]->key_length())) { - table->field[10]->store((longlong) key_part->length / + table->field[10]->store((longlong) key_part->length / key_part->field->charset()->mbmaxlen); table->field[10]->set_notnull(); } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 1bd298dda04..975cc19ea3f 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -450,7 +450,7 @@ void mysql_print_status() calc_sum_of_all_status(&tmp); printf("\nStatus information:\n\n"); - my_getwd(current_dir, sizeof(current_dir),MYF(0)); + VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0))); printf("Current dir: %s\n", current_dir); printf("Running threads: %d Stack size: %ld\n", thread_count, (long) thread_stack); diff --git a/sql/table.cc b/sql/table.cc index fc75568b615..45f8edddd0b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1040,7 +1040,10 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names) ret_value=uint4korr(pos); } if (! save_names) - my_free((gptr) buf,MYF(0)); + { + if (names) + my_free((gptr) buf,MYF(0)); + } else if (!names) bzero((char*) save_names,sizeof(save_names)); else diff --git a/sql/uniques.cc b/sql/uniques.cc index 367aed2d113..ad074f8b2b0 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -38,8 +38,8 @@ int unique_write_to_file(gptr key, element_count count, Unique *unique) { /* - Use unique->size (size of element stored in the tree) and not - unique->tree.size_of_element. The latter is different from unique->size + Use unique->size (size of element stored in the tree) and not + unique->tree.size_of_element. The latter is different from unique->size when tree implementation chooses to store pointer to key in TREE_ELEMENT (instead of storing the element itself there) */ @@ -63,27 +63,27 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, comp_func_fixed_arg); /* If the following fail's the next add will also fail */ my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); - /* + /* If you change the following, change it in get_max_elements function, too. */ max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); - open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, - MYF(MY_WME)); + VOID(open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE, + MYF(MY_WME))); } /* Calculate log2(n!) - + NOTES Stirling's approximate formula is used: - - n! ~= sqrt(2*M_PI*n) * (n/M_E)^n - + + n! ~= sqrt(2*M_PI*n) * (n/M_E)^n + Derivation of formula used for calculations is as follows: log2(n!) = log(n!)/log(2) = log(sqrt(2*M_PI*n)*(n/M_E)^n) / log(2) = - + = (log(2*M_PI*n)/2 + n*log(n/M_E)) / log(2). */ @@ -94,7 +94,7 @@ inline double log2_n_fact(double x) /* - Calculate cost of merge_buffers function call for given sequence of + Calculate cost of merge_buffers function call for given sequence of input stream lengths and store the number of rows in result stream in *last. SYNOPSIS @@ -103,21 +103,21 @@ inline double log2_n_fact(double x) elem_size Size of element stored in buffer first Pointer to first merged element size last Pointer to last merged element size - + RETURN Cost of merge_buffers operation in disk seeks. - + NOTES It is assumed that no rows are eliminated during merge. - The cost is calculated as - + The cost is calculated as + cost(read_and_write) + cost(merge_comparisons). - - All bytes in the sequences is read and written back during merge so cost + + All bytes in the sequences is read and written back during merge so cost of disk io is 2*elem_size*total_buf_elems/IO_SIZE (2 is for read + write) - + For comparisons cost calculations we assume that all merged sequences have - the same length, so each of total_buf_size elements will be added to a sort + the same length, so each of total_buf_size elements will be added to a sort heap with (n_buffers-1) elements. This gives the comparison cost: total_buf_elems* log2(n_buffers) / TIME_FOR_COMPARE_ROWID; @@ -125,16 +125,16 @@ inline double log2_n_fact(double x) static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, uint *first, uint *last) -{ +{ uint total_buf_elems= 0; for (uint *pbuf= first; pbuf <= last; pbuf++) total_buf_elems+= *pbuf; *last= total_buf_elems; - + int n_buffers= last - first + 1; /* Using log2(n)=log(n)/log(2) formula */ - return 2*((double)total_buf_elems*elem_size) / IO_SIZE + + return 2*((double)total_buf_elems*elem_size) / IO_SIZE + total_buf_elems*log((double) n_buffers) / (TIME_FOR_COMPARE_ROWID * M_LN2); } @@ -142,13 +142,13 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, /* Calculate cost of merging buffers into one in Unique::get, i.e. calculate how long (in terms of disk seeks) the two calls - merge_many_buffs(...); - merge_buffers(...); + merge_many_buffs(...); + merge_buffers(...); will take. SYNOPSIS get_merge_many_buffs_cost() - buffer buffer space for temporary data, at least + buffer buffer space for temporary data, at least Unique::get_cost_calc_buff_size bytes maxbuffer # of full buffers max_n_elems # of elements in first maxbuffer buffers @@ -156,12 +156,12 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size, elem_size size of buffer element NOTES - maxbuffer+1 buffers are merged, where first maxbuffer buffers contain + maxbuffer+1 buffers are merged, where first maxbuffer buffers contain max_n_elems elements each and last buffer contains last_n_elems elements. The current implementation does a dumb simulation of merge_many_buffs function actions. - + RETURN Cost of merge in disk seeks. */ @@ -173,17 +173,17 @@ static double get_merge_many_buffs_cost(uint *buffer, register int i; double total_cost= 0.0; uint *buff_elems= buffer; /* #s of elements in each of merged sequences */ - - /* + + /* Set initial state: first maxbuffer sequences contain max_n_elems elements each, last sequence contains last_n_elems elements. */ for (i = 0; i < (int)maxbuffer; i++) - buff_elems[i]= max_n_elems; + buff_elems[i]= max_n_elems; buff_elems[maxbuffer]= last_n_elems; - /* - Do it exactly as merge_many_buff function does, calling + /* + Do it exactly as merge_many_buff function does, calling get_merge_buffers_cost to get cost of merge_buffers. */ if (maxbuffer >= MERGEBUFF2) @@ -194,17 +194,17 @@ static double get_merge_many_buffs_cost(uint *buffer, for (i = 0; i <= (int) maxbuffer - MERGEBUFF*3/2; i += MERGEBUFF) { total_cost+=get_merge_buffers_cost(buff_elems, elem_size, - buff_elems + i, + buff_elems + i, buff_elems + i + MERGEBUFF-1); lastbuff++; } total_cost+=get_merge_buffers_cost(buff_elems, elem_size, - buff_elems + i, + buff_elems + i, buff_elems + maxbuffer); maxbuffer= lastbuff; } } - + /* Simulate final merge_buff call. */ total_cost += get_merge_buffers_cost(buff_elems, elem_size, buff_elems, buff_elems + maxbuffer); @@ -213,7 +213,7 @@ static double get_merge_many_buffs_cost(uint *buffer, /* - Calculate cost of using Unique for processing nkeys elements of size + Calculate cost of using Unique for processing nkeys elements of size key_size using max_in_memory_size memory. SYNOPSIS @@ -223,12 +223,12 @@ static double get_merge_many_buffs_cost(uint *buffer, nkeys #of elements in Unique key_size size of each elements in bytes max_in_memory_size amount of memory Unique will be allowed to use - + RETURN Cost in disk seeks. - + NOTES - cost(using_unqiue) = + cost(using_unqiue) = cost(create_trees) + (see #1) cost(merge) + (see #2) cost(read_result) (see #3) @@ -237,42 +237,42 @@ static double get_merge_many_buffs_cost(uint *buffer, For each Unique::put operation there will be 2*log2(n+1) elements comparisons, where n runs from 1 tree_size (we assume that all added elements are different). Together this gives: - + n_compares = 2*(log2(2) + log2(3) + ... + log2(N+1)) = 2*log2((N+1)!) - + then cost(tree_creation) = n_compares*ROWID_COMPARE_COST; Total cost of creating trees: (n_trees - 1)*max_size_tree_cost + non_max_size_tree_cost. Approximate value of log2(N!) is calculated by log2_n_fact function. - + 2. Cost of merging. If only one tree is created by Unique no merging will be necessary. Otherwise, we model execution of merge_many_buff function and count - #of merges. (The reason behind this is that number of buffers is small, - while size of buffers is big and we don't want to loose precision with + #of merges. (The reason behind this is that number of buffers is small, + while size of buffers is big and we don't want to loose precision with O(x)-style formula) - + 3. If only one tree is created by Unique no disk io will happen. - Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume + Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume these will be random seeks. */ -double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, +double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, ulong max_in_memory_size) { ulong max_elements_in_tree; ulong last_tree_elems; int n_full_trees; /* number of trees in unique - 1 */ double result; - - max_elements_in_tree= + + max_elements_in_tree= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size); n_full_trees= nkeys / max_elements_in_tree; last_tree_elems= nkeys % max_elements_in_tree; - + /* Calculate cost of creating trees */ result= 2*log2_n_fact(last_tree_elems + 1.0); if (n_full_trees) @@ -285,13 +285,13 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, if (!n_full_trees) return result; - - /* + + /* There is more then one tree and merging is necessary. First, add cost of writing all trees to disk, assuming that all disk writes are sequential. */ - result += DISK_SEEK_BASE_COST * n_full_trees * + result += DISK_SEEK_BASE_COST * n_full_trees * ceil(((double) key_size)*max_elements_in_tree / IO_SIZE); result += DISK_SEEK_BASE_COST * ceil(((double) key_size)*last_tree_elems / IO_SIZE); @@ -303,8 +303,8 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size, return merge_cost; result += merge_cost; - /* - Add cost of reading the resulting sequence, assuming there were no + /* + Add cost of reading the resulting sequence, assuming there were no duplicate elements. */ result += ceil((double)key_size*nkeys/IO_SIZE); @@ -320,7 +320,7 @@ Unique::~Unique() } - /* Write tree to disk; clear tree */ + /* Write tree to disk; clear tree */ bool Unique::flush() { BUFFPEK file_ptr; @@ -359,7 +359,7 @@ Unique::reset() } elements= 0; } - + /* The comparison function, passed to queue_init() in merge_walk() must use comparison function of Uniques::tree, but compare members of struct @@ -386,7 +386,7 @@ C_MODE_END /* DESCRIPTION - Function is very similar to merge_buffers, but instead of writing sorted + Function is very similar to merge_buffers, but instead of writing sorted unique keys to the output file, it invokes walk_action for each key. This saves I/O if you need to pass through all unique keys only once. SYNOPSIS @@ -601,7 +601,7 @@ bool Unique::get(TABLE *table) bool error=1; /* Open cached file if it isn't open */ - outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), MYF(MY_ZEROFILL)); if (!outfile || ! my_b_inited(outfile) && @@ -618,7 +618,7 @@ bool Unique::get(TABLE *table) sort_param.keys= max_in_memory_size / sort_param.sort_length; sort_param.not_killable=1; - if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * + if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) * sort_param.sort_length, MYF(0)))) return 1; @@ -633,7 +633,7 @@ bool Unique::get(TABLE *table) goto err; if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr, file_ptr, file_ptr+maxbuffer,0)) - goto err; + goto err; error=0; err: x_free((gptr) sort_buffer); From 3524b80092486c450366f60ff5b6b7dcc4c39742 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Wed, 4 Jan 2006 10:32:52 +0100 Subject: [PATCH 082/154] Avoid double slash (//) in socket paths, breaks on QNX. --- mysql-test/mysql-test-run.pl | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d64a487758d..2c53b94a248 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -804,6 +804,12 @@ sub command_line_setup () { } } + # On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be + # considered different, so avoid the extra slash (/) in the socket + # paths. + my $sockdir = $opt_tmpdir; + $sockdir =~ s|/+$||; + # Put this into a hash, will be a C struct $master->[0]= @@ -812,7 +818,7 @@ sub command_line_setup () { path_myerr => "$opt_vardir/log/master.err", path_mylog => "$opt_vardir/log/master.log", path_mypid => "$opt_vardir/run/master.pid", - path_mysock => "$opt_tmpdir/master.sock", + path_mysock => "$sockdir/master.sock", path_myport => $opt_master_myport, start_timeout => 400, # enough time create innodb tables @@ -825,7 +831,7 @@ sub command_line_setup () { path_myerr => "$opt_vardir/log/master1.err", path_mylog => "$opt_vardir/log/master1.log", path_mypid => "$opt_vardir/run/master1.pid", - path_mysock => "$opt_tmpdir/master1.sock", + path_mysock => "$sockdir/master1.sock", path_myport => $opt_master_myport + 1, start_timeout => 400, # enough time create innodb tables }; @@ -836,7 +842,7 @@ sub command_line_setup () { path_myerr => "$opt_vardir/log/slave.err", path_mylog => "$opt_vardir/log/slave.log", path_mypid => "$opt_vardir/run/slave.pid", - path_mysock => "$opt_tmpdir/slave.sock", + path_mysock => "$sockdir/slave.sock", path_myport => $opt_slave_myport, start_timeout => 400, }; @@ -847,7 +853,7 @@ sub command_line_setup () { path_myerr => "$opt_vardir/log/slave1.err", path_mylog => "$opt_vardir/log/slave1.log", path_mypid => "$opt_vardir/run/slave1.pid", - path_mysock => "$opt_tmpdir/slave1.sock", + path_mysock => "$sockdir/slave1.sock", path_myport => $opt_slave_myport + 1, start_timeout => 300, }; @@ -858,7 +864,7 @@ sub command_line_setup () { path_myerr => "$opt_vardir/log/slave2.err", path_mylog => "$opt_vardir/log/slave2.log", path_mypid => "$opt_vardir/run/slave2.pid", - path_mysock => "$opt_tmpdir/slave2.sock", + path_mysock => "$sockdir/slave2.sock", path_myport => $opt_slave_myport + 2, start_timeout => 300, }; @@ -868,7 +874,7 @@ sub command_line_setup () { path_err => "$opt_vardir/log/im.err", path_log => "$opt_vardir/log/im.log", path_pid => "$opt_vardir/run/im.pid", - path_sock => "$opt_tmpdir/im.sock", + path_sock => "$sockdir/im.sock", port => $im_port, start_timeout => $master->[0]->{'start_timeout'}, admin_login => 'im_admin', @@ -883,7 +889,7 @@ sub command_line_setup () { server_id => 1, port => $im_mysqld1_port, path_datadir => "$opt_vardir/im_mysqld_1.data", - path_sock => "$opt_tmpdir/mysqld_1.sock", + path_sock => "$sockdir/mysqld_1.sock", path_pid => "$opt_vardir/run/mysqld_1.pid", }; @@ -892,7 +898,7 @@ sub command_line_setup () { server_id => 2, port => $im_mysqld2_port, path_datadir => "$opt_vardir/im_mysqld_2.data", - path_sock => "$opt_tmpdir/mysqld_2.sock", + path_sock => "$sockdir/mysqld_2.sock", path_pid => "$opt_vardir/run/mysqld_2.pid", nonguarded => 1, }; From aa6400a356b64f9f3e2b0dd1a89174bfaab23d9b Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Wed, 4 Jan 2006 11:38:58 +0100 Subject: [PATCH 083/154] ndb - Make testDatabuffer clean up tables --- ndb/test/ndbapi/testDataBuffers.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/ndb/test/ndbapi/testDataBuffers.cpp b/ndb/test/ndbapi/testDataBuffers.cpp index 03d52252334..27e241fa87a 100644 --- a/ndb/test/ndbapi/testDataBuffers.cpp +++ b/ndb/test/ndbapi/testDataBuffers.cpp @@ -254,12 +254,6 @@ testcase(int flag) ndbout << "tab=" << tab << " cols=" << attrcnt << " size max=" << smax << " tot=" << stot << endl; - ndb = new Ndb("TEST_DB"); - if (ndb->init() != 0) - return ndberror("init"); - if (ndb->waitUntilReady(30) < 0) - return ndberror("waitUntilReady"); - if ((tcon = NdbSchemaCon::startSchemaTrans(ndb)) == 0) return ndberror("startSchemaTransaction"); if ((top = tcon->getNdbSchemaOp()) == 0) @@ -541,7 +535,6 @@ testcase(int flag) return ndberror("key %d not found", k); ndbout << "scanned " << key << endl; - ndb = 0; ndbout << "done" << endl; return 0; } @@ -605,7 +598,23 @@ NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuff return NDBT_ProgramExit(NDBT_WRONGARGS); } } + unsigned ok = true; + + ndb = new Ndb("TEST_DB"); + if (ndb->init() != 0) + { + ndberror("init"); + ok = false; + goto out; + } + if (ndb->waitUntilReady(30) < 0) + { + ndberror("waitUntilReady"); + ok = false; + goto out; + } + for (i = 1; 0 == loopcnt || i <= loopcnt; i++) { ndbout << "=== loop " << i << " ===" << endl; for (int flag = 0; flag < (1<getDictionary(); + dict->dropTable(tab); } } + out: + delete ndb; return NDBT_ProgramExit(ok ? NDBT_OK : NDBT_FAILED); } From 85575904fae96f54a6da456bc104ba5a503e573c Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Wed, 4 Jan 2006 15:25:32 +0100 Subject: [PATCH 084/154] BUG#14931: Temporarily add synchronization to avoid sporadic test failures until the bug is fixed. --- mysql-test/r/rpl_sp.result | 3 +++ mysql-test/t/rpl_sp.test | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 41bcfc7d72c..c9a9e162fa6 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -57,6 +57,9 @@ insert into t1 values (15); grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; +SELECT 1; +1 +1 create procedure foo4() deterministic begin diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index 386582f8f1b..8fa330584e2 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -87,6 +87,14 @@ grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; +# ToDo: BUG#14931: There is a race between the last grant binlogging, and +# the binlogging in the new connection made below, causing sporadic test +# failures due to switched statement order in binlog. To fix this we do +# SELECT 1 in the first connection before starting the second, ensuring +# that binlogging is done in the expected order. +# Please remove this SELECT 1 when BUG#14931 is fixed. +SELECT 1; + connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); connection con1; From f7d6fa6f1733e64f202e517d7391c868a53b125a Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 4 Jan 2006 17:35:30 +0300 Subject: [PATCH 085/154] A fix for Bug#7209 "Client error with "Access Denied" on updates when high concurrency": remove HASH::current_record and make it an external search parameter, so that it can not be the cause of a race condition under high concurrent load. The bug was in a race condition in table_hash_search, when column_priv_hash.current_record was overwritten simultaneously by multiple threads, causing the search for a suitable grant record to fail. No test case as the bug is repeatable only under concurrent load. --- include/hash.h | 14 +++++++---- mysys/hash.c | 60 ++++++++++++++++++++++++++++-------------------- mysys/testhash.c | 9 ++++---- sql/lock.cc | 5 ++-- sql/sql_acl.cc | 9 ++++---- sql/sql_base.cc | 22 ++++++++++++------ sql/sql_cache.cc | 10 ++++---- 7 files changed, 79 insertions(+), 50 deletions(-) diff --git a/include/hash.h b/include/hash.h index 9a6d91036e1..8f5ff21ae5e 100644 --- a/include/hash.h +++ b/include/hash.h @@ -33,7 +33,7 @@ typedef void (*hash_free_key)(void *); typedef struct st_hash { uint key_offset,key_length; /* Length of key if const length */ - uint records,blength,current_record; + uint records, blength; uint flags; DYNAMIC_ARRAY array; /* Place for hash_keys */ hash_get_key get_key; @@ -41,6 +41,9 @@ typedef struct st_hash { CHARSET_INFO *charset; } HASH; +/* A search iterator state */ +typedef uint HASH_SEARCH_STATE; + #define hash_init(A,B,C,D,E,F,G,H) _hash_init(A,B,C,D,E,F,G, H CALLER_INFO) my_bool _hash_init(HASH *hash, CHARSET_INFO *charset, uint default_array_elements, uint key_offset, @@ -49,12 +52,15 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset, void hash_free(HASH *tree); void my_hash_reset(HASH *hash); byte *hash_element(HASH *hash,uint idx); -gptr hash_search(HASH *info,const byte *key,uint length); -gptr hash_next(HASH *info,const byte *key,uint length); +gptr hash_search(const HASH *info, const byte *key, uint length); +gptr hash_first(const HASH *info, const byte *key, uint length, + HASH_SEARCH_STATE *state); +gptr hash_next(const HASH *info, const byte *key, uint length, + HASH_SEARCH_STATE *state); my_bool my_hash_insert(HASH *info,const byte *data); my_bool hash_delete(HASH *hash,byte *record); my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length); -void hash_replace(HASH *hash, uint idx, byte *new_row); +void hash_replace(HASH *hash, HASH_SEARCH_STATE *state, byte *new_row); my_bool hash_check(HASH *hash); /* Only in debug library */ #define hash_clear(H) bzero((char*) (H),sizeof(*(H))) diff --git a/mysys/hash.c b/mysys/hash.c index ffebdf76144..75135a470c9 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -36,9 +36,10 @@ typedef struct st_hash_info { static uint hash_mask(uint hashnr,uint buffmax,uint maxlength); static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink); -static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length); +static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key, + uint length); -static uint calc_hash(HASH *hash,const byte *key,uint length) +static uint calc_hash(const HASH *hash, const byte *key, uint length) { ulong nr1=1, nr2=4; hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2); @@ -63,7 +64,6 @@ _hash_init(HASH *hash,CHARSET_INFO *charset, hash->key_offset=key_offset; hash->key_length=key_length; hash->blength=1; - hash->current_record= NO_RECORD; /* For the future */ hash->get_key=get_key; hash->free=free_element; hash->flags=flags; @@ -135,7 +135,6 @@ void my_hash_reset(HASH *hash) reset_dynamic(&hash->array); /* Set row pointers so that the hash can be reused at once */ hash->blength= 1; - hash->current_record= NO_RECORD; DBUG_VOID_RETURN; } @@ -147,7 +146,8 @@ void my_hash_reset(HASH *hash) */ static inline char* -hash_key(HASH *hash,const byte *record,uint *length,my_bool first) +hash_key(const HASH *hash, const byte *record, uint *length, + my_bool first) { if (hash->get_key) return (*hash->get_key)(record,length,first); @@ -163,8 +163,8 @@ static uint hash_mask(uint hashnr,uint buffmax,uint maxlength) return (hashnr & ((buffmax >> 1) -1)); } -static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax, - uint maxlength) +static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos, + uint buffmax, uint maxlength) { uint length; byte *key= (byte*) hash_key(hash,pos->data,&length,0); @@ -186,14 +186,25 @@ unsigned int rec_hashnr(HASH *hash,const byte *record) } - /* Search after a record based on a key */ - /* Sets info->current_ptr to found record */ +gptr hash_search(const HASH *hash, const byte *key, uint length) +{ + HASH_SEARCH_STATE state; + return hash_first(hash, key, length, &state); +} -gptr hash_search(HASH *hash,const byte *key,uint length) +/* + Search after a record based on a key + + NOTE + Assigns the number of the found record to HASH_SEARCH_STATE state +*/ + +gptr hash_first(const HASH *hash, const byte *key, uint length, + HASH_SEARCH_STATE *current_record) { HASH_LINK *pos; uint flag,idx; - DBUG_ENTER("hash_search"); + DBUG_ENTER("hash_first"); flag=1; if (hash->records) @@ -206,7 +217,7 @@ gptr hash_search(HASH *hash,const byte *key,uint length) if (!hashcmp(hash,pos,key,length)) { DBUG_PRINT("exit",("found key at %d",idx)); - hash->current_record= idx; + *current_record= idx; DBUG_RETURN (pos->data); } if (flag) @@ -218,31 +229,32 @@ gptr hash_search(HASH *hash,const byte *key,uint length) } while ((idx=pos->next) != NO_RECORD); } - hash->current_record= NO_RECORD; + *current_record= NO_RECORD; DBUG_RETURN(0); } /* Get next record with identical key */ /* Can only be called if previous calls was hash_search */ -gptr hash_next(HASH *hash,const byte *key,uint length) +gptr hash_next(const HASH *hash, const byte *key, uint length, + HASH_SEARCH_STATE *current_record) { HASH_LINK *pos; uint idx; - if (hash->current_record != NO_RECORD) + if (*current_record != NO_RECORD) { HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*); - for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next) + for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next) { pos=data+idx; if (!hashcmp(hash,pos,key,length)) { - hash->current_record= idx; + *current_record= idx; return pos->data; } } - hash->current_record=NO_RECORD; + *current_record= NO_RECORD; } return 0; } @@ -282,7 +294,8 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink) > 0 key of record > key */ -static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length) +static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key, + uint length) { uint rec_keylength; byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1); @@ -308,7 +321,6 @@ my_bool my_hash_insert(HASH *info,const byte *record) if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array))) return(TRUE); /* No more memory */ - info->current_record= NO_RECORD; data=dynamic_element(&info->array,0,HASH_LINK*); halfbuff= info->blength >> 1; @@ -451,7 +463,6 @@ my_bool hash_delete(HASH *hash,byte *record) } if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1; - hash->current_record= NO_RECORD; lastpos=data+hash->records; /* Remove link to record */ @@ -544,7 +555,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length) if ((idx=pos->next) == NO_RECORD) DBUG_RETURN(1); /* Not found in links */ } - hash->current_record= NO_RECORD; org_link= *pos; empty=idx; @@ -594,10 +604,10 @@ byte *hash_element(HASH *hash,uint idx) isn't changed */ -void hash_replace(HASH *hash, uint idx, byte *new_row) +void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, byte *new_row) { - if (idx != NO_RECORD) /* Safety */ - dynamic_element(&hash->array,idx,HASH_LINK*)->data=new_row; + if (*current_record != NO_RECORD) /* Safety */ + dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row; } diff --git a/mysys/testhash.c b/mysys/testhash.c index 72badffdbcd..d15016113cd 100644 --- a/mysys/testhash.c +++ b/mysys/testhash.c @@ -74,7 +74,7 @@ static int do_test() bzero((char*) key1,sizeof(key1[0])*1000); printf("- Creating hash\n"); - if (hash_init(&hash,recant/2,0,6,0,free_record,0)) + if (hash_init(&hash, default_charset_info, recant/2, 0, 6, 0, free_record, 0)) goto err; printf("- Writing records:\n"); @@ -172,15 +172,16 @@ static int do_test() break; if (key1[j] > 1) { + HASH_SEARCH_STATE state; printf("- Testing identical read\n"); sprintf(key,"%6d",j); pos=1; - if (!(recpos=hash_search(&hash,key,0))) + if (!(recpos= hash_first(&hash, key, 0, &state))) { printf("can't find key1: \"%s\"\n",key); goto err; } - while (hash_next(&hash,key,0) && pos < (ulong) (key1[j]+10)) + while (hash_next(&hash, key, 0, &state) && pos < (ulong) (key1[j]+10)) pos++; if (pos != (ulong) key1[j]) { @@ -189,7 +190,7 @@ static int do_test() } } printf("- Creating output heap-file 2\n"); - if (hash_init(&hash2,hash.records,0,0,hash2_key,free_record,0)) + if (hash_init(&hash2, default_charset_info, hash.records, 0, 0, hash2_key, free_record,0)) goto err; printf("- Copying and removing records\n"); diff --git a/sql/lock.cc b/sql/lock.cc index a571b7f8ee8..f65ce69bb80 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -641,6 +641,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) char key[MAX_DBKEY_LENGTH]; char *db= table_list->db; uint key_length; + HASH_SEARCH_STATE state; DBUG_ENTER("lock_table_name"); DBUG_PRINT("enter",("db: %s name: %s", db, table_list->real_name)); @@ -651,9 +652,9 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) /* Only insert the table if we haven't insert it already */ - for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; + for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state); table ; - table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) + table = (TABLE*) hash_next(&open_cache, (byte*)key, key_length, &state)) if (table->in_use == thd) DBUG_RETURN(0); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0ee83424d9f..74f7a1dcf06 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1988,14 +1988,15 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, char helping [NAME_LEN*2+USERNAME_LENGTH+3]; uint len; GRANT_TABLE *grant_table,*found=0; + HASH_SEARCH_STATE state; len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; - for (grant_table=(GRANT_TABLE*) hash_search(&column_priv_hash, - (byte*) helping, - len) ; + for (grant_table=(GRANT_TABLE*) hash_first(&column_priv_hash, + (byte*) helping, + len, &state) ; grant_table ; grant_table= (GRANT_TABLE*) hash_next(&column_priv_hash,(byte*) helping, - len)) + len, &state)) { if (exact) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8b1fa754929..c8443948a4a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -799,6 +799,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, reg1 TABLE *table; char key[MAX_DBKEY_LENGTH]; uint key_length; + HASH_SEARCH_STATE state; DBUG_ENTER("open_table"); /* find a unused table in the open table cache */ @@ -863,9 +864,11 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, /* close handler tables which are marked for flush */ mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); - for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; + for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length, + &state); table && table->in_use ; - table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) + table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length, + &state)) { if (table->version != refresh_version) { @@ -1236,12 +1239,14 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock) { do { + HASH_SEARCH_STATE state; char *key= table->table_cache_key; uint key_length=table->key_length; - for (TABLE *search=(TABLE*) hash_search(&open_cache, - (byte*) key,key_length) ; + for (TABLE *search= (TABLE*) hash_first(&open_cache, (byte*) key, + key_length, &state); search ; - search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) + search= (TABLE*) hash_next(&open_cache, (byte*) key, + key_length, &state)) { if (search->locked_by_flush || search->locked_by_name && wait_for_name_lock || @@ -2958,11 +2963,14 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; for (;;) { + HASH_SEARCH_STATE state; result= signalled= 0; - for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; + for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length, + &state); table; - table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) + table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length, + &state)) { THD *in_use; table->version=0L; /* Free when thread is ready */ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b40257511f7..457478e90db 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2873,6 +2873,7 @@ my_bool Query_cache::move_by_type(byte **border, } case Query_cache_block::TABLE: { + HASH_SEARCH_STATE record_idx; DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block)); if (*border == 0) break; @@ -2890,7 +2891,7 @@ my_bool Query_cache::move_by_type(byte **border, byte *key; uint key_length; key=query_cache_table_get_key((byte*) block, &key_length, 0); - hash_search(&tables, (byte*) key, key_length); + hash_first(&tables, (byte*) key, key_length, &record_idx); block->destroy(); new_block->init(len); @@ -2924,7 +2925,7 @@ my_bool Query_cache::move_by_type(byte **border, /* Fix pointer to table name */ new_block->table()->table(new_block->table()->db() + tablename_offset); /* Fix hash to point at moved block */ - hash_replace(&tables, tables.current_record, (byte*) new_block); + hash_replace(&tables, &record_idx, (byte*) new_block); DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx", len, (ulong) new_block, (ulong) *border)); @@ -2932,6 +2933,7 @@ my_bool Query_cache::move_by_type(byte **border, } case Query_cache_block::QUERY: { + HASH_SEARCH_STATE record_idx; DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block)); if (*border == 0) break; @@ -2949,7 +2951,7 @@ my_bool Query_cache::move_by_type(byte **border, byte *key; uint key_length; key=query_cache_query_get_key((byte*) block, &key_length, 0); - hash_search(&queries, (byte*) key, key_length); + hash_first(&queries, (byte*) key, key_length, &record_idx); // Move table of used tables memmove((char*) new_block->table(0), (char*) block->table(0), ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table))); @@ -3017,7 +3019,7 @@ my_bool Query_cache::move_by_type(byte **border, net->query_cache_query= (gptr) new_block; } /* Fix hash to point at moved block */ - hash_replace(&queries, queries.current_record, (byte*) new_block); + hash_replace(&queries, &record_idx, (byte*) new_block); DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx", len, (ulong) new_block, (ulong) *border)); break; From f6b1f10707b75463dc0f1f2a64416feb2ac80432 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Wed, 4 Jan 2006 16:02:41 +0100 Subject: [PATCH 086/154] Fix QNX test abort in release builds and pushbuild, avoid killing our parent when we are not the process group leader. --- mysql-test/lib/mtr_process.pl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index b3a243444c1..4d88c9b3322 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -890,7 +890,14 @@ sub mtr_exit ($) { # cluck("Called mtr_exit()"); mtr_timer_stop_all($::glob_timers); local $SIG{HUP} = 'IGNORE'; - kill('HUP', -$$); + # ToDo: Signalling -$$ will only work if we are the process group + # leader (in fact on QNX it will signal our session group leader, + # which might be Do-compile or Pushbuild, causing tests to be + # aborted). So we only do it if we are the group leader. We might + # set ourselves as the group leader at startup (with + # POSIX::setpgrp(0,0)), but then care must be needed to always do + # proper child process cleanup. + kill('HUP', -$$) if $$ == getpgrp(); sleep 2; exit($code); } From f13dff7a72f309748f0b687a88421ee67e9239e7 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Wed, 4 Jan 2006 16:38:54 +0100 Subject: [PATCH 087/154] EADDRINUSE is not defined on Windows. --- include/my_global.h | 3 +++ sql/mysqld.cc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/my_global.h b/include/my_global.h index e62f6c269aa..0df9ac78eb2 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -862,6 +862,7 @@ typedef off_t os_off_t; #define SOCKET_EAGAIN WSAEINPROGRESS #define SOCKET_ETIMEDOUT WSAETIMEDOUT #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#define SOCKET_EADDRINUSE WSAEADDRINUSE #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE #elif defined(OS2) @@ -870,6 +871,7 @@ typedef off_t os_off_t; #define SOCKET_EAGAIN SOCEINPROGRESS #define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK +#define SOCKET_EADDRINUSE SOCEADDRINUSE #define SOCKET_ENFILE SOCENFILE #define SOCKET_EMFILE SOCEMFILE #define closesocket(A) soclose(A) @@ -880,6 +882,7 @@ typedef off_t os_off_t; #define SOCKET_EAGAIN EAGAIN #define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK EWOULDBLOCK +#define SOCKET_EADDRINUSE EADDRINUSE #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 14cbaf28ae3..8934b872c94 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1401,7 +1401,7 @@ static void network_init(void) { if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr), sizeof(IPaddr))) >= 0) || - (socket_errno != EADDRINUSE) || + (socket_errno != SOCKET_EADDRINUSE) || (waited >= mysqld_port_timeout)) break; sql_print_information("Retrying bind on TCP/IP port %u", mysqld_port); From 4a4b8eacc1b5791ff53c6c596bb756c6d690d38c Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 4 Jan 2006 21:39:39 +0300 Subject: [PATCH 088/154] Post-merge fixes. --- sql/sql_acl.cc | 1 - sql/sql_base.cc | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 22fecda2599..66a1b1f9b11 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2245,7 +2245,6 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, uint len; GRANT_NAME *grant_name,*found=0; HASH_SEARCH_STATE state; - GRANT_TABLE *grant_table,*found=0; len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; for (grant_name= (GRANT_NAME*) hash_first(name_hash, (byte*) helping, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 290f16a09d6..0b414f59223 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1624,7 +1624,8 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock) { char *key= table->s->table_cache_key; uint key_length= table->s->key_length; - for (TABLE *search= (TABLE*) hash_search(&open_cache, (byte*) key, + HASH_SEARCH_STATE state; + for (TABLE *search= (TABLE*) hash_first(&open_cache, (byte*) key, key_length, &state); search ; search= (TABLE*) hash_next(&open_cache, (byte*) key, From 71215d0cbcae549b23048641e437a04f1ee7de37 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Thu, 5 Jan 2006 23:39:45 +0100 Subject: [PATCH 089/154] Port to Win64/x64 in Visual Studio 2005 --- include/config-win.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/config-win.h b/include/config-win.h index 528bc8a8cdd..cebc4c8b82b 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -22,6 +22,11 @@ functions */ #define _WIN32_WINNT 0x0500 #endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 +/* Avoid endless warnings about sprintf() etc. being unsafe. */ +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + #include #include #include /* Because of rint() */ @@ -325,6 +330,11 @@ inline double ulonglong2double(ulonglong value) #define HAVE_SETFILEPOINTER #define HAVE_VIO_READ_BUFF +#if defined(_WIN64) && defined(_M_X64) +/* Avoid type conflicts with built-in functions. */ +#define HAVE_STRNLEN +#endif + #ifndef __NT__ #undef FILE_SHARE_DELETE #define FILE_SHARE_DELETE 0 /* Not implemented on Win 98/ME */ From 6e22e29de669b95aefc4f5f7ce46420e52c99870 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Fri, 6 Jan 2006 00:47:49 +0200 Subject: [PATCH 090/154] Review fixes of new pushed code - Fixed tests - Optimized new code - Fixed some unlikely core dumps - Better bug fixes for: - #14397 - OPTIMIZE TABLE with an open HANDLER causes a crash - #14850 (ERROR 1062 when a quering a view using a Group By on a column that can be null --- mysql-test/r/create.result | 43 ++++++++++------ mysql-test/r/handler.result | 2 +- mysql-test/r/kill.result | 2 - mysql-test/r/mysqlshow.result | 2 +- mysql-test/r/trigger.result | 7 ++- mysql-test/r/view.result | 3 ++ mysql-test/t/create.test | 16 ++++++ mysql-test/t/disabled.def | 1 - mysql-test/t/handler.test | 2 +- mysql-test/t/kill.test | 13 +++-- mysql-test/t/mysqlshow.test | 2 +- mysql-test/t/trigger.test | 9 ++-- mysql-test/t/view.test | 1 + sql/field.cc | 4 +- sql/ha_federated.cc | 3 +- sql/ha_ndbcluster.cc | 22 +++++---- sql/item.cc | 6 +++ sql/item.h | 6 +-- sql/log_event.cc | 93 ++++++++++++++++++++--------------- sql/opt_range.cc | 14 ++++-- sql/parse_file.cc | 2 +- sql/sp.cc | 70 +++++++++++++------------- sql/sp_head.cc | 68 ++++++++++++++----------- sql/sp_head.h | 4 +- sql/sql_acl.cc | 2 +- sql/sql_base.cc | 1 - sql/sql_handler.cc | 35 +++---------- sql/sql_insert.cc | 6 ++- sql/sql_parse.cc | 12 ++--- sql/sql_select.cc | 2 +- sql/sql_trigger.cc | 32 +++++++----- 31 files changed, 269 insertions(+), 216 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index a201af78518..199fdd1eb5d 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -287,7 +287,6 @@ a b create table if not exists t1 select 3 as 'a',4 as 'b'; Warnings: Note 1050 Table 't1' already exists -Warning 1364 Field 'a' doesn't have a default value create table if not exists t1 select 3 as 'a',3 as 'b'; ERROR 23000: Duplicate entry '3' for key 1 select * from t1; @@ -645,8 +644,6 @@ create table t1 ( a varchar(112) charset utf8 collate utf8_bin not null, primary key (a) ) select 'test' as a ; -Warnings: -Warning 1364 Field 'a' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -662,9 +659,6 @@ create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) ) select a, 1 as b from t2 ; -Warnings: -Warning 1364 Field 'a' doesn't have a default value -Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -674,12 +668,37 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int not null, primary key (a) +) select a, 1 as c from t2 ; +Warnings: +Warning 1364 Field 'b' doesn't have a default value +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) NOT NULL, + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, + `c` bigint(1) NOT NULL default '0', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +a varchar(12) charset utf8 collate utf8_bin not null, +b int null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) default NULL, + `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, + `c` bigint(1) NOT NULL default '0', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, b int not null, primary key (a) ) select 'a' as a , 1 as b from t2 ; -Warnings: -Warning 1364 Field 'a' doesn't have a default value -Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -692,8 +711,6 @@ create table t1 ( a varchar(12) charset utf8 collate utf8_bin, b int not null, primary key (a) ) select 'a' as a , 1 as b from t2 ; -Warnings: -Warning 1364 Field 'b' doesn't have a default value show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -712,8 +729,6 @@ a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; -Warnings: -Warning 1364 Field 'a1' doesn't have a default value drop table t2; create table t2 ( a1 varchar(12) charset utf8 collate utf8_bin, @@ -729,8 +744,6 @@ a1 varchar(12) charset utf8 collate utf8_bin not null, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, primary key (a1) ) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ; -Warnings: -Warning 1364 Field 'a1' doesn't have a default value drop table t2; create table t2 ( a int default 3, b int default 3) select a1,a2 from t1; diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 133683fb273..104025e83eb 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1,t3,t4,t5; create table t1 (a int, b char(10), key a(a), key b(a,b)); insert into t1 values (17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"), diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index 754568093ff..2413834be4f 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -5,8 +5,6 @@ select ((@id := kill_id) - kill_id) from t1; ((@id := kill_id) - kill_id) 0 kill @id; -select 1; -Got one of the listed errors select ((@id := kill_id) - kill_id) from t1; ((@id := kill_id) - kill_id) 0 diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index 355c20fdad3..942cde83f21 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1,t2; +DROP TABLE IF EXISTS t1,t2,test1,test2; CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a int, b int); diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ff92fc543d4..0ad5c485b28 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -767,8 +767,7 @@ deallocate prepare stmt1; drop procedure p1; drop table t1, t2, t3; create table t1 (a int); -drop procedure if exists p2; -CREATE PROCEDURE `p2`() +CREATE PROCEDURE `p1`() begin insert into t1 values (1); end// @@ -777,6 +776,6 @@ begin declare done int default 0; set done= not done; end// -CALL p2(); -drop procedure p2; +CALL p1(); +drop procedure p1; drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ebb2c190eb1..c26671ac937 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2418,6 +2418,9 @@ drop view v1; drop table t1; create table t1(f1 int, f2 int); insert into t1 values (null, 10), (null,2); +select f1, sum(f2) from t1 group by f1; +f1 sum(f2) +NULL 12 create view v1 as select * from t1; select f1, sum(f2) from v1 group by f1; f1 sum(f2) diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 470a7bcbb59..fcbdff7ec5b 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -571,6 +571,22 @@ create table t1 ( show create table t1; drop table t1; +--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int not null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +drop table t1; + +--warning 1364 +create table t1 ( + a varchar(12) charset utf8 collate utf8_bin not null, + b int null, primary key (a) +) select a, 1 as c from t2 ; +show create table t1; +drop table t1; + --warning 1364 create table t1 ( a varchar(12) charset utf8 collate utf8_bin not null, diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index fe95a543fb5..b96aa7befd9 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -14,4 +14,3 @@ sp-goto : GOTO is currently is disabled - will be fixed in the future rpl_relayrotate : Unstable test case, bug#12429 rpl_until : Unstable test case, bug#12429 rpl_deadlock : Unstable test case, bug#12429 -kill : Unstable test case, bug#9712 diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index f3e14c3cd2b..3fb09df5f2f 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1; +drop table if exists t1,t3,t4,t5; --enable_warnings create table t1 (a int, b char(10), key a(a), key b(a,b)); diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 7f3a9932d31..c50c35825fc 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -25,11 +25,18 @@ select ((@id := kill_id) - kill_id) from t1; kill @id; connection con1; ---sleep 1 +--sleep 2 -# this statement should fail ---error 2006,2013 +--disable_query_log +--disable_result_log +# One of the following statements should fail +--error 0,2006,2013 select 1; +--error 0,2006,2013 +select 1; +--enable_query_log +--enable_result_log + --enable_reconnect # this should work, and we should have a new connection_id() select ((@id := kill_id) - kill_id) from t1; diff --git a/mysql-test/t/mysqlshow.test b/mysql-test/t/mysqlshow.test index 1e2e97a4e07..78c4ae2b531 100644 --- a/mysql-test/t/mysqlshow.test +++ b/mysql-test/t/mysqlshow.test @@ -2,7 +2,7 @@ -- source include/not_embedded.inc --disable_warnings -DROP TABLE IF EXISTS t1,t2; +DROP TABLE IF EXISTS t1,t2,test1,test2; --enable_warnings # diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index d4fa5268762..acd3297e12a 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -928,11 +928,8 @@ drop table t1, t2, t3; # operator. # create table t1 (a int); ---disable_warnings -drop procedure if exists p2; ---enable_warnings DELIMITER //; -CREATE PROCEDURE `p2`() +CREATE PROCEDURE `p1`() begin insert into t1 values (1); end// @@ -942,7 +939,7 @@ begin set done= not done; end// DELIMITER ;// -CALL p2(); -drop procedure p2; +CALL p1(); +drop procedure p1; drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ac103278f08..bc54287afb2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2276,6 +2276,7 @@ drop table t1; # create table t1(f1 int, f2 int); insert into t1 values (null, 10), (null,2); +select f1, sum(f2) from t1 group by f1; create view v1 as select * from t1; select f1, sum(f2) from v1 group by f1; drop view v1; diff --git a/sql/field.cc b/sql/field.cc index b70e2a92618..9e73c132d68 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6204,8 +6204,8 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table) This is done to ensure that ALTER TABLE will convert old VARCHAR fields to now VARCHAR fields. */ - if (new_field= new Field_varstring(field_length, maybe_null(), - field_name, new_table, charset())) + if ((new_field= new Field_varstring(field_length, maybe_null(), + field_name, new_table, charset()))) { /* delayed_insert::get_local_table() needs a ptr copied from old table. diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d2f827989f5..14b79a9a418 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -2616,8 +2616,7 @@ int ha_federated::stash_remote_error() { DBUG_ENTER("ha_federated::stash_remote_error()"); remote_error_number= mysql_errno(mysql); - my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s", - mysql_error(mysql)); + strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1); DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM); } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index cdd406d473c..81d11e0a27c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -300,7 +300,8 @@ Thd_ndb::~Thd_ndb() if (ndb) { #ifndef DBUG_OFF - Ndb::Free_list_usage tmp; tmp.m_name= 0; + Ndb::Free_list_usage tmp; + tmp.m_name= 0; while (ndb->get_free_list_usage(&tmp)) { uint leaked= (uint) tmp.m_created - tmp.m_free; @@ -312,8 +313,8 @@ Thd_ndb::~Thd_ndb() } #endif delete ndb; + ndb= NULL; } - ndb= NULL; changed_tables.empty(); } @@ -4883,7 +4884,8 @@ bool ndbcluster_end() if (g_ndb) { #ifndef DBUG_OFF - Ndb::Free_list_usage tmp; tmp.m_name= 0; + Ndb::Free_list_usage tmp; + tmp.m_name= 0; while (g_ndb->get_free_list_usage(&tmp)) { uint leaked= (uint) tmp.m_created - tmp.m_free; @@ -4895,10 +4897,9 @@ bool ndbcluster_end() } #endif delete g_ndb; + g_ndb= NULL; } - g_ndb= NULL; - if (g_ndb_cluster_connection) - delete g_ndb_cluster_connection; + delete g_ndb_cluster_connection; g_ndb_cluster_connection= NULL; hash_free(&ndbcluster_open_tables); @@ -7443,7 +7444,8 @@ ndbcluster_show_status(THD* thd) if (have_ndbcluster != SHOW_OPTION_YES) { my_message(ER_NOT_SUPPORTED_YET, - "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined", + "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is " + "defined", MYF(0)); DBUG_RETURN(TRUE); } @@ -7454,13 +7456,15 @@ ndbcluster_show_status(THD* thd) field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG)); field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG)); - if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + if (protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb) { Ndb* ndb= (get_thd_ndb(thd))->ndb; - Ndb::Free_list_usage tmp; tmp.m_name= 0; + Ndb::Free_list_usage tmp; + tmp.m_name= 0; while (ndb->get_free_list_usage(&tmp)) { protocol->prepare_for_resend(); diff --git a/sql/item.cc b/sql/item.cc index 6d5855cd0ca..dadbd31c81f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4843,6 +4843,12 @@ int Item_ref::save_in_field(Field *to, bool no_conversions) } +void Item_ref::save_org_in_field(Field *field) +{ + (*ref)->save_org_in_field(field); +} + + void Item_ref::make_field(Send_field *field) { (*ref)->make_field(field); diff --git a/sql/item.h b/sql/item.h index 4201790e907..c64e6586d5f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1612,11 +1612,7 @@ public: void make_field(Send_field *field); bool fix_fields(THD *, Item **); int save_in_field(Field *field, bool no_conversions); - void save_org_in_field(Field *field) - { - (*ref)->save_org_in_field(field); - null_value= (*ref)->null_value; - } + void save_org_in_field(Field *field); enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } Field *get_tmp_table_field() diff --git a/sql/log_event.cc b/sql/log_event.cc index 056bcca1a02..519b077b17b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -114,13 +114,24 @@ static char *pretty_print_str(char *packet, char *str, int len) /* - slave_load_file_stem() + Creates a temporary name for load data infile: + + SYNOPSIS + slave_load_file_stem() + buf Store new filename here + file_id File_id (part of file name) + event_server_id Event_id (part of file name) + ext Extension for file name + + RETURN + Pointer to start of extension */ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -static inline char* slave_load_file_stem(char*buf, uint file_id, - int event_server_id) +static char *slave_load_file_stem(char *buf, uint file_id, + int event_server_id, const char *ext) { + char *res; fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME); to_unix_path(buf); @@ -129,7 +140,9 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, *buf++ = '-'; buf = int10_to_str(event_server_id, buf, 10); *buf++ = '-'; - return int10_to_str(file_id, buf, 10); + res= int10_to_str(file_id, buf, 10); + strmov(res, ext); // Add extension last + return res; // Pointer to extension } #endif @@ -901,7 +914,6 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) /* Pretty-print event common header if header is exactly 19 bytes */ if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN) { - DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); fprintf(file, "# Position Timestamp Type Master ID " "Size Master Pos Flags \n"); fprintf(file, "# %8.8lx %02x %02x %02x %02x %02x " @@ -927,7 +939,6 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) if (i % 16 == 15) { - DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); fprintf(file, "# %8.8lx %-48.48s |%16s|\n", (unsigned long) (hexdump_from + (i & 0xfffffff0)), hex_string, char_string); @@ -941,12 +952,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) *c= '\0'; /* Non-full last line */ - if (hex_string[0]) { - DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from); + if (hex_string[0]) fprintf(file, "# %8.8lx %-48.48s |%s|\n# ", (unsigned long) (hexdump_from + (i & 0xfffffff0)), hex_string, char_string); - } } } @@ -4160,16 +4169,15 @@ void Create_file_log_event::pack_info(Protocol *protocol) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Create_file_log_event::exec_event(struct st_relay_log_info* rli) { - char proc_info[17+FN_REFLEN+10], *fname_buf= proc_info+17; - char *p; + char proc_info[17+FN_REFLEN+10], *fname_buf; + char *ext; int fd = -1; IO_CACHE file; int error = 1; bzero((char*)&file, sizeof(file)); - p = slave_load_file_stem(fname_buf, file_id, server_id); - strmov(p, ".info"); // strmov takes less code than memcpy - strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 + fname_buf= strmov(proc_info, "Making temp file "); + ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info"); thd->proc_info= proc_info; my_delete(fname_buf, MYF(0)); // old copy may exist already if ((fd= my_create(fname_buf, CREATE_MODE, @@ -4178,19 +4186,21 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf); + slave_print_error(rli,my_errno, + "Error in Create_file event: could not open file '%s'", + fname_buf); goto err; } // a trick to avoid allocating another buffer - strmov(p, ".data"); - fname = fname_buf; - fname_len = (uint)(p-fname) + 5; + fname= fname_buf; + fname_len= (uint) (strmov(ext, ".data") - fname); if (write_base(&file)) { - strmov(p, ".info"); // to have it right in the error message + strmov(ext, ".info"); // to have it right in the error message slave_print_error(rli,my_errno, - "Error in Create_file event: could not write to file '%s'", + "Error in Create_file event: could not write to file " + "'%s'", fname_buf); goto err; } @@ -4203,12 +4213,16 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, MYF(MY_WME))) < 0) { - slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf); + slave_print_error(rli,my_errno, + "Error in Create_file event: could not open file '%s'", + fname_buf); goto err; } if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) { - slave_print_error(rli,my_errno, "Error in Create_file event: write to '%s' failed", fname_buf); + slave_print_error(rli,my_errno, + "Error in Create_file event: write to '%s' failed", + fname_buf); goto err; } error=0; // Everything is ok @@ -4332,13 +4346,12 @@ int Append_block_log_event::get_create_or_append() const int Append_block_log_event::exec_event(struct st_relay_log_info* rli) { char proc_info[17+FN_REFLEN+10], *fname= proc_info+17; - char *p= slave_load_file_stem(fname, file_id, server_id); int fd; int error = 1; DBUG_ENTER("Append_block_log_event::exec_event"); - memcpy(p, ".data", 6); - strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0 + fname= strmov(proc_info, "Making temp file "); + slave_load_file_stem(fname, file_id, server_id, ".data"); thd->proc_info= proc_info; if (get_create_or_append()) { @@ -4464,10 +4477,9 @@ void Delete_file_log_event::pack_info(Protocol *protocol) int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) { char fname[FN_REFLEN+10]; - char *p= slave_load_file_stem(fname, file_id, server_id); - memcpy(p, ".data", 6); + char *ext= slave_load_file_stem(fname, file_id, server_id, ".data"); (void) my_delete(fname, MYF(MY_WME)); - memcpy(p, ".info", 6); + strmov(ext, ".info"); (void) my_delete(fname, MYF(MY_WME)); return Log_event::exec_event(rli); } @@ -4560,19 +4572,21 @@ void Execute_load_log_event::pack_info(Protocol *protocol) int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) { char fname[FN_REFLEN+10]; - char *p= slave_load_file_stem(fname, file_id, server_id); + char *ext; int fd; - int error = 1; + int error= 1; IO_CACHE file; - Load_log_event* lev = 0; + Load_log_event *lev= 0; - memcpy(p, ".info", 6); + ext= slave_load_file_stem(fname, file_id, server_id, ".info"); if ((fd = my_open(fname, O_RDONLY | O_BINARY | O_NOFOLLOW, MYF(MY_WME))) < 0 || init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_error(rli,my_errno, "Error in Exec_load event: could not open file '%s'", fname); + slave_print_error(rli,my_errno, + "Error in Exec_load event: could not open file '%s'", + fname); goto err; } if (!(lev = (Load_log_event*)Log_event::read_log_event(&file, @@ -4580,7 +4594,9 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) rli->relay_log.description_event_for_exec)) || lev->get_type_code() != NEW_LOAD_EVENT) { - slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname); + slave_print_error(rli,0, + "Error in Exec_load event: file '%s' appears corrupted", + fname); goto err; } @@ -4625,7 +4641,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) fd= -1; } (void) my_delete(fname, MYF(MY_WME)); - memcpy(p, ".data", 6); + memcpy(ext, ".data", 6); (void) my_delete(fname, MYF(MY_WME)); error = 0; @@ -4823,11 +4839,10 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli) memcpy(p, query, fn_pos_start); p+= fn_pos_start; fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'"))); - p= slave_load_file_stem(p, file_id, server_id); - fname_end= (p= strmake(p, STRING_WITH_LEN(".data"))); + p= slave_load_file_stem(p, file_id, server_id, ".data"); + fname_end= p= strend(p); // Safer than p=p+5 *(p++)='\''; - switch (dup_handling) - { + switch (dup_handling) { case LOAD_DUP_IGNORE: p= strmake(p, STRING_WITH_LEN(" IGNORE")); break; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 323e829f219..12b00a62012 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5737,6 +5737,7 @@ bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List *fields) /* Create quick select from ref/ref_or_null scan. + SYNOPSIS get_quick_select_for_ref() thd Thread handle @@ -5756,15 +5757,18 @@ bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List *fields) QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref, ha_rows records) { - MEM_ROOT *old_root= thd->mem_root; - /* The following call may change thd->mem_root */ - QUICK_RANGE_SELECT *quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0); - /* save mem_root set by QUICK_RANGE_SELECT constructor */ - MEM_ROOT *alloc= thd->mem_root; + MEM_ROOT *old_root, *alloc; + QUICK_RANGE_SELECT *quick; KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; QUICK_RANGE *range; uint part; + + old_root= thd->mem_root; + /* The following call may change thd->mem_root */ + quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0); + /* save mem_root set by QUICK_RANGE_SELECT constructor */ + alloc= thd->mem_root; /* return back default mem_root (thd->mem_root) changed by QUICK_RANGE_SELECT constructor diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 69757e0be06..041b770ac0b 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -944,6 +944,6 @@ File_parser_dummy_hook::process_unknown_string(char *&unknown_key, char *end) { DBUG_ENTER("file_parser_dummy_hook::process_unknown_string"); - DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + DBUG_PRINT("info", ("Unknown key: '%60s'", unknown_key)); DBUG_RETURN(FALSE); } diff --git a/sql/sp.cc b/sql/sp.cc index 8991cc78b5e..983addb2db7 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -399,14 +399,14 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, const char *body, st_sp_chistics &chistics, const char *definer, longlong created, longlong modified) { - LEX *oldlex= thd->lex, newlex; - sp_rcontext *save_spcont= thd->spcont; + LEX *old_lex= thd->lex, newlex; String defstr; char olddb[128]; bool dbchanged; ulong old_sql_mode= thd->variables.sql_mode; - ha_rows select_limit= thd->variables.select_limit; - int ret= SP_INTERNAL_ERROR; + ha_rows old_select_limit= thd->variables.select_limit; + sp_rcontext *old_spcont= thd->spcont; + int ret; thd->variables.sql_mode= sql_mode; thd->variables.select_limit= HA_POS_ERROR; @@ -422,7 +422,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, returns, strlen(returns), body, strlen(body), &chistics)) + { + ret= SP_INTERNAL_ERROR; goto end; + } dbchanged= FALSE; if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb), @@ -451,10 +454,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, (*sphp)->optimize(); } end: - thd->spcont= save_spcont; + thd->spcont= old_spcont; thd->variables.sql_mode= old_sql_mode; - thd->variables.select_limit= select_limit; - thd->lex= oldlex; + thd->variables.select_limit= old_select_limit; + thd->lex= old_lex; return ret; } @@ -926,7 +929,6 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, ulong depth= (type == TYPE_ENUM_PROCEDURE ? thd->variables.max_sp_recursion_depth : 0); - DBUG_ENTER("sp_find_routine"); DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d", name->m_db.length, name->m_db.str, @@ -936,6 +938,11 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, if ((sp= sp_cache_lookup(cp, name))) { ulong level; + sp_head *new_sp; + const char *returns= ""; + char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + String retstr(64); + DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); if (sp->m_first_free_instance) { @@ -946,7 +953,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED)); if (sp->m_first_free_instance->m_recursion_level > depth) { - sp->recursion_level_error(); + sp->recursion_level_error(thd); DBUG_RETURN(0); } DBUG_RETURN(sp->m_first_free_instance); @@ -954,37 +961,32 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, level= sp->m_last_cached_sp->m_recursion_level + 1; if (level > depth) { - sp->recursion_level_error(); + sp->recursion_level_error(thd); DBUG_RETURN(0); } + + strxmov(definer, sp->m_definer_user.str, "@", + sp->m_definer_host.str, NullS); + if (type == TYPE_ENUM_FUNCTION) { - sp_head *new_sp; - const char *returns= ""; - char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; - String retstr(64); - strxmov(definer, sp->m_definer_user.str, "@", - sp->m_definer_host.str, NullS); - if (type == TYPE_ENUM_FUNCTION) - { - sp_returns_type(thd, retstr, sp); - returns= retstr.ptr(); - } - if (db_load_routine(thd, type, name, &new_sp, - sp->m_sql_mode, sp->m_params.str, returns, - sp->m_body.str, *sp->m_chistics, definer, - sp->m_created, sp->m_modified) == SP_OK) - { - sp->m_last_cached_sp->m_next_cached_sp= new_sp; - new_sp->m_recursion_level= level; - new_sp->m_first_instance= sp; - sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; - DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", + sp_returns_type(thd, retstr, sp); + returns= retstr.ptr(); + } + if (db_load_routine(thd, type, name, &new_sp, + sp->m_sql_mode, sp->m_params.str, returns, + sp->m_body.str, *sp->m_chistics, definer, + sp->m_created, sp->m_modified) == SP_OK) + { + sp->m_last_cached_sp->m_next_cached_sp= new_sp; + new_sp->m_recursion_level= level; + new_sp->m_first_instance= sp; + sp->m_last_cached_sp= sp->m_first_free_instance= new_sp; + DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x", (ulong)new_sp, new_sp->m_recursion_level, new_sp->m_flags)); - DBUG_RETURN(new_sp); - } - DBUG_RETURN(0); + DBUG_RETURN(new_sp); } + DBUG_RETURN(0); } if (!cache_only) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a6e88c08789..576830a6587 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -24,11 +24,17 @@ #include "sp_rcontext.h" #include "sp_cache.h" +/* + Sufficient max length of printed destinations and frame offsets (all uints). +*/ +#define SP_INSTR_UINT_MAXLEN 8 +#define SP_STMT_PRINT_MAXLEN 40 + + Item_result sp_map_result_type(enum enum_field_types type) { - switch (type) - { + switch (type) { case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: @@ -891,17 +897,17 @@ static bool subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) SYNOPSIS sp_head::recursion_level_error() + thd Thread handle NOTE For functions and triggers we return error about prohibited recursion. For stored procedures we return about reaching recursion limit. */ -void sp_head::recursion_level_error() +void sp_head::recursion_level_error(THD *thd) { if (m_type == TYPE_ENUM_PROCEDURE) { - THD *thd= current_thd; my_error(ER_SP_RECURSION_LIMIT, MYF(0), thd->variables.max_sp_recursion_depth, m_name); @@ -952,10 +958,15 @@ int sp_head::execute(THD *thd) DBUG_ASSERT(!(m_flags & IS_INVOKED)); m_flags|= IS_INVOKED; m_first_instance->m_first_free_instance= m_next_cached_sp; - DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x", - (ulong)m_first_instance, this, m_next_cached_sp, - m_next_cached_sp->m_recursion_level, - m_next_cached_sp->m_flags)); + if (m_next_cached_sp) + { + DBUG_PRINT("info", + ("first free for 0x%lx ++: 0x%lx->0x%lx level: %lu flags %x", + (ulong)m_first_instance, (ulong) this, + (ulong) m_next_cached_sp, + m_next_cached_sp->m_recursion_level, + m_next_cached_sp->m_flags)); + } /* Check that if there are not any instances after this one then pointer to the last instance points on this instance or if there are @@ -1140,9 +1151,9 @@ int sp_head::execute(THD *thd) } m_flags&= ~IS_INVOKED; DBUG_PRINT("info", ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x", - (ulong)m_first_instance, - m_first_instance->m_first_free_instance, this, - m_recursion_level, m_flags)); + (ulong) m_first_instance, + (ulong) m_first_instance->m_first_free_instance, + (ulong) this, m_recursion_level, m_flags)); /* Check that we have one of following: @@ -1152,7 +1163,7 @@ int sp_head::execute(THD *thd) 2) There are some free instances which mean that first free instance should go just after this one and recursion level of that free instance - should be on 1 more then recursion leven of this instance. + should be on 1 more then recursion level of this instance. */ DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 && this == m_first_instance->m_last_cached_sp && @@ -1684,16 +1695,16 @@ sp_head::set_info(longlong created, longlong modified, void -sp_head::set_definer(char *definer, uint definerlen) + +sp_head::set_definer(const char *definer, uint definerlen) { char *p= strrchr(definer, '@'); if (!p) { - m_definer_user.str= strmake_root(mem_root, "", 0); + m_definer_user.str= (char*) ""; m_definer_user.length= 0; - - m_definer_host.str= strmake_root(mem_root, "", 0); + m_definer_host.str= (char*) ""; m_definer_host.length= 0; } else @@ -1788,9 +1799,9 @@ sp_head::show_create_procedure(THD *thd) byte *sql_mode_str; ulong sql_mode_len; bool full_access; - DBUG_ENTER("sp_head::show_create_procedure"); DBUG_PRINT("info", ("procedure %s", m_name.str)); + LINT_INIT(sql_mode_str); LINT_INIT(sql_mode_len); @@ -2143,12 +2154,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } -/* - Sufficient max length of printed destinations and frame offsets (all uints). -*/ -#define SP_INSTR_UINT_MAXLEN 8 -#define SP_STMT_PRINT_MAXLEN 40 void sp_instr_stmt::print(String *str) { @@ -2170,16 +2176,16 @@ sp_instr_stmt::print(String *str) /* Copy the query string and replace '\n' with ' ' in the process */ for (i= 0 ; i < len ; i++) { - if (m_query.str[i] == '\n') - str->qs_append(' '); - else - str->qs_append(m_query.str[i]); + char c= m_query.str[i]; + if (c == '\n') + c= ' '; + str->qs_append(c); } if (m_query.length > SP_STMT_PRINT_MAXLEN) str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */ str->qs_append('"'); } -#undef SP_STMT_PRINT_MAXLEN + int sp_instr_stmt::exec_core(THD *thd, uint *nextp) @@ -2523,6 +2529,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_hpush_jump::print(String *str) { @@ -2533,8 +2540,7 @@ sp_instr_hpush_jump::print(String *str) str->qs_append(m_dest); str->qs_append(' '); str->qs_append(m_frame); - switch (m_type) - { + switch (m_type) { case SP_HANDLER_NONE: str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug break; @@ -2548,11 +2554,13 @@ sp_instr_hpush_jump::print(String *str) str->qs_append(STRING_WITH_LEN(" UNDO")); break; default: - str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); // This would be a bug as well + // This would be a bug as well + str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); str->qs_append(m_type); } } + uint sp_instr_hpush_jump::opt_mark(sp_head *sp) { diff --git a/sql/sp_head.h b/sql/sp_head.h index 6334bca0fc6..6f4a2de1518 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -283,7 +283,7 @@ public: void set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode); - void set_definer(char *definer, uint definerlen); + void set_definer(const char *definer, uint definerlen); void reset_thd_mem_root(THD *thd); @@ -292,7 +292,7 @@ public: void optimize(); void opt_mark(uint ip); - void recursion_level_error(); + void recursion_level_error(THD *thd); inline sp_instr * get_instr(uint i) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 46be74ae972..8d3bb316630 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3537,7 +3537,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, of other queries). For simple queries first_not_own_table is 0. */ for (i= 0, table= tables; - table && table != first_not_own_table && i < number; + table != first_not_own_table && i < number; table= table->next_global, i++) { /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 39e15675e47..598e6d46a60 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5135,7 +5135,6 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, bool result=0, signalled= 0; DBUG_ENTER("remove_table_from_cache"); - key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; for (;;) { diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index da72d283259..545cf41eeeb 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -227,6 +227,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* add to hash */ if (my_hash_insert(&thd->handler_tables_hash, (byte*) hash_tables)) { + my_free((char*) hash_tables, MYF(0)); mysql_ha_close(thd, tables); goto err; } @@ -369,28 +370,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->table_name, hash_tables->alias, table)); - /* Table might have been flushed. */ - if (table && (table->s->version != refresh_version)) - { - /* - We must follow the thd->handler_tables chain, as we need the - address of the 'next' pointer referencing this table - for close_thread_table(). - */ - for (table_ptr= &(thd->handler_tables); - *table_ptr && (*table_ptr != table); - table_ptr= &(*table_ptr)->next) - {} - (*table_ptr)->file->ha_index_or_rnd_end(); - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) - { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); - } - VOID(pthread_mutex_unlock(&LOCK_open)); - table= hash_tables->table= NULL; - } if (!table) { /* @@ -448,12 +427,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - if (insert_fields(thd, &thd->lex->select_lex.context, - tables->db, tables->alias, &it, 0)) - goto err0; - - protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); - HANDLER_TABLES_HACK(thd); lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); HANDLER_TABLES_HACK(thd); @@ -461,6 +434,12 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already + if (insert_fields(thd, &thd->lex->select_lex.context, + tables->db, tables->alias, &it, 0)) + goto err0; + + protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); + /* In ::external_lock InnoDB resets the fields which tell it that the handle is used in the HANDLER interface. Tell it again that diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 5e9ca203632..a291a824e61 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2492,7 +2492,11 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) } /* First field to copy */ - field=table->field+table->s->fields - values.elements; + field= table->field+table->s->fields - values.elements; + + /* Mark all fields that are given values */ + for (Field **f= field ; *f ; f++) + (*f)->query_id= thd->query_id; /* Don't set timestamp if used */ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1a9b4ef4db7..065406d1f0c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4843,7 +4843,6 @@ end_with_restore_list: if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) reset_one_shot_variables(thd); - /* The return value for ROW_COUNT() is "implementation dependent" if the statement is not DELETE, INSERT or UPDATE (or a CALL executing @@ -4851,13 +4850,10 @@ end_with_restore_list: */ if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2) thd->row_count_func= -1; - goto cleanup; + DBUG_RETURN(res || thd->net.report_error); error: - res= 1; - -cleanup: - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(1); } @@ -5080,7 +5076,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, the given table list refers to the list for prelocking (contains tables of other queries). For simple queries first_not_own_table is 0. */ - for (; tables && tables != first_not_own_table; tables= tables->next_global) + for (; tables != first_not_own_table; tables= tables->next_global) { if (tables->schema_table && (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) @@ -7558,7 +7554,7 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) /* Create and initialize. */ - if (! (definer= (LEX_USER*) thd->alloc(sizeof (LEX_USER)))) + if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) return 0; definer->user= *user_name; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 470015f8869..52070aa8983 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10628,7 +10628,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), item->save_org_in_field(group->field); /* Store in the used key if the field was 0 */ if (item->maybe_null) - group->buff[-1]=item->null_value ? 1 : 0; + group->buff[-1]= (char) group->field->is_null(); } if (!table->file->index_read(table->record[1], join->tmp_table_param.group_buff,0, diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 296b55679a3..d3fda132f50 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -51,6 +51,13 @@ static File_option triggers_file_parameters[]= { { 0, 0 }, 0, FILE_OPTIONS_STRING } }; +File_option sql_modes_parameters= +{ + {STRING_WITH_LEN("sql_modes") }, + offsetof(class Table_triggers_list, definition_modes_list), + FILE_OPTIONS_ULLLIST +}; + /* This must be kept up to date whenever a new option is added to the list above, as it specifies the number of required parameters of the trigger in @@ -428,7 +435,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!is_acl_user(lex->definer->host.str, - lex->definer->user.str)) + lex->definer->user.str)) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, @@ -771,7 +778,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, sizeof(LEX_STRING)))) DBUG_RETURN(1); // EOM - trg_definer->str= ""; + trg_definer->str= (char*) ""; trg_definer->length= 0; while (it++) @@ -1164,7 +1171,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, if (is_special_var_used(event, time_type)) { - TABLE_LIST table_list; + TABLE_LIST table_list, **save_query_tables_own_last; bzero((char *) &table_list, sizeof (table_list)); table_list.db= (char *) table->s->db; table_list.db_length= strlen(table_list.db); @@ -1172,8 +1179,12 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, table_list.table_name_length= strlen(table_list.table_name); table_list.alias= (char *) table->alias; table_list.table= table; + save_query_tables_own_last= thd->lex->query_tables_own_last; + thd->lex->query_tables_own_last= 0; - if (check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0)) + res= check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0); + thd->lex->query_tables_own_last= save_query_tables_own_last; + if (res) { sp_restore_security_context(thd, save_ctx); return TRUE; @@ -1215,32 +1226,29 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, TRUE Error */ +#define INVALID_SQL_MODES_LENGTH 13 + bool Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key, gptr base, MEM_ROOT *mem_root, char *end) { -#define INVALID_SQL_MODES_LENGTH 13 DBUG_ENTER("handle_old_incorrect_sql_modes"); DBUG_PRINT("info", ("unknown key:%60s", unknown_key)); + if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end && unknown_key[INVALID_SQL_MODES_LENGTH] == '=' && !memcmp(unknown_key, STRING_WITH_LEN("sql_modes"))) { + char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1; + DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected")); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_OLD_FILE_FORMAT, ER(ER_OLD_FILE_FORMAT), (char *)path, "TRIGGER"); - File_option sql_modes_parameters= - { - {STRING_WITH_LEN("sql_modes") }, - offsetof(class Table_triggers_list, definition_modes_list), - FILE_OPTIONS_ULLLIST - }; - char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1; if (get_file_options_ulllist(ptr, end, unknown_key, base, &sql_modes_parameters, mem_root)) { From 64cab9d76717e5fdd819b08858ca6db087e1c7fd Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Fri, 6 Jan 2006 12:48:14 +0200 Subject: [PATCH 091/154] After merge fix and a safety fix for handler --- sql/sql_handler.cc | 14 +++++++------- sql/sql_trigger.cc | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 545cf41eeeb..fae48c7d164 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -414,6 +414,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; + HANDLER_TABLES_HACK(thd); + lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); + HANDLER_TABLES_HACK(thd); + + if (!lock) + goto err0; // mysql_lock_tables() printed error message already + if (cond && ((!cond->fixed && cond->fix_fields(thd, &cond)) || cond->check_cols(1))) goto err0; @@ -427,13 +434,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); - HANDLER_TABLES_HACK(thd); - - if (!lock) - goto err0; // mysql_lock_tables() printed error message already - if (insert_fields(thd, &thd->lex->select_lex.context, tables->db, tables->alias, &it, 0)) goto err0; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 5f2d269ed1e..bbc32950c2d 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1189,9 +1189,10 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, save_query_tables_own_last= thd->lex->query_tables_own_last; thd->lex->query_tables_own_last= 0; - res= check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0); + err_status= check_table_access(thd, SELECT_ACL | UPDATE_ACL, + &table_list, 0); thd->lex->query_tables_own_last= save_query_tables_own_last; - if (res) + if (err_status) { sp_restore_security_context(thd, save_ctx); return TRUE; From be8f21e8f10b9dec5cc3918894cb4745f554e3ba Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Fri, 6 Jan 2006 14:30:25 +0100 Subject: [PATCH 092/154] Fix compile failure on QNX. --- sql/sp_head.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d6db9a47748..12f9260e7b1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1755,7 +1755,7 @@ void sp_head::set_definer(const char *definer, uint definerlen) { - char *p= strrchr(definer, '@'); + const char *p= strrchr(definer, '@'); if (!p) { From 7d20407c9cf6436c607f0c56ffdac6c500759066 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 6 Jan 2006 17:32:25 +0100 Subject: [PATCH 093/154] BSD make compatibility --- Docs/Makefile.am | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 542c82d8f58..f512aa9e29e 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -45,22 +45,22 @@ CLEAN_FILES: $(TXT_FILES) GT = $(srcdir)/Support/generate-text-files.pl ../INSTALL-SOURCE: mysql.info $(GT) - perl -w $(GT) $< "installing-source" "windows-source-build" > $@ + perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@ ../INSTALL-WIN-SOURCE: mysql.info $(GT) - perl -w $(GT) $< "windows-source-build" "post-installation" > $@ + perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@ # We put the description for the binary installation here so that # people who download source wont have to see it. It is moved up to # the toplevel by the script that makes the binary tar files. INSTALL-BINARY: mysql.info $(GT) - perl -w $(GT) $< "installing-binary" "installing-source" > $@ + perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@ ../EXCEPTIONS-CLIENT: mysql.info $(GT) - perl -w $(GT) $< "mysql-floss-license-exception" "function-index" > $@ + perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@ ../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) $< "mac-os-x-installation" "netware-installation" > $@ + perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@ # Don't update the files from bitkeeper %::SCCS/s.% From fd4a04032594cab1dbfd9a0e4e8358898b0d0da2 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Fri, 6 Jan 2006 21:42:17 +0200 Subject: [PATCH 094/154] Fixes during review of new pushed code: Remove wrong fix for Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Safety fix for bug #13855 "select distinct with group by caused server crash" --- client/mysqlimport.c | 1 - myisam/myisam_ftdump.c | 2 +- sql/item_cmpfunc.cc | 2 +- sql/sql_handler.cc | 46 +++++++++++------------------------------- sql/sql_select.cc | 9 ++++++++- 5 files changed, 22 insertions(+), 38 deletions(-) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 0932cf7432a..2dcb1d4eb6d 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -252,7 +252,6 @@ static int write_to_table(char *filename, MYSQL *sock) { char tablename[FN_REFLEN], hard_path[FN_REFLEN], sql_statement[FN_REFLEN*16+256], *end; - my_bool local_file; DBUG_ENTER("write_to_table"); DBUG_PRINT("enter",("filename: %s",filename)); diff --git a/myisam/myisam_ftdump.c b/myisam/myisam_ftdump.c index 838f90feae5..005d15376fb 100644 --- a/myisam/myisam_ftdump.c +++ b/myisam/myisam_ftdump.c @@ -66,7 +66,7 @@ int main(int argc,char *argv[]) struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ MY_INIT(argv[0]); - if (error=handle_options(&argc, &argv, my_long_options, get_one_option)) + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(error); if (count || dump) verbose=0; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 107a17815ae..db6c4d9789b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -659,7 +659,7 @@ bool Item_func_nullif::is_null() { if (!(this->*cmp_func)()) - return null_value=1; + return (null_value= 1); return 0; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 28e94d1a477..58b75e667b5 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -380,27 +380,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->real_name, hash_tables->alias, table)); - /* Table might have been flushed. */ - if (table && (table->version != refresh_version)) - { - /* - We must follow the thd->handler_tables chain, as we need the - address of the 'next' pointer referencing this table - for close_thread_table(). - */ - for (table_ptr= &(thd->handler_tables); - *table_ptr && (*table_ptr != table); - table_ptr= &(*table_ptr)->next) - {} - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) - { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); - } - VOID(pthread_mutex_unlock(&LOCK_open)); - table= hash_tables->table= NULL; - } if (!table) { /* @@ -447,11 +426,16 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; + HANDLER_TABLES_HACK(thd); + lock= mysql_lock_tables(thd, &tables->table, 1, 0); + HANDLER_TABLES_HACK(thd); + + if (!lock) + goto err0; // mysql_lock_tables() printed error message already + if (cond && cond->fix_fields(thd,tables)) goto err0; - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - if (keyname) { if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) @@ -462,6 +446,11 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } table->file->index_init(keyno); } + + byte *key; + uint key_len; + LINT_INIT(key); + LINT_INIT(key_len); if (insert_fields(thd,tables,tables->db,tables->alias,&it)) goto err0; @@ -469,17 +458,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, select_limit+=offset_limit; send_fields(thd,list,1); - HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0); - HANDLER_TABLES_HACK(thd); - - byte *key; - uint key_len; - LINT_INIT(key); - LINT_INIT(key_len); - if (!lock) - goto err0; // mysql_lock_tables() printed error message already - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it for (num_rows=0; num_rows < select_limit; ) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6dd68a60f88..32658f92416 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4082,7 +4082,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, *(reg_field++) =new_field; } if (!--hidden_field_count) + { hidden_null_count=null_count; + /* + We need to update hidden_field_count as we may have stored group + functions with constant arguments + */ + param->hidden_field_count= (uint) (reg_field - table->field); + } } DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= (uint) (reg_field - table->field); @@ -4270,7 +4277,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, } } - if (distinct) + if (distinct && field_count != param->hidden_field_count) { /* Create an unique key or an unique constraint over all columns From d2cfad167b15ba3276c7855bfcc4950a706b0f3d Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Fri, 6 Jan 2006 22:28:26 -0800 Subject: [PATCH 095/154] Fixed bug #16016: MIN/MAX optimization was not applied to views. --- mysql-test/r/view.result | 29 +++++++++++++++++++++++++++++ mysql-test/t/view.test | 24 ++++++++++++++++++++++++ sql/opt_sum.cc | 10 +++++----- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b9380dcf033..8b6d0787ada 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2475,3 +2475,32 @@ alias1 alias2 5 5 drop view v2, v1; drop table t1; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (2,20), (3,10), (1,10), (0,30), (5,10); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT MAX(a) FROM t1; +MAX(a) +5 +SELECT MAX(a) FROM v1; +MAX(a) +5 +EXPLAIN SELECT MAX(a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +EXPLAIN SELECT MAX(a) FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +SELECT MIN(a) FROM t1; +MIN(a) +0 +SELECT MIN(a) FROM v1; +MIN(a) +0 +EXPLAIN SELECT MIN(a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +EXPLAIN SELECT MIN(a) FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index db6c12fdacb..5f3678215f2 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2339,3 +2339,27 @@ order by v2.receipt_id; drop view v2, v1; drop table t1; + +# +# Bug#16016: MIN/MAX optimization for views +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (2,20), (3,10), (1,10), (0,30), (5,10); + +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT MAX(a) FROM t1; +SELECT MAX(a) FROM v1; + +EXPLAIN SELECT MAX(a) FROM t1; +EXPLAIN SELECT MAX(a) FROM v1; + +SELECT MIN(a) FROM t1; +SELECT MIN(a) FROM v1; + +EXPLAIN SELECT MIN(a) FROM t1; +EXPLAIN SELECT MIN(a) FROM v1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 37acce2934b..ed8e694dcb7 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -180,14 +180,14 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) indexes to find the key. */ Item *expr=item_sum->args[0]; - if (expr->type() == Item::FIELD_ITEM) + if (expr->real_item()->type() == Item::FIELD_ITEM) { byte key_buff[MAX_KEY_LENGTH]; TABLE_REF ref; uint range_fl, prefix_len; ref.key_buff= key_buff; - Item_field *item_field= ((Item_field*) expr); + Item_field *item_field= (Item_field*) (expr->real_item()); TABLE *table= item_field->field->table; /* @@ -267,14 +267,14 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) indexes to find the key. */ Item *expr=item_sum->args[0]; - if (expr->type() == Item::FIELD_ITEM) + if (expr->real_item()->type() == Item::FIELD_ITEM) { byte key_buff[MAX_KEY_LENGTH]; TABLE_REF ref; - uint range_fl, prefix_len; + uint range_fl, prefix_len; ref.key_buff= key_buff; - Item_field *item_field= ((Item_field*) expr); + Item_field *item_field= (Item_field*) (expr->real_item()); TABLE *table= item_field->field->table; /* From 8139f3641708dcb0900f51b653cf095c21a1fae2 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Sun, 8 Jan 2006 07:42:40 +0100 Subject: [PATCH 096/154] BUG#16282: Remove unused gcc.cpp linker input that causes failure in make -j. --- ndb/config/common.mk.am | 2 +- ndb/src/common/portlib/Makefile.am | 2 -- ndb/src/common/portlib/gcc.cpp | 7 ------- 3 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 ndb/src/common/portlib/gcc.cpp diff --git a/ndb/config/common.mk.am b/ndb/config/common.mk.am index 869e2fae91d..6fda12d33b0 100644 --- a/ndb/config/common.mk.am +++ b/ndb/config/common.mk.am @@ -7,6 +7,6 @@ ndbapiincludedir = "$(pkgincludedir)/ndb/ndbapi" mgmapiincludedir = "$(pkgincludedir)/ndb/mgmapi" INCLUDES = $(INCLUDES_LOC) -LDADD = $(top_srcdir)/ndb/src/common/portlib/gcc.cpp $(LDADD_LOC) +LDADD = $(LDADD_LOC) DEFS = @DEFS@ @NDB_DEFS@ $(DEFS_LOC) $(NDB_EXTRA_FLAGS) NDB_CXXFLAGS=@ndb_cxxflags_fix@ $(NDB_CXXFLAGS_LOC) diff --git a/ndb/src/common/portlib/Makefile.am b/ndb/src/common/portlib/Makefile.am index 99138a7414e..1e27d713495 100644 --- a/ndb/src/common/portlib/Makefile.am +++ b/ndb/src/common/portlib/Makefile.am @@ -1,5 +1,3 @@ -noinst_HEADERS = gcc.cpp - noinst_LTLIBRARIES = libportlib.la libportlib_la_SOURCES = \ diff --git a/ndb/src/common/portlib/gcc.cpp b/ndb/src/common/portlib/gcc.cpp deleted file mode 100644 index 4e49d787d3c..00000000000 --- a/ndb/src/common/portlib/gcc.cpp +++ /dev/null @@ -1,7 +0,0 @@ - -/** - * GCC linking problem... - */ -#if 0 -extern "C" { int __cxa_pure_virtual() { return 0;} } -#endif From 05947d9916a9b85a32d8cda770de12ceb544e90f Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sat, 7 Jan 2006 23:00:06 -0800 Subject: [PATCH 097/154] Fixed bug #14274: a query with a having clause containing only set function returned a wrong result set. --- mysql-test/r/having.result | 13 +++++++++++++ mysql-test/t/having.test | 12 ++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index 218276406b1..9730f9f81bf 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -128,3 +128,16 @@ id description c 1 test 0 2 test2 0 drop table t1,t2,t3; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (4), (1), (3), (1); +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a)>0; +SUM(a) +2 +6 +4 +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a); +SUM(a) +2 +6 +4 +DROP TABLE t1; diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 920a3b752ab..3dd9ace6a1b 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -123,4 +123,16 @@ group by a.id, a.description having (a.description is not null) and (c=0); drop table t1,t2,t3; +# +# Bug #14274: HAVING clause containing only set function +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (4), (1), (3), (1); + +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a)>0; +SELECT SUM(a) FROM t1 GROUP BY a HAVING SUM(a); + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5e29c98e2c8..09900c89307 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -287,7 +287,7 @@ JOIN::prepare(Item ***rref_pointer_array, if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) - having->split_sum_func(thd, ref_pointer_array, all_fields); + having->split_sum_func2(thd, ref_pointer_array, all_fields, &having); } // Is it subselect From 44ea4f5441dba0960c47d7733796bd8cf96848dd Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Mon, 9 Jan 2006 01:09:42 +0100 Subject: [PATCH 098/154] ndb - wl#2972 ndb api test_event_merge 5.0+5.1 --- ndb/test/ndbapi/test_event_merge.cpp | 1245 ++++++++++++++++++-------- 1 file changed, 877 insertions(+), 368 deletions(-) diff --git a/ndb/test/ndbapi/test_event_merge.cpp b/ndb/test/ndbapi/test_event_merge.cpp index 1332455cdc5..f57667caf62 100644 --- a/ndb/test/ndbapi/test_event_merge.cpp +++ b/ndb/test/ndbapi/test_event_merge.cpp @@ -27,6 +27,9 @@ #undef version50 #endif +// until rbr in 5.1 +#undef version51rbr + #if !defined(min) || !defined(max) #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -42,13 +45,20 @@ * 2) In event API version >= 5.1 separate commits within same GCI are * by default merged. This is required to read blob data via NdbBlob. * - * This test program ignores Blob columns in version 5.0. + * Option --separate-events disables GCI merge and implies --no-blobs. + * This is used to test basic events functionality. + * + * Option --no-blobs omits blob attributes. This is used to test GCI + * merge without getting into blob bugs. + * + * Option --no-multiops allows 1 operation per commit. This avoids TUP + * and blob multi-operation bugs. * * There are 5 ways (ignoring NUL operand) to compose 2 ops: * 5.0 bugs 5.1 bugs * INS o DEL = NUL - * INS o UPD = INS 5.1 - * DEL o INS = UPD type=INS 5.1 + * INS o UPD = INS type=INS + * DEL o INS = UPD type=INS type=INS * UPD o DEL = DEL no event * UPD o UPD = UPD */ @@ -59,41 +69,69 @@ struct Opts { uint loop; uint maxops; uint maxpk; - const char* opstr; + my_bool no_blobs; + my_bool no_multiops; + my_bool one_blob; + const char* opstring; uint seed; my_bool separate_events; my_bool use_table; }; static Opts g_opts; -static const uint g_maxops = 10000; static const uint g_maxpk = 100; +static const uint g_maxopstringpart = 100; +static const char* g_opstringpart[g_maxopstringpart]; +static uint g_opstringparts = 0; +static uint g_loop = 0; static Ndb_cluster_connection* g_ncc = 0; static Ndb* g_ndb = 0; static NdbDictionary::Dictionary* g_dic = 0; static NdbTransaction* g_con = 0; static NdbOperation* g_op = 0; +static NdbScanOperation* g_scan_op = 0; static const char* g_tabname = "tem1"; static const char* g_evtname = "tem1ev1"; static const uint g_charlen = 5; +static const char* g_charval = "abcdefgh"; static const char* g_csname = "latin1_swedish_ci"; +static uint g_blobinlinesize = 256; +static uint g_blobpartsize = 2000; +static uint g_blobstripesize = 2; +static const uint g_maxblobsize = 100000; + static const NdbDictionary::Table* g_tab = 0; static const NdbDictionary::Event* g_evt = 0; static NdbEventOperation* g_evt_op = 0; +static NdbBlob* g_bh = 0; static uint -urandom(uint n) +urandom() { uint r = (uint)random(); - if (n != 0) - r = r % n; return r; } +static uint +urandom(uint m) +{ + if (m == 0) + return 0; + uint r = urandom(); + r = r % m; + return r; +} + +static bool +urandom(uint per, uint cent) +{ + return urandom(cent) < per; +} + static int& g_loglevel = g_opts.loglevel; // default log level #define chkdb(x) \ @@ -138,11 +176,21 @@ errdb() if (e.code != 0) ll0(++any << " op: error " << e); } + if (g_scan_op != 0) { + const NdbError& e = g_scan_op->getNdbError(); + if (e.code != 0) + ll0(++any << " scan_op: error " << e); + } if (g_evt_op != 0) { const NdbError& e = g_evt_op->getNdbError(); if (e.code != 0) ll0(++any << " evt_op: error " << e); } + if (g_bh != 0) { + const NdbError& e = g_bh->getNdbError(); + if (e.code != 0) + ll0(++any << " evt_op: error " << e); + } if (! any) ll0("unknown db error"); } @@ -155,31 +203,47 @@ struct Col { bool nullable; uint length; uint size; + bool isblob() const { + return type == NdbDictionary::Column::Text; + } }; static Col g_col[] = { { 0, "pk1", NdbDictionary::Column::Unsigned, true, false, 1, 4 }, { 1, "pk2", NdbDictionary::Column::Char, true, false, g_charlen, g_charlen }, { 2, "seq", NdbDictionary::Column::Unsigned, false, false, 1, 4 }, - { 3, "cc1", NdbDictionary::Column::Char, false, true, g_charlen, g_charlen } + { 3, "cc1", NdbDictionary::Column::Char, false, true, g_charlen, g_charlen }, + { 4, "tx1", NdbDictionary::Column::Text, false, true, 0, 0 }, + { 5, "tx2", NdbDictionary::Column::Text, false, true, 0, 0 } }; -static const uint g_ncol = sizeof(g_col)/sizeof(g_col[0]); +static const uint g_maxcol = sizeof(g_col)/sizeof(g_col[0]); + +static uint +ncol() +{ + uint n = g_maxcol; + if (g_opts.no_blobs) + n -= 2; + else if (g_opts.one_blob) + n -= 1; + return n; +} static const Col& getcol(uint i) { - if (i < g_ncol) + if (i < ncol()) return g_col[i]; assert(false); - return g_col[g_ncol]; + return g_col[0]; } static const Col& getcol(const char* name) { uint i; - for (i = 0; i < g_ncol; i++) + for (i = 0; i < ncol(); i++) if (strcmp(g_col[i].name, name) == 0) break; return getcol(i); @@ -194,7 +258,7 @@ createtable() CHARSET_INFO* cs; chkrc((cs = get_charset_by_name(g_csname, MYF(0))) != 0); uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = g_col[i]; NdbDictionary::Column col(c.name); col.setType(c.type); @@ -209,6 +273,12 @@ createtable() col.setLength(c.length); col.setCharset(cs); break; + case NdbDictionary::Column::Text: + col.setInlineSize(g_blobinlinesize); + col.setPartSize(g_blobpartsize); + col.setStripeSize(g_blobstripesize); + col.setCharset(cs); + break; default: assert(false); break; @@ -229,9 +299,9 @@ createtable() chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0); chkdb(g_op->insertTuple() == 0); Uint32 pk1; - char pk2[g_charlen]; + char pk2[g_charlen + 1]; pk1 = g_maxpk; - memset(pk2, 0x20, g_charlen); + sprintf(pk2, "%-*u", g_charlen, pk1); chkdb(g_op->equal("pk1", (char*)&pk1) == 0); chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0); chkdb(g_con->execute(Commit) == 0); @@ -255,34 +325,86 @@ droptable() } struct Data { + struct Txt { char* val; uint len; }; + union Ptr { Uint32* u32; char* ch; Txt* txt; void* v; }; Uint32 pk1; - char pk2[g_charlen]; + char pk2[g_charlen + 1]; Uint32 seq; - char cc1[g_charlen]; - void* ptr[g_ncol]; - int ind[g_ncol]; // -1 = no data, 1 = NULL, 0 = not NULL + char cc1[g_charlen + 1]; + Txt tx1; + Txt tx2; + Ptr ptr[g_maxcol]; + int ind[g_maxcol]; // -1 = no data, 1 = NULL, 0 = not NULL + uint noop; // bit: omit in NdbOperation (implicit NULL INS or no UPD) + uint ppeq; // bit: post/pre data value equal in GCI data[0]/data[1] void init() { uint i; pk1 = 0; memset(pk2, 0, sizeof(pk2)); seq = 0; memset(cc1, 0, sizeof(cc1)); - ptr[0] = &pk1; - ptr[1] = pk2; - ptr[2] = &seq; - ptr[3] = cc1; - for (i = 0; i < g_ncol; i++) + tx1.val = tx2.val = 0; + tx1.len = tx2.len = 0; + ptr[0].u32 = &pk1; + ptr[1].ch = pk2; + ptr[2].u32 = &seq; + ptr[3].ch = cc1; + ptr[4].txt = &tx1; + ptr[5].txt = &tx2; + for (i = 0; i < g_maxcol; i++) ind[i] = -1; + noop = 0; + ppeq = 0; + } + void free() { + delete [] tx1.val; + delete [] tx2.val; + init(); } }; +static int +cmpcol(const Col& c, const Data& d1, const Data& d2) +{ + uint i = c.no; + if (d1.ind[i] != d2.ind[i]) + return 1; + if (d1.ind[i] == 0) { + switch (c.type) { + case NdbDictionary::Column::Unsigned: + if (*d1.ptr[i].u32 != *d2.ptr[i].u32) + return 1; + break; + case NdbDictionary::Column::Char: + if (memcmp(d1.ptr[i].ch, d2.ptr[i].ch, c.size) != 0) + return 1; + break; + case NdbDictionary::Column::Text: + { + const Data::Txt& t1 = *d1.ptr[i].txt; + const Data::Txt& t2 = *d2.ptr[i].txt; + if (t1.len != t2.len) + return 1; + if (memcmp(t1.val, t2.val, t1.len) != 0) + return 1; + } + break; + default: + assert(false); + break; + } + } + return 0; +} + static NdbOut& operator<<(NdbOut& out, const Data& d) { uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = getcol(i); - out << (i == 0 ? "" : " ") << c.name << "="; + out << (i == 0 ? "" : " ") << c.name; + out << (! (d.noop & (1 << i)) ? "=" : ":"); if (d.ind[i] == -1) continue; if (d.ind[i] == 1) { @@ -291,12 +413,12 @@ operator<<(NdbOut& out, const Data& d) } switch (c.type) { case NdbDictionary::Column::Unsigned: - out << *(Uint32*)d.ptr[i]; + out << *d.ptr[i].u32; break; case NdbDictionary::Column::Char: { char buf[g_charlen + 1]; - memcpy(buf, d.ptr[i], g_charlen); + memcpy(buf, d.ptr[i].ch, g_charlen); uint n = g_charlen; while (1) { buf[n] = 0; @@ -304,11 +426,30 @@ operator<<(NdbOut& out, const Data& d) break; n--; } - out << buf; + out << "'" << buf << "'"; + } + break; + case NdbDictionary::Column::Text: + { + Data::Txt& t = *d.ptr[i].txt; + bool first = true; + uint j = 0; + while (j < t.len) { + char c[2]; + c[0] = t.val[j++]; + c[1] = 0; + uint m = 1; + while (j < t.len && t.val[j] == c[0]) + j++, m++; + if (! first) + out << "+"; + first = false; + out << m << c; + } } break; default: - out << "?"; + assert(false); break; } } @@ -329,18 +470,26 @@ struct Op { // single or composite Type type; Op* next_op; // within one commit Op* next_com; // next commit chain or next event + Op* next_gci; // groups commit chains (unless --separate-events) + Op* next_ev; + Op* next_free; // free list + bool free; // on free list uint num_op; uint num_com; Data data[2]; // 0-post 1-pre bool match; // matched to event - void init() { + Uint32 gci; // defined for com op and event + void init(Kind a_kind) { + kind = a_kind; assert(kind == OP || kind == EV); type = NUL; - next_op = next_com = 0; + next_op = next_com = next_gci = next_ev = next_free = 0; + free = false; num_op = num_com = 0; data[0].init(); data[1].init(); match = false; + gci = 0; } }; @@ -370,9 +519,11 @@ operator<<(NdbOut& out, Op::Type t) static NdbOut& operator<<(NdbOut& out, const Op& op) { - out << "t=" << op.type; + out << op.type; out << " " << op.data[0]; out << " [" << op.data[1] << "]"; + if (op.gci != 0) + out << " gci:" << op.gci; return out; } @@ -398,75 +549,104 @@ seteventtype(Op* ev, NdbDictionary::Event::TableEvent te) return 0; } +static Op* g_opfree = 0; +static uint g_freeops = 0; static uint g_usedops = 0; -static uint g_usedevs = 0; -static Op g_oplist[g_maxops]; -static Op g_evlist[g_maxops]; -static uint g_maxcom = 8; // max ops per commit - +static uint g_maxcom = 10; // max ops per commit static Op* g_pk_op[g_maxpk]; static Op* g_pk_ev[g_maxpk]; static uint g_seq = 0; - -static NdbRecAttr* g_ra[2][g_ncol]; // 0-post 1-pre +static NdbRecAttr* g_ev_ra[2][g_maxcol]; // 0-post 1-pre +static NdbBlob* g_ev_bh[2][g_maxcol]; // 0-post 1-pre static Op* g_rec_ev; -static uint g_ev_cnt[g_maxpk]; - -static uint -getfreeops() -{ - assert(g_opts.maxops >= g_usedops); - return g_opts.maxops - g_usedops; -} - -static uint -getfreeevs() -{ - assert(g_opts.maxops >= g_usedevs); - return g_opts.maxops - g_usedevs; -} +static uint g_ev_pos[g_maxpk]; static Op* -getop() +getop(Op::Kind a_kind) { - if (g_usedops < g_opts.maxops) { - Op* op = &g_oplist[g_usedops++]; - op->kind = Op::OP; - op->init(); - return op; + if (g_opfree == 0) { + assert(g_freeops == 0); + Op* op = new Op; + assert(op != 0); + op->next_free = g_opfree; + g_opfree = op; + op->free = true; + g_freeops++; } - assert(false); - return 0; + Op* op = g_opfree; + g_opfree = op->next_free; + assert(g_freeops != 0); + g_freeops--; + g_usedops++; + op->init(a_kind); + return op; } -static Op* -getev() +static void +freeop(Op* op) { - if (g_usedevs < g_opts.maxops) { - Op* ev = &g_evlist[g_usedevs++]; - ev->kind = Op::EV; - ev->init(); - return ev; - } - assert(false); - return 0; + assert(! op->free); + op->data[0].free(); + op->data[1].free(); + op->free = true; + op->next_free = g_opfree; + g_opfree = op; + g_freeops++; + assert(g_usedops != 0); + g_usedops--; } static void resetmem() { int i, j; - for (j = 0; j < 2; j++) - for (i = 0; i < g_ncol; i++) - g_ra[j][i] = 0; - g_rec_ev = 0; - for (i = 0; i < g_opts.maxpk; i++) - g_pk_op[i] = 0; - for (i = 0; i < g_opts.maxpk; i++) - g_ev_cnt[i] = 0; - g_seq = 0; - g_usedops = 0; - g_usedevs = 0; + for (j = 0; j < 2; j++) { + for (i = 0; i < g_maxcol; i++) { + g_ev_ra[j][i] = 0; + g_ev_bh[j][i] = 0; + } + } + if (g_rec_ev != 0) { + freeop(g_rec_ev); + g_rec_ev = 0; + } + Uint32 pk1; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) + g_ev_pos[pk1] = 0; + // leave g_seq + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + if (g_pk_op[pk1] != 0) { + Op* tot_op = g_pk_op[pk1]; + while (tot_op->next_gci != 0) { + Op* gci_op = tot_op->next_gci; + while (gci_op->next_com != 0) { + Op* com_op = gci_op->next_com; + while (com_op->next_op != 0) { + Op* op = com_op->next_op; + com_op->next_op = op->next_op; + freeop(op); + } + gci_op->next_com = com_op->next_com; + freeop(com_op); + } + tot_op->next_gci = gci_op->next_gci; + freeop(gci_op); + } + freeop(tot_op); + g_pk_op[pk1] = 0; + } + if (g_pk_ev[pk1] != 0) { + Op* tot_op = g_pk_ev[pk1]; + while (tot_op->next_ev != 0) { + Op* ev = tot_op->next_ev; + tot_op->next_ev = ev->next_ev; + freeop(ev); + } + freeop(tot_op); + g_pk_ev[pk1] = 0; + } + } + assert(g_usedops == 0); } struct Comp { @@ -487,43 +667,43 @@ static const uint g_ncomp = sizeof(g_comp)/sizeof(g_comp[0]); static int checkop(const Op* op, Uint32& pk1) { - const Data (&d)[2] = op->data; Op::Type t = op->type; - chkrc(t == Op::NUL || t == Op::INS || t == Op::DEL || t == Op::UPD); - { const Col& c = getcol("pk1"); - chkrc(d[0].ind[c.no] == 0); - pk1 = d[0].pk1; + if (t == Op::NUL) + return 0; + chkrc(t == Op::INS || t == Op::DEL || t == Op::UPD); + const Data& d0 = op->data[0]; + const Data& d1 = op->data[1]; + { + const Col& c = getcol("pk1"); + chkrc(d0.ind[c.no] == 0); + pk1 = d0.pk1; chkrc(pk1 < g_opts.maxpk); } uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = getcol(i); - if (t != Op::NUL) { - if (c.pk) { - chkrc(d[0].ind[i] == 0); // even DEL has PK in post data - if (t == Op::INS) { - chkrc(d[1].ind[i] == -1); - } else if (t == Op::DEL) { -#ifdef ndb_event_cares_about_pk_pre_data - chkrc(d[1].ind[i] == -1); -#endif - } else { -#ifdef ndb_event_cares_about_pk_pre_data - chkrc(d[1].ind[i] == 0); -#endif - } - } else { - if (t == Op::INS) { - chkrc(d[0].ind[i] >= 0); - chkrc(d[1].ind[i] == -1); - } else if (t == Op::DEL) { - chkrc(d[0].ind[i] == -1); - chkrc(d[1].ind[i] >= 0); - } else if (op->kind == Op::OP) { - chkrc(d[0].ind[i] >= 0); - chkrc(d[1].ind[i] >= 0); - } - } + const int ind0 = d0.ind[i]; + const int ind1 = d1.ind[i]; + // the rules are the rules.. + if (c.pk) { + chkrc(ind0 == 0); // always PK in post data + if (t == Op::INS) + chkrc(ind1 == -1); + if (t == Op::DEL) + chkrc(ind1 == -1); // no PK in pre data + if (t == Op::UPD) + chkrc(ind1 == 0); + } + if (! c.pk) { + if (t == Op::INS) + chkrc(ind0 >= 0 && ind1 == -1); + if (t == Op::DEL) + chkrc(ind0 == -1 && ind1 >= 0); // always non-PK in pre data + if (t == Op::UPD) + chkrc(ind0 == -1 || ind1 >= 0); // update must have pre data + } + if (! c.nullable) { + chkrc(ind0 <= 0 && ind1 <= 0); } } return 0; @@ -542,28 +722,51 @@ comptype(Op::Type t1, Op::Type t2) // only non-NUL static void copycol(const Col& c, const Data& d1, Data& d3) { - if ((d3.ind[c.no] = d1.ind[c.no]) != -1) - memmove(d3.ptr[c.no], d1.ptr[c.no], c.size); + uint i = c.no; + if ((d3.ind[i] = d1.ind[i]) == 0) { + if (! c.isblob()) { + memmove(d3.ptr[i].v, d1.ptr[i].v, c.size); + } else { + Data::Txt& t1 = *d1.ptr[i].txt; + Data::Txt& t3 = *d3.ptr[i].txt; + delete [] t3.val; + t3.val = new char [t1.len]; + t3.len = t1.len; + memcpy(t3.val, t1.val, t1.len); + } + } } static void -copykeys(const Data& d1, Data& d3) +copydata(const Data& d1, Data& d3, bool pk, bool nonpk) { uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = g_col[i]; - if (c.pk) + if (c.pk && pk || ! c.pk && nonpk) copycol(c, d1, d3); } } static void -copydata(const Data& d1, Data& d3) +compdata(const Data& d1, const Data& d2, Data& d3, bool pk, bool nonpk) { uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = g_col[i]; - copycol(c, d1, d3); + if (c.pk && pk || ! c.pk && nonpk) { + const Data* d = 0; + if (d1.ind[i] == -1 && d2.ind[i] == -1) + d3.ind[i] = -1; + else if (d1.ind[i] == -1 && d2.ind[i] != -1) + d = &d2; + else if (d1.ind[i] != -1 && d2.ind[i] == -1) + d = &d1; + else + d = &d2; + if (d != 0) + copycol(c, *d, d3); + } } } @@ -571,33 +774,13 @@ static void copyop(const Op* op1, Op* op3) { op3->type = op1->type; - copydata(op1->data[0], op3->data[0]); - copydata(op1->data[1], op3->data[1]); + copydata(op1->data[0], op3->data[0], true, true); + copydata(op1->data[1], op3->data[1], true, true); + op3->gci = op1->gci; Uint32 pk1_tmp; reqrc(checkop(op3, pk1_tmp) == 0); } -// not needed for ops -static void -compdata(const Data& d1, const Data& d2, Data& d3) // d2 overrides d1 -{ - uint i; - for (i = 0; i < g_ncol; i++) { - const Col& c = g_col[i]; - const Data* d = 0; - if (d1.ind[i] == -1 && d2.ind[i] == -1) - d3.ind[i] = -1; - else if (d1.ind[i] == -1 && d2.ind[i] != -1) - d = &d2; - else if (d1.ind[i] != -1 && d2.ind[i] == -1) - d = &d1; - else - d = &d2; - if (d != 0) - copycol(c, *d, d3); - } -} - static int compop(const Op* op1, const Op* op2, Op* op3) // op1 o op2 = op3 { @@ -610,16 +793,38 @@ compop(const Op* op1, const Op* op2, Op* op3) // op1 o op2 = op3 copyop(op2, op3); return 0; } + Op::Kind kind = + op1->kind == Op::OP && op2->kind == Op::OP ? Op::OP : Op::EV; + Op* res_op = getop(kind); chkrc((comp = comptype(op1->type, op2->type)) != 0); - op3->type = comp->t3; - copykeys(op2->data[0], op3->data[0]); - if (op3->type != Op::DEL) - copydata(op2->data[0], op3->data[0]); - if (op3->type != Op::INS) - copydata(op1->data[1], op3->data[1]); + res_op->type = comp->t3; + if (res_op->type == Op::INS) { + // INS o UPD + compdata(op1->data[0], op2->data[0], res_op->data[0], true, true); + // pre = undef + } + if (res_op->type == Op::DEL) { + // UPD o DEL + copydata(op2->data[0], res_op->data[0], true, false); // PK + copydata(op1->data[1], res_op->data[1], false, true); // non-PK + } + if (res_op->type == Op::UPD && op1->type == Op::DEL) { + // DEL o INS + copydata(op2->data[0], res_op->data[0], true, true); + copydata(op1->data[0], res_op->data[1], true, false); // PK + copydata(op1->data[1], res_op->data[1], false, true); // non-PK + } + if (res_op->type == Op::UPD && op1->type == Op::UPD) { + // UPD o UPD + compdata(op1->data[0], op2->data[0], res_op->data[0], true, true); + compdata(op2->data[1], op1->data[1], res_op->data[1], true, true); + } + assert(op1->gci == op2->gci); + res_op->gci = op2->gci; Uint32 pk1_tmp; - reqrc(checkop(op3, pk1_tmp) == 0); - // not eliminating identical post-pre fields + reqrc(checkop(res_op, pk1_tmp) == 0); + copyop(res_op, op3); + freeop(res_op); return 0; } @@ -632,12 +837,14 @@ createevent() NdbDictionary::Event evt(g_evtname); evt.setTable(*g_tab); evt.addTableEvent(NdbDictionary::Event::TE_ALL); - // pk always - evt.addEventColumn("pk1"); - evt.addEventColumn("pk2"); - // simple cols - evt.addEventColumn("seq"); - evt.addEventColumn("cc1"); + uint i; + for (i = 0; i < ncol(); i++) { + const Col& c = g_col[i]; + evt.addEventColumn(c.name); + } +#ifdef version51rbr + evt.separateEvents(g_opts.separate_events); +#endif if (g_dic->getEvent(evt.getName()) != 0) chkdb(g_dic->dropEvent(evt.getName()) == 0); chkdb(g_dic->createEvent(evt) == 0); @@ -666,20 +873,22 @@ createeventop() chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName(), bsz)) != 0); #else chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName())) != 0); +#ifdef version51rbr + g_evt_op->separateEvents(g_opts.separate_events); // not yet inherited +#endif #endif uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = g_col[i]; Data (&d)[2] = g_rec_ev->data; - switch (c.type) { - case NdbDictionary::Column::Unsigned: - case NdbDictionary::Column::Char: - chkdb((g_ra[0][i] = g_evt_op->getValue(c.name, (char*)d[0].ptr[i])) != 0); - chkdb((g_ra[1][i] = g_evt_op->getPreValue(c.name, (char*)d[1].ptr[i])) != 0); - break; - default: - assert(false); - break; + if (! c.isblob()) { + chkdb((g_ev_ra[0][i] = g_evt_op->getValue(c.name, (char*)d[0].ptr[i].v)) != 0); + chkdb((g_ev_ra[1][i] = g_evt_op->getPreValue(c.name, (char*)d[1].ptr[i].v)) != 0); + } else { +#ifdef version51rbr + chkdb((g_ev_bh[0][i] = g_evt_op->getBlobHandle(c.name)) != 0); + chkdb((g_ev_bh[1][i] = g_evt_op->getPreBlobHandle(c.name)) != 0); +#endif } } return 0; @@ -705,9 +914,9 @@ waitgci() // wait for event to be installed and for at least 1 GCI to pass chkdb((g_con = g_ndb->startTransaction()) != 0); { // forced to exec a dummy op Uint32 pk1; - char pk2[g_charlen]; + char pk2[g_charlen + 1]; pk1 = g_maxpk; - memset(pk2, 0x20, g_charlen); + sprintf(pk2, "%-*u", g_charlen, pk1); chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0); chkdb(g_op->readTuple() == 0); chkdb(g_op->equal("pk1", (char*)&pk1) == 0); @@ -723,61 +932,153 @@ waitgci() // wait for event to be installed and for at least 1 GCI to pass break; } i = 1; + sleep(1); } return 0; } +// scan table and set current tot_op for each pk1 static int -makeop(Op* op, Uint32 pk1, Op::Type t, const Op* prev_op) +scantab() { - op->type = t; - if (t != Op::INS) - copydata(prev_op->data[0], op->data[1]); + NdbRecAttr* ra[g_maxcol]; + NdbBlob* bh[g_maxcol]; + Op* rec_op = getop(Op::OP); + Data& d0 = rec_op->data[0]; + chkdb((g_con = g_ndb->startTransaction()) != 0); + chkdb((g_scan_op = g_con->getNdbScanOperation(g_tabname)) != 0); + chkdb(g_scan_op->readTuples() == 0); uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = getcol(i); - Data (&d)[2] = op->data; - if (i == getcol("pk1").no) { - d[0].pk1 = pk1; - d[0].ind[i] = 0; - continue; + if (! c.isblob()) { + chkdb((ra[i] = g_scan_op->getValue(c.name, (char*)d0.ptr[i].v)) != 0); + } else { + chkdb((bh[i] = g_scan_op->getBlobHandle(c.name)) != 0); } - if (i == getcol("pk2").no) { - sprintf(d[0].pk2, "%-*u", g_charlen, d[0].pk1); - d[0].ind[i] = 0; - continue; - } - if (t == Op::DEL) { - d[0].ind[i] = -1; - continue; - } - if (i == getcol("seq").no) { - d[0].seq = g_seq++; - d[0].ind[i] = 0; - continue; - } - uint u; - u = urandom(100); - if (c.nullable && u < 20) { - d[0].ind[i] = 1; + } + chkdb(g_con->execute(NoCommit) == 0); + int ret; + while ((ret = g_scan_op->nextResult()) == 0) { + Uint32 pk1 = d0.pk1; + if (pk1 >= g_opts.maxpk) continue; + rec_op->type = Op::INS; + for (i = 0; i < ncol(); i++) { + const Col& c = getcol(i); + int ind; + if (! c.isblob()) { + ind = ra[i]->isNULL(); + } else { +#ifdef version51rbr + int ret; + ret = bh[i]->getDefined(ind); + assert(ret == 0); + if (ind == 0) { + Data::Txt& t = *d0.ptr[i].txt; + Uint64 len64; + ret = bh[i]->getLength(len64); + assert(ret == 0); + t.len = (uint)len64; + delete [] t.val; + t.val = new char [t.len]; + memset(t.val, 'X', t.len); + Uint32 len = t.len; + ret = bh[i]->readData(t.val, len); + assert(ret == 0 && len == t.len); + } +#endif + } + assert(ind >= 0); + d0.ind[i] = ind; } + assert(g_pk_op[pk1] == 0); + Op* tot_op = g_pk_op[pk1] = getop(Op::OP); + copyop(rec_op, tot_op); + tot_op->type = Op::INS; + } + chkdb(ret == 1); + g_ndb->closeTransaction(g_con); + g_scan_op = 0; + g_con = 0; + freeop(rec_op); + return 0; +} + +static void +makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t) +{ + uint i = c.no; + if (c.pk) { switch (c.type) { case NdbDictionary::Column::Unsigned: { - u = urandom(0); - Uint32* p = (Uint32*)d[0].ptr[i]; + Uint32* p = d.ptr[i].u32; + *p = pk1; + } + break; + case NdbDictionary::Column::Char: + { + char* p = d.ptr[i].ch; + sprintf(p, "%-*u", g_charlen, pk1); + } + break; + default: + assert(false); + break; + } + d.ind[i] = 0; + } else if (t == Op::DEL) { + ; + } else if (i == getcol("seq").no) { + d.seq = g_seq++; + d.ind[i] = 0; + } else if (t == Op::INS && c.nullable && urandom(10, 100)) { + d.noop |= (1 << i); + d.ind[i] = 1; // implicit NULL value is known + } else if (t == Op::UPD && urandom(10, 100)) { + d.noop |= (1 << i); + d.ind[i] = -1; // fixed up in caller + } else if (c.nullable && urandom(10, 100)) { + d.ind[i] = 1; + } else { + switch (c.type) { + case NdbDictionary::Column::Unsigned: + { + Uint32* p = d.ptr[i].u32; + uint u = urandom(); *p = u; } break; case NdbDictionary::Column::Char: { - u = urandom(g_charlen); - char* p = (char*)d[0].ptr[i]; + char* p = d.ptr[i].ch; + uint u = urandom(g_charlen); uint j; for (j = 0; j < g_charlen; j++) { - uint v = urandom(3); - p[j] = j < u ? "abcde"[v] : 0x20; + uint v = urandom(strlen(g_charval)); + p[j] = j < u ? g_charval[v] : 0x20; + } + } + break; + case NdbDictionary::Column::Text: + { + Data::Txt& t = *d.ptr[i].txt; + uint u = urandom(g_maxblobsize); + u = urandom(u); // 4x bias for smaller blobs + u = urandom(u); + delete [] t.val; + t.val = new char [u]; + t.len = u; + uint j = 0; + while (j < u) { + assert(u > 0); + uint k = 1 + urandom(u - 1); + if (k > u - j) + k = u - j; + uint v = urandom(strlen(g_charval)); + memset(&t.val[j], g_charval[v], k); + j += k; } } break; @@ -785,74 +1086,78 @@ makeop(Op* op, Uint32 pk1, Op::Type t, const Op* prev_op) assert(false); break; } - d[0].ind[i] = 0; + d.ind[i] = 0; } - Uint32 pk1_tmp = ~(Uint32)0; - chkrc(checkop(op, pk1_tmp) == 0); - reqrc(pk1 == pk1_tmp); - return 0; } static void -makeop(Op* tot_op, Op* com_op, Uint32 pk1, Op::Type t) +makeop(const Op* prev_op, Op* op, Uint32 pk1, Op::Type t) { - Op tmp_op; - tmp_op.kind = Op::OP; - Op* op = getop(); - reqrc(makeop(op, pk1, t, tot_op) == 0); - // add to end - Op* last_op = com_op; - while (last_op->next_op != 0) - last_op = last_op->next_op; - last_op->next_op = op; - // merge into chain head - tmp_op.init(); - reqrc(compop(com_op, op, &tmp_op) == 0); - copyop(&tmp_op, com_op); - // merge into total op - tmp_op.init(); - reqrc(compop(tot_op, op, &tmp_op) == 0); - copyop(&tmp_op, tot_op); - // counts - com_op->num_op += 1; - tot_op->num_op += 1; + op->type = t; + const Data& dp = prev_op->data[0]; + Data& d0 = op->data[0]; + Data& d1 = op->data[1]; + uint i; + for (i = 0; i < ncol(); i++) { + const Col& c = getcol(i); + makedata(c, d0, pk1, t); + if (t == Op::INS) { + d1.ind[i] = -1; + } else if (t == Op::DEL) { + assert(dp.ind[i] >= 0); + if (c.pk) + d1.ind[i] = -1; + else + copycol(c, dp, d1); + } else if (t == Op::UPD) { + assert(dp.ind[i] >= 0); + if (d0.ind[i] == -1) // not updating this col + copycol(c, dp, d0); // must keep track of data + copycol(c, dp, d1); + } else { + assert(false); + } + } + Uint32 pk1_tmp = ~(Uint32)0; + reqrc(checkop(op, pk1_tmp) == 0); + reqrc(pk1 == pk1_tmp); } static void makeops() { ll1("makeops"); - uint resv = g_opts.opstr == 0 ? 2 * g_opts.maxpk : 0; // for final deletes - uint next = g_opts.opstr == 0 ? g_maxcom : strlen(g_opts.opstr); - Op tmp_op; - tmp_op.kind = Op::OP; Uint32 pk1 = 0; - while (getfreeops() >= resv + 2 + next && pk1 < g_opts.maxpk) { - if (g_opts.opstr == 0) + while (g_usedops < g_opts.maxops && pk1 < g_opts.maxpk) { + if (g_opts.opstring == 0) pk1 = urandom(g_opts.maxpk); - ll2("makeops: pk1=" << pk1 << " free=" << getfreeops()); + ll2("makeops: pk1=" << pk1); // total op on the pk so far // optype either NUL=initial/deleted or INS=created Op* tot_op = g_pk_op[pk1]; if (tot_op == 0) - tot_op = g_pk_op[pk1] = getop(); //1 + tot_op = g_pk_op[pk1] = getop(Op::OP); assert(tot_op->type == Op::NUL || tot_op->type == Op::INS); // add new commit chain to end - Op* last_com = tot_op; - while (last_com->next_com != 0) - last_com = last_com->next_com; - Op* com_op = getop(); //2 - last_com->next_com = com_op; + Op* last_gci = tot_op; + while (last_gci->next_gci != 0) + last_gci = last_gci->next_gci; + Op* gci_op = getop(Op::OP); + last_gci->next_gci = gci_op; + Op* com_op = getop(Op::OP); + gci_op->next_com = com_op; // length of random chain uint len = ~0; - if (g_opts.opstr == 0) + if (g_opts.opstring == 0) { len = 1 + urandom(g_maxcom - 1); + len = 1 + urandom(len - 1); // 2x bias for short chain + } ll2("makeops: com chain"); uint n = 0; while (1) { - // random or from g_opts.opstr + // random or from current g_opts.opstring part Op::Type t; - if (g_opts.opstr == 0) { + if (g_opts.opstring == 0) { if (n == len) break; do { @@ -860,10 +1165,11 @@ makeops() } while (tot_op->type == Op::NUL && (t == Op::DEL || t == Op::UPD) || tot_op->type == Op::INS && t == Op::INS); } else { - uint m = strlen(g_opts.opstr); + const char* str = g_opstringpart[g_loop % g_opstringparts]; + uint m = strlen(str); uint k = tot_op->num_com + tot_op->num_op; assert(k < m); - char c = g_opts.opstr[k]; + char c = str[k]; if (c == 'c') { if (k + 1 == m) pk1 += 1; @@ -874,30 +1180,27 @@ makeops() assert(q != 0); t = (Op::Type)(q - p); } - makeop(tot_op, com_op, pk1, t); + Op* op = getop(Op::OP); + makeop(tot_op, op, pk1, t); + // add to end + Op* last_op = com_op; + while (last_op->next_op != 0) + last_op = last_op->next_op; + last_op->next_op = op; + // merge into chain head and total op + reqrc(compop(com_op, op, com_op) == 0); + reqrc(compop(tot_op, op, tot_op) == 0); assert(tot_op->type == Op::NUL || tot_op->type == Op::INS); + // counts + com_op->num_op += 1; + tot_op->num_op += 1; n++; } + // copy to gci level + copyop(com_op, gci_op); tot_op->num_com += 1; } - assert(getfreeops() >= resv); - // terminate with DEL if necessary - for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { - Op* tot_op = g_pk_op[pk1]; - if (tot_op == 0) - continue; - if (tot_op->type == Op::NUL) - continue; - assert(g_opts.opstr == 0); - Op* last_com = tot_op; - while (last_com->next_com != 0) - last_com = last_com->next_com; - Op* com_op = getop(); //1 - last_com->next_com = com_op; - makeop(tot_op, com_op, pk1, Op::DEL); - assert(tot_op->type == Op::NUL); - tot_op->num_com += 1; - } + ll1("makeops: used ops = " << g_usedops); } static int @@ -919,23 +1222,36 @@ addndbop(Op* op) break; } uint i; - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = getcol(i); const Data& d = op->data[0]; if (! c.pk) continue; - chkdb(g_op->equal(c.name, (char*)d.ptr[i]) == 0); + chkdb(g_op->equal(c.name, (const char*)d.ptr[i].v) == 0); } if (op->type != Op::DEL) { - for (i = 0; i < g_ncol; i++) { + for (i = 0; i < ncol(); i++) { const Col& c = getcol(i); const Data& d = op->data[0]; if (c.pk) continue; - if (d.ind[i] == -1) + if (d.noop & (1 << i)) continue; - const char* ptr = d.ind[i] == 0 ? (char*)d.ptr[i] : 0; - chkdb(g_op->setValue(c.name, ptr) == 0); + assert(d.ind[i] >= 0); + if (! c.isblob()) { + if (d.ind[i] == 0) + chkdb(g_op->setValue(c.name, (const char*)d.ptr[i].v) == 0); + else + chkdb(g_op->setValue(c.name, (const char*)0) == 0); + } else { + const Data::Txt& t = *d.ptr[i].txt; + g_bh = g_op->getBlobHandle(c.name); + if (d.ind[i] == 0) + chkdb(g_bh->setValue(t.val, t.len) == 0); + else + chkdb(g_bh->setValue(0, 0) == 0); + g_bh = 0; + } } } g_op = 0; @@ -947,40 +1263,43 @@ runops() { ll1("runops"); Uint32 pk1; - const Op* com_op[g_maxpk]; - uint left = 0; + Op* gci_op[g_maxpk]; + uint left = 0; // number of pks with ops for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { - com_op[pk1] = 0; + gci_op[pk1] = 0; // total op on the pk Op* tot_op = g_pk_op[pk1]; if (tot_op == 0) continue; // first commit chain - assert(tot_op->next_com != 0); - com_op[pk1] = tot_op->next_com; + assert(tot_op->next_gci != 0); + gci_op[pk1] = tot_op->next_gci; left++; } while (left != 0) { pk1 = urandom(g_opts.maxpk); - if (com_op[pk1] == 0) + if (gci_op[pk1] == 0) continue; // do the ops in one transaction - ll2("runops: pk1=" << pk1); chkdb((g_con = g_ndb->startTransaction()) != 0); + Op* com_op = gci_op[pk1]->next_com; + assert(com_op != 0); // first op in chain - Op* op = com_op[pk1]->next_op; + Op* op = com_op->next_op; assert(op != 0); while (op != 0) { - ll2("add op:" << *op); + ll2("runops:" << *op); chkrc(addndbop(op) == 0); op = op->next_op; } chkdb(g_con->execute(Commit) == 0); + gci_op[pk1]->gci = com_op->gci = g_con->getGCI(); + ll2("commit: gci=" << com_op->gci); g_ndb->closeTransaction(g_con); g_con = 0; // next chain - com_op[pk1] = com_op[pk1]->next_com; - if (com_op[pk1] == 0) { + gci_op[pk1] = gci_op[pk1]->next_gci; + if (gci_op[pk1] == 0) { assert(left != 0); left--; } @@ -989,13 +1308,106 @@ runops() return 0; } +// move com chains with same gci under same gci entry +static int +mergeops() +{ + ll1("mergeops"); + uint mergecnt = 0; + Uint32 pk1; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + Op* tot_op = g_pk_op[pk1]; + if (tot_op == 0) + continue; + Op* gci_op = tot_op->next_gci; + assert(gci_op != 0); + while (gci_op != 0) { + Op* com_op = gci_op->next_com; + assert(com_op != 0 && com_op->next_com == 0); + assert(gci_op->gci == com_op->gci); + Op* last_com = com_op; + Op* gci_op2 = gci_op->next_gci; + while (gci_op2 != 0 && gci_op->gci == gci_op2->gci) { + // move link to com level + last_com = last_com->next_com = gci_op2->next_com; + // merge to gci + reqrc(compop(gci_op, gci_op2, gci_op) == 0); + // move to next and discard + Op* tmp_op = gci_op2; + gci_op2 = gci_op2->next_gci; + freeop(tmp_op); + mergecnt++; + } + gci_op = gci_op->next_gci = gci_op2; + } + } + ll1("mergeops: used ops = " << g_usedops); + ll1("mergeops: merged " << mergecnt << " gci entries"); + return 0; +} + +// set bit for equal post/pre data in UPD, for use in event match +static void +cmppostpre() +{ + ll1("cmppostpre"); + Uint32 pk1; + for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) { + Op* tot_op = g_pk_op[pk1]; + Op* gci_op = tot_op ? tot_op->next_gci : 0; + while (gci_op != 0) { + if (gci_op->type == Op::UPD) { + Data (&d)[2] = gci_op->data; + uint i; + for (i = 0; i < ncol(); i++) { + const Col& c = getcol(i); + bool eq = + d[0].ind[i] == 1 && d[1].ind[i] == 1 || + d[0].ind[i] == 0 && d[1].ind[i] == 0 && cmpcol(c, d[0], d[1]) == 0; + if (eq) { + d[0].ppeq |= (1 << i); + d[1].ppeq |= (1 << i); + } + } + } + gci_op = gci_op->next_gci; + } + } +} +static int +cmpopevdata(const Data& d1, const Data& d2) +{ + uint i; + for (i = 0; i < ncol(); i++) { + const Col& c = getcol(i); + if (cmpcol(c, d1, d2) != 0) { + if ((d1.ppeq & (1 << i)) && d2.ind[i] == -1) + ; // post/pre data equal and no event data returned is OK + else + return 1; + } + } + return 0; +} + +// compare operation to event data +static int +cmpopevdata(const Data (&d1)[2], const Data (&d2)[2]) +{ + if (cmpopevdata(d1[0], d2[0]) != 0) + return 1; + if (cmpopevdata(d1[1], d2[1]) != 0) + return 1; + return 0; +} + static int matchevent(Op* ev) { Op::Type t = ev->type; - Data (&d)[2] = ev->data; + Data (&d2)[2] = ev->data; // get PK - Uint32 pk1 = d[0].pk1; + Uint32 pk1 = d2[0].pk1; chkrc(pk1 < g_opts.maxpk); // on error repeat and print details uint loop = 0; @@ -1004,42 +1416,59 @@ matchevent(Op* ev) ll1("matchevent: pk1=" << pk1 << " type=" << t); ll2("EVT: " << *ev); Op* tot_op = g_pk_op[pk1]; - Op* com_op = tot_op ? tot_op->next_com : 0; - uint cnt = 0; + Op* gci_op = tot_op ? tot_op->next_gci : 0; + uint pos = 0; bool ok = false; - while (com_op != 0) { - ll2("COM: " << *com_op); - Op* op = com_op->next_op; - assert(op != 0); - while (op != 0) { - ll2("---: " << *op); - op = op->next_op; + while (gci_op != 0) { + ll2("GCI: " << *gci_op); + // print details + Op* com_op = gci_op->next_com; + assert(com_op != 0); + while (com_op != 0) { + ll2("COM: " << *com_op); + Op* op = com_op->next_op; + assert(op != 0); + while (op != 0) { + ll2("OP : " << *op); + op = op->next_op; + } + com_op = com_op->next_com; } - if (com_op->type != Op::NUL) { - if (com_op->type == t) { - const Data (&d2)[2] = com_op->data; - if (t == Op::INS && d2[0].seq == d[0].seq || - t == Op::DEL && d2[1].seq == d[1].seq || - t == Op::UPD && d2[0].seq == d[0].seq) { - if (cnt == g_ev_cnt[pk1]) { - if (! com_op->match) { - ll2("match pos " << cnt); - ok = com_op->match = true; - } else { - ll2("duplicate match"); - } - } else { - ll2("match bad pos event=" << g_ev_cnt[pk1] << " op=" << cnt); - } + // match agains GCI op + if (gci_op->type != Op::NUL) { + const Data (&d1)[2] = gci_op->data; + if (cmpopevdata(d1, d2) == 0) { + bool tmpok = true; + if (gci_op->type != t) { + ll2("***: wrong type " << gci_op->type << " != " << t); + tmpok = false; + } + if (gci_op->match) { + ll2("***: duplicate match"); + tmpok = false; + } + if (pos != g_ev_pos[pk1]) { + ll2("***: wrong pos " << pos << " != " << g_ev_pos[pk1]); + tmpok = false; + } + if (gci_op->gci != ev->gci) { + ll2("***: wrong gci " << gci_op->gci << " != " << ev->gci); + tmpok = false; + } + if (tmpok) { + ok = gci_op->match = true; + ll2("===: match"); } } - cnt++; + pos++; } - com_op = com_op->next_com; + gci_op = gci_op->next_gci; } - if (ok) + if (ok) { + ll1("matchevent: match"); return 0; - ll2("no match"); + } + ll1("matchevent: ERROR: no match"); if (g_loglevel >= 2) return -1; loop++; @@ -1056,12 +1485,12 @@ matchevents() Op* tot_ev = g_pk_ev[pk1]; if (tot_ev == 0) continue; - Op* com_ev = tot_ev->next_com; - while (com_ev != 0) { - if (matchevent(com_ev) < 0) + Op* ev = tot_ev->next_ev; + while (ev != 0) { + if (matchevent(ev) < 0) nomatch++; - g_ev_cnt[pk1]++; - com_ev = com_ev->next_com; + g_ev_pos[pk1]++; + ev = ev->next_ev; } } chkrc(nomatch == 0); @@ -1095,22 +1524,58 @@ matchops() return 0; } +static void +geteventdata() +{ + Data (&d)[2] = g_rec_ev->data; + int i, j; + for (j = 0; j < 2; j++) { + for (i = 0; i < ncol(); i++) { + const Col& c = getcol(i); + int ind, ret; + if (! c.isblob()) { + NdbRecAttr* ra = g_ev_ra[j][i]; + ind = ra->isNULL(); + } else { +#ifdef version51rbr + NdbBlob* bh = g_ev_bh[j][i]; + ret = bh->getDefined(ind); + assert(ret == 0); + if (ind == 0) { // value was returned and is not NULL + Data::Txt& t = *d[j].ptr[i].txt; + Uint64 len64; + ret = bh->getLength(len64); + assert(ret == 0); + t.len = (uint)len64; + delete [] t.val; + t.val = new char [t.len]; + memset(t.val, 'X', t.len); + Uint32 len = t.len; + ret = bh->readData(t.val, len); + assert(ret == 0 && len == t.len); + } +#endif + } + d[j].ind[i] = ind; + } + } +} + static int runevents() { ll1("runevents"); - NdbEventOperation* evt_op; - uint npoll = 3; + uint mspoll = 1000; + uint npoll = 6; // strangely long delay while (npoll != 0) { npoll--; int ret; ll1("poll"); - ret = g_ndb->pollEvents(1000); + ret = g_ndb->pollEvents(mspoll); if (ret <= 0) continue; while (1) { - g_rec_ev->init(); - Data (&d)[2] = g_rec_ev->data; + g_rec_ev->init(Op::EV); #ifdef version50 int overrun = g_opts.maxops; chkdb((ret = g_evt_op->next(&overrun)) >= 0); @@ -1124,32 +1589,35 @@ runevents() reqrc(g_evt_op == tmp_op); #endif chkrc(seteventtype(g_rec_ev, g_evt_op->getEventType()) == 0); - // get indicators - { int i, j; - for (j = 0; j < 2; j++) - for (i = 0; i < g_ncol; i++) - d[j].ind[i] = g_ra[j][i]->isNULL(); + geteventdata(); + g_rec_ev->gci = g_evt_op->getGCI(); +#ifdef version50 + // fix to match 5.1 + if (g_rec_ev->type == Op::UPD) { + Uint32 pk1 = g_rec_ev->data[0].pk1; + makedata(getcol("pk1"), g_rec_ev->data[1], pk1, Op::UPD); + makedata(getcol("pk2"), g_rec_ev->data[1], pk1, Op::UPD); } +#endif + // get indicators and blob value ll2("runevents: EVT: " << *g_rec_ev); // check basic sanity Uint32 pk1 = ~(Uint32)0; chkrc(checkop(g_rec_ev, pk1) == 0); // add to events - chkrc(getfreeevs() >= 2); Op* tot_ev = g_pk_ev[pk1]; if (tot_ev == 0) - tot_ev = g_pk_ev[pk1] = getev(); //1 - Op* last_com = tot_ev; - while (last_com->next_com != 0) - last_com = last_com->next_com; + tot_ev = g_pk_ev[pk1] = getop(Op::EV); + Op* last_ev = tot_ev; + while (last_ev->next_ev != 0) + last_ev = last_ev->next_ev; // copy and add - Op* ev = getev(); //3 + Op* ev = getop(Op::EV); copyop(g_rec_ev, ev); - last_com->next_com = ev; + last_ev->next_ev = ev; } } - chkrc(matchevents() == 0); - chkrc(matchops() == 0); + ll1("runevents: used ops = " << g_usedops); return 0; } @@ -1179,18 +1647,23 @@ runtest() setseed(-1); chkrc(createtable() == 0); chkrc(createevent() == 0); - uint n; - for (n = 0; n < g_opts.loop; n++) { - ll0("loop " << n); - setseed(n); + for (g_loop = 0; g_opts.loop == 0 || g_loop < g_opts.loop; g_loop++) { + ll0("loop " << g_loop); + setseed(g_loop); resetmem(); - g_rec_ev = getev(); + chkrc(scantab() == 0); // alternative: save tot_op for loop > 0 + makeops(); + g_rec_ev = getop(Op::EV); chkrc(createeventop() == 0); chkdb(g_evt_op->execute() == 0); chkrc(waitgci() == 0); - makeops(); chkrc(runops() == 0); + if (! g_opts.separate_events) + chkrc(mergeops() == 0); + cmppostpre(); chkrc(runevents() == 0); + chkrc(matchevents() == 0); + chkrc(matchops() == 0); chkrc(dropeventop() == 0); } chkrc(dropevent() == 0); @@ -1204,31 +1677,41 @@ static struct my_option my_long_options[] = { NDB_STD_OPTS("test_event_merge"), - { "abort-on-error", 1008, "Do abort() on any error", + { "abort-on-error", 1001, "Do abort() on any error", (gptr*)&g_opts.abort_on_error, (gptr*)&g_opts.abort_on_error, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "loglevel", 1001, "Logging level in this program (default 0)", + { "loglevel", 1002, "Logging level in this program (default 0)", (gptr*)&g_opts.loglevel, (gptr*)&g_opts.loglevel, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "loop", 1002, "Number of test loops (default 1, 0=forever)", + { "loop", 1003, "Number of test loops (default 2, 0=forever)", (gptr*)&g_opts.loop, (gptr*)&g_opts.loop, 0, - GET_INT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0 }, - { "maxops", 1003, "Number of PK operations (default 2000)", + GET_INT, REQUIRED_ARG, 2, 0, 0, 0, 0, 0 }, + { "maxops", 1004, "Approx number of PK operations (default 1000)", (gptr*)&g_opts.maxops, (gptr*)&g_opts.maxops, 0, - GET_UINT, REQUIRED_ARG, 2000, 0, g_maxops, 0, 0, 0 }, - { "maxpk", 1004, "Number of different PK values (default 10)", + GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0 }, + { "maxpk", 1005, "Number of different PK values (default 10)", (gptr*)&g_opts.maxpk, (gptr*)&g_opts.maxpk, 0, GET_UINT, REQUIRED_ARG, 10, 1, g_maxpk, 0, 0, 0 }, - { "opstr", 1005, "Ops to run e.g. idiucdc (c = commit, default random)", - (gptr*)&g_opts.opstr, (gptr*)&g_opts.opstr, 0, + { "no-blobs", 1006, "Omit blob attributes (5.0: true)", + (gptr*)&g_opts.no_blobs, (gptr*)&g_opts.no_blobs, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "no-multiops", 1007, "Allow only 1 operation per commit", + (gptr*)&g_opts.no_multiops, (gptr*)&g_opts.no_multiops, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "one-blob", 1008, "Only one blob attribute (defautt 2)", + (gptr*)&g_opts.one_blob, (gptr*)&g_opts.one_blob, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "opstring", 1009, "Operations to run e.g. idiucdc (c is commit) or" + " iuuc:uudc (the : separates loops)", + (gptr*)&g_opts.opstring, (gptr*)&g_opts.opstring, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "seed", 1006, "Random seed (0=loop number, default -1=random)", + { "seed", 1010, "Random seed (0=loop number, default -1=random)", (gptr*)&g_opts.seed, (gptr*)&g_opts.seed, 0, GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0 }, - { "separate-events", 1007, "Do not combine events per GCI >5.0", + { "separate-events", 1011, "Do not combine events per GCI (5.0: true)", (gptr*)&g_opts.separate_events, (gptr*)&g_opts.separate_events, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "use-table", 1008, "Use existing table 'tem1'", + { "use-table", 1012, "Use existing table 'tem1'", (gptr*)&g_opts.use_table, (gptr*)&g_opts.use_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, @@ -1245,14 +1728,36 @@ usage() static int checkopts() { - if (g_opts.opstr != 0) { - const char* s = g_opts.opstr; - uint n = strlen(s); - if (n < 3 || s[0] != 'i' || s[n-2] != 'd' || s[n-1] != 'c') - return -1; - while (*s != 0) - if (strchr("iduc", *s++) == 0) +#ifdef version50 + g_opts.separate_events = true; +#endif + if (g_opts.separate_events) { + g_opts.no_blobs = true; + } + if (g_opts.no_multiops) { + g_maxcom = 1; + } + if (g_opts.opstring != 0) { + uint len = strlen(g_opts.opstring); + char* str = new char [len + 1]; + memcpy(str, g_opts.opstring, len + 1); + char* s = str; + while (1) { + g_opstringpart[g_opstringparts++] = s; + s = strchr(s, ':'); + if (s == 0) + break; + *s++ = 0; + } + uint i; + for (i = 0; i < g_opstringparts; i++) { + const char* s = g_opstringpart[i]; + while (*s != 0) + if (strchr("iduc", *s++) == 0) + return -1; + if (s == g_opstringpart[i] || s[-1] != 'c') return -1; + } } return 0; } @@ -1280,6 +1785,10 @@ main(int argc, char** argv) return NDBT_ProgramExit(NDBT_OK); } } + if (g_evt_op != 0) { + (void)dropeventop(); + g_evt_op = 0; + } delete g_ndb; delete g_ncc; return NDBT_ProgramExit(NDBT_FAILED); From dad7268273328b0de7c4fca9623960103e2f8fec Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 9 Jan 2006 10:01:07 +0100 Subject: [PATCH 099/154] Add yassl libs to libmysqlclient_r as well. Add a symlink to extra/yassl/include/openssl to inlude/ when compiling with yassl Similiar to readline) --- config/ac-macros/yassl.m4 | 4 +++- include/Makefile.am | 3 ++- libmysql_r/Makefile.am | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4 index 77208faee0c..b4160ad2a99 100644 --- a/config/ac-macros/yassl.m4 +++ b/config/ac-macros/yassl.m4 @@ -30,7 +30,9 @@ AC_DEFUN([MYSQL_CHECK_YASSL], [ ;; esac AC_SUBST([yassl_taocrypt_extra_cxxflags]) - + # Link extra/yassl/include/openssl subdir to include/ + yassl_h_ln_cmd="\$(LN) -s \$(top_srcdir)/extra/yassl/include/openssl openssl" + AC_SUBST(yassl_h_ln_cmd) else yassl_dir="" AC_MSG_RESULT(no) diff --git a/include/Makefile.am b/include/Makefile.am index 8ad63f088ac..12b8c301b8d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -33,7 +33,7 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \ mysql_version.h.in my_handler.h my_time.h decimal.h # mysql_version.h are generated -CLEANFILES = mysql_version.h my_config.h readline +CLEANFILES = mysql_version.h my_config.h readline openssl # Some include files that may be moved and patched by configure DISTCLEANFILES = sched.h $(CLEANFILES) @@ -41,6 +41,7 @@ DISTCLEANFILES = sched.h $(CLEANFILES) link_sources: -$(RM) -fr readline @readline_h_ln_cmd@ + @yassl_h_ln_cmd@ my_config.h: ../config.h $(CP) ../config.h my_config.h diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am index ee6dd4cfded..11e65a28a19 100644 --- a/libmysql_r/Makefile.am +++ b/libmysql_r/Makefile.am @@ -22,7 +22,7 @@ target = libmysqlclient_r.la target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@ -LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@ @yassl_libs@ +LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ $(openssl_includes) $(yassl_includes) @ZLIB_INCLUDES@ @@ -32,7 +32,7 @@ include $(top_srcdir)/libmysql/Makefile.shared libmysql_dir = $(top_srcdir)/libmysql libmysqlclient_r_la_SOURCES = $(target_sources) -libmysqlclient_r_la_LIBADD = $(target_libadd) +libmysqlclient_r_la_LIBADD = $(target_libadd) $(yassl_libs_with_path) libmysqlclient_r_la_LDFLAGS = $(target_ldflags) # This is called from the toplevel makefile From 1378eda3c4102ee3f48187ceaefbd70ce1c276da Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Mon, 9 Jan 2006 11:10:49 +0200 Subject: [PATCH 100/154] After merge fix (Lines lost in manual merge) --- sql/sql_handler.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index a69bf04cc48..765a057f740 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -454,6 +454,9 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (insert_fields(thd,tables,tables->db,tables->alias,&it)) goto err0; + select_limit+=offset_limit; + protocol->send_fields(&list,1); + /* In ::external_lock InnoDB resets the fields which tell it that the handle is used in the HANDLER interface. Tell it again that From 2a05a6ba87d0b4d62de6e137b3287d59d583c947 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 9 Jan 2006 10:31:07 +0100 Subject: [PATCH 101/154] Bug #15598 Server crashes in specific case during setting new password - When acl_user->host.hostname is NULL compare it as "" --- mysql-test/r/grant.result | 9 +++++++++ mysql-test/t/grant.test | 12 ++++++++++++ sql/sql_acl.cc | 5 +++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 0a406c1ffc2..13593ec2a88 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -464,3 +464,12 @@ show grants for root@localhost; Grants for root@localhost GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION set names latin1; +insert into mysql.user (host, user) values ('', 'mysqltest_7'); +flush privileges; +set password for mysqltest_7@ = password('systpass'); +show grants for mysqltest_7@; +Grants for mysqltest_7@ +GRANT USAGE ON *.* TO 'mysqltest_7'@'' IDENTIFIED BY PASSWORD '*2FB071A056F9BB745219D9C876814231DAF46517' +drop user mysqltest_7@; +show grants for mysqltest_7@; +ERROR 42000: There is no such grant defined for user 'mysqltest_7' on host '' diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 039e41dcf34..805fa881399 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -421,4 +421,16 @@ revoke all privileges on show grants for root@localhost; set names latin1; +# +# Bug #15598 Server crashes in specific case during setting new password +# - Caused by a user with host '' +# +insert into mysql.user (host, user) values ('', 'mysqltest_7'); +flush privileges; +set password for mysqltest_7@ = password('systpass'); +show grants for mysqltest_7@; +drop user mysqltest_7@; +--error 1141 +show grants for mysqltest_7@; + # End of 4.1 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1ade6ce3064..119952eeda9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1371,7 +1371,8 @@ find_acl_user(const char *host, const char *user, my_bool exact) acl_user->user && !strcmp(user,acl_user->user)) { if (exact ? !my_strcasecmp(&my_charset_latin1, host, - acl_user->host.hostname) : + acl_user->host.hostname ? + acl_user->host.hostname : "") : compare_hostname(&acl_user->host,host,host)) { DBUG_RETURN(acl_user); @@ -3604,7 +3605,7 @@ ACL_USER *check_acl_user(LEX_USER *user_name, if (!(user=acl_user->user)) user= ""; if (!(host=acl_user->host.hostname)) - host= "%"; + host= ""; if (!strcmp(user_name->user.str,user) && !my_strcasecmp(system_charset_info, user_name->host.str, host)) break; From 4bcf14179900eb3ee0b91957c71a303261c1fc93 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 9 Jan 2006 17:12:26 +0100 Subject: [PATCH 102/154] Bug #15598 Server crashes in specific case during setting new password - Comparing host string against NULL caused crash. - If host.hostname is NULL treat it as "" --- mysql-test/r/grant.result | 18 +++++++++--------- mysql-test/t/grant.test | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 304294057d7..eea29161de8 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -437,15 +437,6 @@ delete from mysql.columns_priv where user="mysqltest_3"; flush privileges; drop database mysqltest_1; drop database mysqltest_2; -insert into mysql.user (host, user) values ('', 'mysqltest_7'); -flush privileges; -set password for mysqltest_7@ = password('systpass'); -show grants for mysqltest_7@; -Grants for mysqltest_7@ -GRANT USAGE ON *.* TO 'mysqltest_7'@'' IDENTIFIED BY PASSWORD '*2FB071A056F9BB745219D9C876814231DAF46517' -drop user mysqltest_7@; -show grants for mysqltest_7@; -ERROR 42000: There is no such grant defined for user 'mysqltest_7' on host '' SHOW PRIVILEGES; Privilege Context Comment Alter Tables To alter the table @@ -624,3 +615,12 @@ show grants for root@localhost; Grants for root@localhost GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION set names latin1; +create user mysqltest_7@; +set password for mysqltest_7@ = password('systpass'); +show grants for mysqltest_7@; +Grants for mysqltest_7@ +GRANT USAGE ON *.* TO 'mysqltest_7'@'' IDENTIFIED BY PASSWORD '*2FB071A056F9BB745219D9C876814231DAF46517' +drop user mysqltest_7@; +flush privileges; +show grants for mysqltest_7@; +ERROR 42000: There is no such grant defined for user 'mysqltest_7' on host '' diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index d8deb379cd4..9a8b7a19c59 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -503,11 +503,11 @@ set names latin1; # Bug #15598 Server crashes in specific case during setting new password # - Caused by a user with host '' # -insert into mysql.user (host, user) values ('', 'mysqltest_7'); -flush privileges; +create user mysqltest_7@; set password for mysqltest_7@ = password('systpass'); show grants for mysqltest_7@; drop user mysqltest_7@; +flush privileges; # BUG#16297(flush should be removed when that bug is fixed) --error 1141 show grants for mysqltest_7@; From a3a2f065fb660232d37decd47f965736efc51edd Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 9 Jan 2006 21:44:42 -0800 Subject: [PATCH 103/154] Ajustement after merge --- sql/sql_select.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4619f7134f0..c282a5bd42c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -365,7 +365,8 @@ JOIN::prepare(Item ***rref_pointer_array, if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) - having->split_sum_func2(thd, ref_pointer_array, all_fields, &having); + having->split_sum_func2(thd, ref_pointer_array, all_fields, + &having, TRUE); thd->lex->allow_sum_func= save_allow_sum_func; } if (select_lex->inner_sum_func_list) From d7eb02f439ec97cfec616846a35ebb3000c36ed7 Mon Sep 17 00:00:00 2001 From: "aelkin@mysql.com" <> Date: Tue, 10 Jan 2006 13:44:08 +0200 Subject: [PATCH 104/154] BUG#9483 test was overworked to account reviews finally to leave only REVOKE check. There is a specific rpl_ignore_grant test case for GRANT. --- mysql-test/r/rpl_ignore_revoke.result | 28 +++++++++++++++ mysql-test/t/rpl_ignore_revoke-slave.opt | 1 + mysql-test/t/rpl_ignore_revoke.test | 43 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 mysql-test/r/rpl_ignore_revoke.result create mode 100644 mysql-test/t/rpl_ignore_revoke-slave.opt create mode 100644 mysql-test/t/rpl_ignore_revoke.test diff --git a/mysql-test/r/rpl_ignore_revoke.result b/mysql-test/r/rpl_ignore_revoke.result new file mode 100644 index 00000000000..094b571f4f4 --- /dev/null +++ b/mysql-test/r/rpl_ignore_revoke.result @@ -0,0 +1,28 @@ +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; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; +select_priv +N +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* slave:must be N */; +select_priv +N +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +select select_priv from mysql.user where user='user_foo' /* slave:must be Y */; +select_priv +Y +revoke select on *.* from 'user_foo'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; +select_priv +N +select select_priv from mysql.user where user='user_foo' /* slave:must get Y */; +select_priv +Y +revoke select on *.* FROM 'user_foo'; diff --git a/mysql-test/t/rpl_ignore_revoke-slave.opt b/mysql-test/t/rpl_ignore_revoke-slave.opt new file mode 100644 index 00000000000..e931bfbd37e --- /dev/null +++ b/mysql-test/t/rpl_ignore_revoke-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=mysql.% diff --git a/mysql-test/t/rpl_ignore_revoke.test b/mysql-test/t/rpl_ignore_revoke.test new file mode 100644 index 00000000000..e5b5bafb3c5 --- /dev/null +++ b/mysql-test/t/rpl_ignore_revoke.test @@ -0,0 +1,43 @@ +# test verifies that REVOKE must not be replicated when +# slave server starts with --replicate-wild-ignore-table=mysql.% +# the option is set in rpl_ignore_revoke-slave.opt +# The first part of BUG#9483 for GRANT is checked by +# existed specific rpl_ignore_grant test case (BUG#980) + + +source include/master-slave.inc; + +### CLEAN-UP: create an account and manually duplicate it on the slave + +connection master; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; + +sync_slave_with_master; +#connection slave; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +revoke select on *.* from 'user_foo'@'%'; +select select_priv from mysql.user where user='user_foo' /* slave:must be N */; + + +### TEST + +#connection slave; +grant select on *.* to 'user_foo'@'%' identified by 'user_foopass'; +select select_priv from mysql.user where user='user_foo' /* slave:must be Y */; + +connection master; +revoke select on *.* from 'user_foo'; +select select_priv from mysql.user where user='user_foo' /* master:must be N */; + +sync_slave_with_master; +#connection slave; +select select_priv from mysql.user where user='user_foo' /* slave:must get Y */; + +### CLEAN-UP + +connection slave; +--disable_abort_on_error +revoke select on *.* FROM 'user_foo'; +--enable_abort_on_error From a09473e6525f5443a7dd8fa0458c344e832d430b Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 10 Jan 2006 15:56:30 +0100 Subject: [PATCH 105/154] Fix for crashing mysqltest --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index dbb910c2e3d..c31e8bc693b 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4207,7 +4207,7 @@ static VAR *var_init(VAR *v, const char *name, int name_len, const char *val, val_len = strlen(val) ; val_alloc_len = val_len + 16; /* room to grow */ if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) - + name_len, MYF(MY_WME)))) + + name_len+1, MYF(MY_WME)))) die("Out of memory"); tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; From 16004acce1035dced81526272825a4e27c22e0dc Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 10 Jan 2006 17:57:46 +0300 Subject: [PATCH 106/154] Commenting out testcases which cause type_time.test failure. To be uncommented after fixing bug 15805. --- mysql-test/r/type_time.result | 24 ------------------------ mysql-test/t/type_time.test | 16 ++++++++++------ 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index cb76f699cd9..025cf2a57f1 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -85,27 +85,3 @@ sec_to_time(time_to_sec(t)) 13:00:00 09:00:00 drop table t1; -SELECT CAST(235959.123456 AS TIME); -CAST(235959.123456 AS TIME) -23:59:59.123456 -SELECT CAST(0.235959123456e+6 AS TIME); -CAST(0.235959123456e+6 AS TIME) -23:59:59.123456 -SELECT CAST(235959123456e-6 AS TIME); -CAST(235959123456e-6 AS TIME) -23:59:59.123456 -SELECT CAST(235959.1234567 AS TIME); -CAST(235959.1234567 AS TIME) -23:59:59.123456 -Warnings: -Warning 1292 Truncated incorrect time value: '235959.1234567' -SELECT CAST(0.2359591234567e6 AS TIME); -CAST(0.2359591234567e6 AS TIME) -23:59:59.123456 -Warnings: -Warning 1292 Truncated incorrect time value: '235959.1234567' -SELECT CAST(0.2359591234567e+30 AS TIME); -CAST(0.2359591234567e+30 AS TIME) -NULL -Warnings: -Warning 1292 Truncated incorrect time value: '2.359591234567e+29' diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 9abfe914335..cb7e4f85ad1 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -26,13 +26,17 @@ drop table t1; # long fraction part and/or large exponent part. # # These must return normal result: -SELECT CAST(235959.123456 AS TIME); -SELECT CAST(0.235959123456e+6 AS TIME); -SELECT CAST(235959123456e-6 AS TIME); +# ########################################################## +# To be uncommented after fix BUG #15805 +# ########################################################## +# SELECT CAST(235959.123456 AS TIME); +# SELECT CAST(0.235959123456e+6 AS TIME); +# SELECT CAST(235959123456e-6 AS TIME); # These must cut fraction part and produce warning: -SELECT CAST(235959.1234567 AS TIME); -SELECT CAST(0.2359591234567e6 AS TIME); +# SELECT CAST(235959.1234567 AS TIME); +# SELECT CAST(0.2359591234567e6 AS TIME); # This must return NULL and produce warning: -SELECT CAST(0.2359591234567e+30 AS TIME); +# SELECT CAST(0.2359591234567e+30 AS TIME); +# ########################################################## # End of 4.1 tests From df801decef746068fffeecbc15c47384a07aa553 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Tue, 10 Jan 2006 18:56:23 +0200 Subject: [PATCH 107/154] Fixed refresh_status function. --- sql/sql_class.cc | 7 ++++++- sql/sql_parse.cc | 16 +++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ed2089546da..ca86c077a3a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -445,7 +445,12 @@ THD::~THD() /* - Add to one status variable another status variable + Add all status variables to another status variable array + + SYNOPSIS + add_to_status() + to_var add to this array + from_var from this array NOTES This function assumes that all variables are long/ulong. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9cdb288c045..e322fd466d3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6538,7 +6538,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (options & REFRESH_HOSTS) hostname_cache_refresh(); if (thd && (options & REFRESH_STATUS)) - refresh_status(); + refresh_status(thd); if (options & REFRESH_THREADS) flush_thread_cache(); #ifdef HAVE_REPLICATION @@ -6624,20 +6624,18 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query) /* Clear most status variables */ -static void refresh_status(void) +static void refresh_status(THD *thd) { pthread_mutex_lock(&LOCK_status); + + /* We must update the global status before cleaning up the thread */ + add_to_status(&global_status_var, &thd->status_var); + bzero((char*) &thd->status_var, sizeof(thd->status_var)); + for (struct show_var_st *ptr=status_vars; ptr->name; ptr++) { if (ptr->type == SHOW_LONG) *(ulong*) ptr->value= 0; - else if (ptr->type == SHOW_LONG_STATUS) - { - THD *thd= current_thd; - /* We must update the global status before cleaning up the thread */ - add_to_status(&global_status_var, &thd->status_var); - bzero((char*) &thd->status_var, sizeof(thd->status_var)); - } } /* Reset the counters of all key caches (default and named). */ process_key_caches(reset_key_cache_counters); From 2970e71ce80ca698f1728d4d9d1bb5a445a4f523 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Tue, 10 Jan 2006 19:13:12 +0200 Subject: [PATCH 108/154] Re-run fix-fields on condition if table was reopened in HANDLERREAD --- sql/sql_base.cc | 20 ++++++++++++++++---- sql/sql_handler.cc | 11 ++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c8443948a4a..ea013bb4e1e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1012,10 +1012,20 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name) /**************************************************************************** -** Reopen an table because the definition has changed. The date file for the -** table is already closed. -** Returns 0 if ok. -** If table can't be reopened, the entry is unchanged. + Reopen an table because the definition has changed. The date file for the + table is already closed. + + SYNOPSIS + reopen_table() + table Table to be opened + locked 1 if we have already a lock on LOCK_open + + NOTES + table->query_id will be 0 if table was reopened + + RETURN + 0 ok + 1 error ('table' is unchanged if table couldn't be reopened) ****************************************************************************/ bool reopen_table(TABLE *table,bool locked) @@ -1085,8 +1095,10 @@ bool reopen_table(TABLE *table,bool locked) (*field)->table_name=table->table_name; } for (key=0 ; key < table->keys ; key++) + { for (part=0 ; part < table->key_info[key].usable_key_parts ; part++) table->key_info[key].key_part[part].field->table= table; + } VOID(pthread_cond_broadcast(&COND_refresh)); error=0; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 765a057f740..1c5381a9fa0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -437,9 +437,14 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already - if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) - goto err0; + if (cond) + { + if (table->query_id != thd->query_id) + cond->cleanup(); // File was reopened + if ((!cond->fixed && + cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)) + goto err0; + } if (keyname) { From d9d6dfea3a48f9768dcee1ec088cd1ed86db94d4 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Tue, 10 Jan 2006 19:19:56 +0200 Subject: [PATCH 109/154] Changed function prototype. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e322fd466d3..58594cce293 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -73,7 +73,7 @@ static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_multi_update_lock(THD *thd); static void remove_escape(char *name); -static void refresh_status(void); +static void refresh_status(THD *thd); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); From cdf3e4c02e12d4d2de697e7237a8d1fa72a9b0ac Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 10 Jan 2006 21:03:02 +0300 Subject: [PATCH 110/154] Post-merge changes --- mysql-test/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index a209088f202..46f15983dc3 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -12,4 +12,3 @@ sp-goto : GOTO is currently is disabled - will be fixed in the future subselect : Bug#15706 -type_time : Bug#15805 From b04b851ef9540e14641db9e5ee6c5a572b8119fb Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Wed, 11 Jan 2006 02:07:40 +0300 Subject: [PATCH 111/154] Fix for BUG#15110: mysqldump --triggers: does not include DEFINER clause There are two main idea of this fix: - introduce a common function for server and client to split user value (@) into user name and host name parts; - dump DEFINER clause in correct format in mysqldump. --- .bzrignore | 3 ++ client/Makefile.am | 7 +++-- client/mysqldump.c | 35 +++++++++++++++++++-- include/Makefile.am | 3 +- include/my_user.h | 35 +++++++++++++++++++++ include/mysql_com.h | 8 +++++ libmysqld/Makefile.am | 2 +- mysql-test/r/mysqldump.result | 12 ++++---- sql-common/Makefile.am | 2 +- sql-common/my_user.c | 57 +++++++++++++++++++++++++++++++++++ sql/Makefile.am | 4 ++- sql/sp.cc | 4 +-- sql/sp_head.cc | 30 ++++++++---------- sql/sql_acl.cc | 4 +-- sql/sql_parse.cc | 4 +-- sql/sql_show.cc | 6 ++-- sql/sql_trigger.cc | 2 +- 17 files changed, 175 insertions(+), 43 deletions(-) create mode 100644 include/my_user.h create mode 100644 sql-common/my_user.c diff --git a/.bzrignore b/.bzrignore index 6e1da35a08f..109f9e536a9 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1269,3 +1269,6 @@ vio/viotest.cpp zlib/*.ds? zlib/*.vcproj libmysqld/ha_blackhole.cc +client/my_user.c +libmysqld/my_user.c +sql/my_user.c diff --git a/client/Makefile.am b/client/Makefile.am index 804f194085f..2c513d3d7c7 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -46,7 +46,7 @@ mysqltestmanager_pwgen_SOURCES = mysqlmanager-pwgen.c mysqltestmanagerc_SOURCES= mysqlmanagerc.c $(yassl_dummy_link_fix) mysqlcheck_SOURCES= mysqlcheck.c $(yassl_dummy_link_fix) mysqlshow_SOURCES= mysqlshow.c $(yassl_dummy_link_fix) -mysqldump_SOURCES= mysqldump.c $(yassl_dummy_link_fix) +mysqldump_SOURCES= mysqldump.c my_user.c $(yassl_dummy_link_fix) mysqlimport_SOURCES= mysqlimport.c $(yassl_dummy_link_fix) sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc strings_src=decimal.c @@ -62,7 +62,10 @@ link_sources: for f in $(strings_src) ; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ - done; + done; \ + rm -f $(srcdir)/my_user.c; \ + @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c; + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/mysqldump.c b/client/mysqldump.c index 454fc0df84e..b24d67ec302 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -1840,9 +1841,37 @@ static void dump_triggers_for_table (char *table, char *db) DELIMITER ;;\n"); while ((row= mysql_fetch_row(result))) { - fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n\ -/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n\n", - row[6], /* sql_mode */ + fprintf(sql_file, + "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n" + "/*!50003 CREATE */ ", + row[6] /* sql_mode */); + + if (mysql_num_fields(result) > 7) + { + /* + mysqldump can be run against the server, that does not support definer + in triggers (there is no DEFINER column in SHOW TRIGGERS output). So, + we should check if we have this column before accessing it. + */ + + uint user_name_len; + char user_name_str[USERNAME_LENGTH + 1]; + char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; + uint host_name_len; + char host_name_str[HOSTNAME_LENGTH + 1]; + char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; + + parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len, + host_name_str, &host_name_len); + + fprintf(sql_file, + "/*!50017 DEFINER=%s@%s */ ", + quote_name(user_name_str, quoted_user_name_str, FALSE), + quote_name(host_name_str, quoted_host_name_str, FALSE)); + } + + fprintf(sql_file, + "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n\n", quote_name(row[0], name_buff, 0), /* Trigger */ row[4], /* Timing */ row[1], /* Event */ diff --git a/include/Makefile.am b/include/Makefile.am index 12b8c301b8d..07c32e3127b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -30,7 +30,8 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \ my_nosys.h my_alarm.h queues.h rijndael.h sha1.h \ my_aes.h my_tree.h hash.h thr_alarm.h \ thr_lock.h t_ctype.h violite.h md5.h base64.h \ - mysql_version.h.in my_handler.h my_time.h decimal.h + mysql_version.h.in my_handler.h my_time.h decimal.h \ + my_user.h # mysql_version.h are generated CLEANFILES = mysql_version.h my_config.h readline openssl diff --git a/include/my_user.h b/include/my_user.h new file mode 100644 index 00000000000..2bd4208a34c --- /dev/null +++ b/include/my_user.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + This is a header for libraries containing functions used in both server and + only some of clients (but not in libmysql)... +*/ + +#ifndef _my_user_h_ +#define _my_user_h_ + +#include + +C_MODE_START + +void parse_user(const char *user_id_str, uint user_id_len, + char *user_name_str, uint *user_name_len, + char *host_name_str, uint *host_name_len); + +C_MODE_END + +#endif /* _my_user_h_ */ diff --git a/include/mysql_com.h b/include/mysql_com.h index 1e595cdbba3..ec1c133799f 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -27,6 +27,14 @@ #define SERVER_VERSION_LENGTH 60 #define SQLSTATE_LENGTH 5 +/* + USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain + username and hostname parts of the user identifier with trailing zero in + MySQL standard format: + user_name_part@host_name_part\0 +*/ +#define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2 + #define LOCAL_HOST "localhost" #define LOCAL_HOST_NAMEDPIPE "." diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index f07bbacba02..5ec9cdfe5bf 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -63,7 +63,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \ - ha_blackhole.cc ha_archive.cc + ha_blackhole.cc ha_archive.cc my_user.c libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources) libmysqld_a_SOURCES= diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 62d2b46e617..4e2564c69da 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1986,7 +1986,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="" */;; -/*!50003 CREATE TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW begin if new.a > 10 then set new.a := 10; @@ -1995,12 +1995,12 @@ end if; end */;; /*!50003 SET SESSION SQL_MODE="" */;; -/*!50003 CREATE TRIGGER `trg2` BEFORE UPDATE ON `t1` FOR EACH ROW begin +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg2` BEFORE UPDATE ON `t1` FOR EACH ROW begin if old.a % 2 = 0 then set new.b := 12; end if; end */;; /*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; -/*!50003 CREATE TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW begin if new.a = -1 then set @fired:= "Yes"; @@ -2023,7 +2023,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; -/*!50003 CREATE TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW begin if new.a > 10 then set @fired:= "No"; @@ -2376,7 +2376,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="" */;; -/*!50003 CREATE TRIGGER `test trig` BEFORE INSERT ON `t1 test` FOR EACH ROW BEGIN +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `test trig` BEFORE INSERT ON `t1 test` FOR EACH ROW BEGIN INSERT INTO `t2 test` SET a2 = NEW.a1; END */;; DELIMITER ; @@ -2532,7 +2532,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="IGNORE_SPACE" */;; -/*!50003 CREATE TRIGGER `tr1` BEFORE INSERT ON `t1` FOR EACH ROW BEGIN +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `tr1` BEFORE INSERT ON `t1` FOR EACH ROW BEGIN SET new.a = 0; END */;; diff --git a/sql-common/Makefile.am b/sql-common/Makefile.am index 6bd42d70e4f..d71523a741c 100644 --- a/sql-common/Makefile.am +++ b/sql-common/Makefile.am @@ -15,7 +15,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Process this file with automake to create Makefile.in -EXTRA_DIST = client.c pack.c my_time.c +EXTRA_DIST = client.c pack.c my_time.c my_user.c # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/sql-common/my_user.c b/sql-common/my_user.c new file mode 100644 index 00000000000..c39f08e520f --- /dev/null +++ b/sql-common/my_user.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include + + +/* + Parse user value to user name and host name parts. + + SYNOPSIS + user_id_str [IN] User value string (the source). + user_id_len [IN] Length of the user value. + user_name_str [OUT] Buffer to store user name part. + Must be not less than USERNAME_LENGTH + 1. + user_name_len [OUT] A place to store length of the user name part. + host_name_str [OUT] Buffer to store host name part. + Must be not less than HOSTNAME_LENGTH + 1. + host_name_len [OUT] A place to store length of the host name part. +*/ + +void parse_user(const char *user_id_str, uint user_id_len, + char *user_name_str, uint *user_name_len, + char *host_name_str, uint *host_name_len) +{ + char *p= strrchr(user_id_str, '@'); + + if (!p) + { + *user_name_len= 0; + *host_name_len= 0; + } + else + { + *user_name_len= p - user_id_str; + *host_name_len= user_id_len - *user_name_len - 1; + + memcpy(user_name_str, user_id_str, *user_name_len); + memcpy(host_name_str, p + 1, *host_name_len); + } + + user_name_str[*user_name_len]= 0; + host_name_str[*host_name_len]= 0; +} diff --git a/sql/Makefile.am b/sql/Makefile.am index 1437751bf2f..d701c18a4d7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -97,7 +97,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ stacktrace.c repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ gstream.cc spatial.cc sql_help.cc sql_cursor.cc \ - tztime.cc my_time.c my_decimal.cc\ + tztime.cc my_time.c my_user.c my_decimal.cc\ sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \ sp_cache.cc parse_file.cc sql_trigger.cc \ examples/ha_example.cc ha_archive.cc \ @@ -133,6 +133,8 @@ link_sources: mysql_tzinfo_to_sql.cc @LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c rm -f my_time.c @LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c + rm -f my_user.c + @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES) $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $< diff --git a/sql/sp.cc b/sql/sp.cc index a9b1a462d5f..37a9c02124e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -480,7 +480,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) { int ret; TABLE *table; - char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + char definer[USER_HOST_BUFF_SIZE]; char olddb[128]; bool dbchanged; DBUG_ENTER("db_create_routine"); @@ -940,7 +940,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, ulong level; sp_head *new_sp; const char *returns= ""; - char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + char definer[USER_HOST_BUFF_SIZE]; String retstr(64); DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 12f9260e7b1..d3045467f91 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -31,6 +31,8 @@ #define SP_STMT_PRINT_MAXLEN 40 +#include + Item_result sp_map_result_type(enum enum_field_types type) { @@ -1752,29 +1754,21 @@ sp_head::set_info(longlong created, longlong modified, void - sp_head::set_definer(const char *definer, uint definerlen) { - const char *p= strrchr(definer, '@'); + uint user_name_len; + char user_name_str[USERNAME_LENGTH + 1]; + uint host_name_len; + char host_name_str[HOSTNAME_LENGTH + 1]; - if (!p) - { - m_definer_user.str= (char*) ""; - m_definer_user.length= 0; - m_definer_host.str= (char*) ""; - m_definer_host.length= 0; - } - else - { - const uint user_name_len= p - definer; - const uint host_name_len= definerlen - user_name_len - 1; + parse_user(definer, definerlen, user_name_str, &user_name_len, + host_name_str, &host_name_len); - m_definer_user.str= strmake_root(mem_root, definer, user_name_len); - m_definer_user.length= user_name_len; + m_definer_user.str= strmake_root(mem_root, user_name_str, user_name_len); + m_definer_user.length= user_name_len; - m_definer_host.str= strmake_root(mem_root, p + 1, host_name_len); - m_definer_host.length= host_name_len; - } + m_definer_host.str= strmake_root(mem_root, host_name_str, host_name_len); + m_definer_host.length= host_name_len; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 7bb84895da5..130674b47f9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2490,7 +2490,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ulong rights, ulong col_rights, bool revoke_grant) { - char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + char grantor[USER_HOST_BUFF_SIZE]; int old_row_exists = 1; int error=0; ulong store_table_rights, store_col_rights; @@ -2608,7 +2608,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, const char *db, const char *routine_name, bool is_proc, ulong rights, bool revoke_grant) { - char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + char grantor[USER_HOST_BUFF_SIZE]; int old_row_exists= 1; int error=0; ulong store_proc_rights; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9cdb288c045..76d24ede8f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -214,7 +214,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, { int return_val= 0; uint temp_len, user_len; - char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; + char temp_user[USER_HOST_BUFF_SIZE]; struct user_conn *uc; DBUG_ASSERT(user != 0); @@ -743,7 +743,7 @@ static void reset_mqh(LEX_USER *lu, bool get_them= 0) { USER_CONN *uc; uint temp_len=lu->user.length+lu->host.length+2; - char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; + char temp_user[USER_HOST_BUFF_SIZE]; memcpy(temp_user,lu->user.str,lu->user.length); memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 089314078a6..d15df686e40 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2887,7 +2887,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) int res= 0; TABLE *table= tables->table; bool full_access; - char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + char definer[USER_HOST_BUFF_SIZE]; Open_tables_state open_tables_state_backup; DBUG_ENTER("fill_schema_proc"); @@ -3029,7 +3029,7 @@ static int get_schema_views_record(THD *thd, struct st_table_list *tables, { CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_views_record"); - char definer[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + char definer[USER_HOST_BUFF_SIZE]; uint definer_len; if (tables->view) @@ -3213,7 +3213,7 @@ static int get_schema_triggers_record(THD *thd, struct st_table_list *tables, LEX_STRING trigger_name; LEX_STRING trigger_stmt; ulong sql_mode; - char definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + char definer_holder[USER_HOST_BUFF_SIZE]; LEX_STRING definer_buffer; definer_buffer.str= definer_holder; if (triggers->get_trigger_info(thd, (enum trg_event_type) event, diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index bbc32950c2d..c70914edc31 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -317,7 +317,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, LEX_STRING dir, file, trigname_file; LEX_STRING *trg_def, *name; ulonglong *trg_sql_mode; - char trg_definer_holder[HOSTNAME_LENGTH + USERNAME_LENGTH + 2]; + char trg_definer_holder[USER_HOST_BUFF_SIZE]; LEX_STRING *trg_definer; Item_trigger_field *trg_field; struct st_trigname trigname; From d42d3994641a07e8cfb1dcaed3f051f86c8aa37a Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 11 Jan 2006 00:24:57 +0100 Subject: [PATCH 112/154] Disable code for "let" to assign each column from query to it's own variable --- client/mysqltest.c | 3 ++- mysql-test/r/mysqltest.result | 19 ------------------- mysql-test/t/mysqltest.test | 4 ++-- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index c31e8bc693b..a073df979f2 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1205,6 +1205,7 @@ int var_query_set(VAR* var, const char *query, const char** query_end) { if (row[0]) { +#ifdef NOT_YET /* Add to _ */ uint j; char var_col_name[MAX_VAR_NAME]; @@ -1218,7 +1219,7 @@ int var_query_set(VAR* var, const char *query, const char** query_end) } var_set(var_col_name, var_col_name + length, row[i], row[i] + lengths[i]); - +#endif /* Add column to tab separated string */ dynstr_append_mem(&result, row[i], lengths[i]); } diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 2657fb8a409..d0db0269a98 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -222,25 +222,6 @@ mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Variable name in =hi does not start with '$' mysqltest: At line 1: Missing assignment operator in let -var1 -hi 1 hi there -hi -1 -hi there -var2 -2 - - -var2 again -2 - -2 - -var3 two columns with same name -1 2 3 -2 -2 -3 mysqltest: At line 1: Missing file name in source mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index ae28a66c685..ee309fbd7c9 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -543,7 +543,7 @@ echo $novar1; # Test to assign let from query # let $=``; # ---------------------------------------------------------------------------- - +--disable_parsing echo var1; let $var1= `select "hi" as "Col", 1 as "Column1", "hi there" as Col3`; echo $var1; @@ -574,7 +574,7 @@ echo $var3_var3; #echo failing query in let; #--error 1 #--exec echo "let $var2= `failing query;`" | $MYSQL_TEST 2>&1 - +--enable_parsing # ---------------------------------------------------------------------------- # Test source command # ---------------------------------------------------------------------------- From 2f48e4f1dc09868912b42b07edfe59753451363d Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 11 Jan 2006 11:06:26 +0100 Subject: [PATCH 113/154] Fix problem with strange printout of line numbers, detected on aix52, but existing on all platforms, just being masked by init of vars to zero. --- client/mysqltest.c | 31 ++++++++++++++++--------------- mysql-test/r/mysqltest.result | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index a073df979f2..31fd4992650 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -165,7 +165,6 @@ static my_bool sp_protocol= 0, sp_protocol_enabled= 0; static my_bool view_protocol= 0, view_protocol_enabled= 0; static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0; static int parsing_disabled= 0; -static uint start_lineno, *lineno; const char *manager_user="root",*manager_host=0; char *manager_pass=0; int manager_port=MYSQL_MANAGER_PORT; @@ -180,13 +179,14 @@ typedef struct { FILE* file; const char *file_name; + uint lineno; /* Current line in file */ } test_file; static test_file file_stack[MAX_INCLUDE_DEPTH]; static test_file* cur_file; static test_file* file_stack_end; +uint start_lineno; /* Start line of query */ -static uint lineno_stack[MAX_INCLUDE_DEPTH]; static char TMPDIR[FN_REFLEN]; static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; static uint delimiter_length= 1; @@ -662,7 +662,7 @@ static void verbose_msg(const char *fmt, ...) va_start(args, fmt); fprintf(stderr, "mysqltest: "); - if (start_lineno > 0) + if (start_lineno != 0) fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); @@ -900,7 +900,7 @@ int open_file(const char *name) die("Could not open file %s", buff); } cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); - *++lineno=1; + cur_file->lineno=1; DBUG_RETURN(0); } @@ -2497,7 +2497,7 @@ int read_line(char *buf, int size) DBUG_ENTER("read_line"); LINT_INIT(quote); - start_lineno= *lineno; + start_lineno= cur_file->lineno; for (; p < buf_end ;) { no_save= 0; @@ -2512,28 +2512,25 @@ int read_line(char *buf, int size) } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; - lineno--; - start_lineno= *lineno; if (cur_file == file_stack) { /* We're back at the first file, check if all { have matching } */ if (cur_block != block_stack) - { - start_lineno= *(lineno+1); die("Missing end of block"); - } + DBUG_PRINT("info", ("end of file")); DBUG_RETURN(1); } cur_file--; + start_lineno= cur_file->lineno; continue; } /* Line counting is independent of state */ if (c == '\n') - (*lineno)++; + cur_file->lineno++; switch(state) { case R_NORMAL: @@ -2562,14 +2559,15 @@ int read_line(char *buf, int size) break; case R_LINE_START: /* Only accept start of comment if this is the first line in query */ - if ((*lineno == start_lineno) && (c == '#' || c == '-' || parsing_disabled)) + if ((cur_file->lineno == start_lineno) && + (c == '#' || c == '-' || parsing_disabled)) { state = R_COMMENT; } else if (my_isspace(charset_info, c)) { if (c == '\n') - start_lineno= *lineno; /* Query hasn't started yet */ + start_lineno= cur_file->lineno; /* Query hasn't started yet */ no_save= 1; } else if (c == '}') @@ -2895,6 +2893,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) die("Could not open %s: errno = %d", buff, errno); cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); + cur_file->lineno= 1; break; } case 'm': @@ -4291,7 +4290,7 @@ int main(int argc, char **argv) memset(&master_pos, 0, sizeof(master_pos)); file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; cur_file= file_stack; - lineno = lineno_stack; + my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, INIT_Q_LINES); @@ -4313,8 +4312,8 @@ int main(int argc, char **argv) { cur_file->file= stdin; cur_file->file_name= my_strdup("", MYF(MY_WME)); + cur_file->lineno= 1; } - *lineno=1; #ifndef EMBEDDED_LIBRARY if (manager_host) init_manager(); @@ -4609,6 +4608,8 @@ int main(int argc, char **argv) parser.current_line += current_line_inc; } + start_lineno= 0; + /* The whole test has been executed _sucessfully_ Time to compare result or save it to record file diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index d0db0269a98..067054510c2 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -149,7 +149,7 @@ hello mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: Missing delimiter -mysqltest: End of line junk detected: "sleep 7 +mysqltest: At line 1: End of line junk detected: "sleep 7 # Another comment " mysqltest: At line 1: Extra delimiter ";" found From f4ad824df979d3ac2298b2f394b9e1555c48ceda Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 11 Jan 2006 11:07:17 +0100 Subject: [PATCH 114/154] Remove obsolete comment --- client/mysqltest.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 31fd4992650..552d8c4ee29 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2669,7 +2669,6 @@ int read_line(char *buf, int size) The advantage with this approach is to be able to execute commands terminated by new line '\n' regardless how many "delimiter" it contain. - If query starts with @ this will specify a file to .... */ static char read_query_buf[MAX_QUERY]; From f60f7576899f89dbcb44ab64f36528f859bda1d9 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 11 Jan 2006 11:10:58 +0100 Subject: [PATCH 115/154] Add comments that groups and describes the inits --- client/mysqltest.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 552d8c4ee29..6a2a7b072de 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4280,25 +4280,30 @@ int main(int argc, char **argv) save_file[0]=0; TMPDIR[0]=0; + + /* Init cons */ memset(cons, 0, sizeof(cons)); cons_end = cons + MAX_CONS; next_con = cons + 1; cur_con = cons; + /* Init file stack */ memset(file_stack, 0, sizeof(file_stack)); - memset(&master_pos, 0, sizeof(master_pos)); file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; cur_file= file_stack; - my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, - INIT_Q_LINES); - + /* Init block stack */ memset(block_stack, 0, sizeof(block_stack)); block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1; cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= cmd_none; + my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, + INIT_Q_LINES); + + memset(&master_pos, 0, sizeof(master_pos)); + init_dynamic_string(&ds_res, "", 0, 65536); parse_args(argc, argv); From 9105d06dd6503f3a12952c2a4272024915c5e07e Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Wed, 11 Jan 2006 17:31:52 +0300 Subject: [PATCH 116/154] A fix for Bug#13944 "libmysqlclient exporting sha1_result function": rename sha1_* to mysql_sha1_* --- include/sha1.h | 6 +++--- mysys/sha1.c | 16 ++++++++-------- sql/item_strfunc.cc | 8 +++++--- sql/password.c | 46 ++++++++++++++++++++++----------------------- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/include/sha1.h b/include/sha1.h index 1c345469d3c..e67acbf96b8 100644 --- a/include/sha1.h +++ b/include/sha1.h @@ -60,8 +60,8 @@ typedef struct SHA1_CONTEXT C_MODE_START -int sha1_reset( SHA1_CONTEXT* ); -int sha1_input( SHA1_CONTEXT*, const uint8 *, unsigned int ); -int sha1_result( SHA1_CONTEXT* , uint8 Message_Digest[SHA1_HASH_SIZE] ); +int mysql_sha1_reset(SHA1_CONTEXT*); +int mysql_sha1_input(SHA1_CONTEXT*, const uint8 *, unsigned int); +int mysql_sha1_result(SHA1_CONTEXT* , uint8 Message_Digest[SHA1_HASH_SIZE]); C_MODE_END diff --git a/mysys/sha1.c b/mysys/sha1.c index d93b4571baf..110d24f8bfc 100644 --- a/mysys/sha1.c +++ b/mysys/sha1.c @@ -69,7 +69,7 @@ static void SHA1ProcessMessageBlock(SHA1_CONTEXT*); Initialize SHA1Context SYNOPSIS - sha1_reset() + mysql_sha1_reset() context [in/out] The context to reset. DESCRIPTION @@ -92,7 +92,7 @@ const uint32 sha_const_key[5]= }; -int sha1_reset(SHA1_CONTEXT *context) +int mysql_sha1_reset(SHA1_CONTEXT *context) { #ifndef DBUG_OFF if (!context) @@ -119,7 +119,7 @@ int sha1_reset(SHA1_CONTEXT *context) Return the 160-bit message digest into the array provided by the caller SYNOPSIS - sha1_result() + mysql_sha1_result() context [in/out] The context to use to calculate the SHA-1 hash. Message_Digest: [out] Where the digest is returned. @@ -132,8 +132,8 @@ int sha1_reset(SHA1_CONTEXT *context) != SHA_SUCCESS sha Error Code. */ -int sha1_result(SHA1_CONTEXT *context, - uint8 Message_Digest[SHA1_HASH_SIZE]) +int mysql_sha1_result(SHA1_CONTEXT *context, + uint8 Message_Digest[SHA1_HASH_SIZE]) { int i; @@ -165,7 +165,7 @@ int sha1_result(SHA1_CONTEXT *context, Accepts an array of octets as the next portion of the message. SYNOPSIS - sha1_input() + mysql_sha1_input() context [in/out] The SHA context to update message_array An array of characters representing the next portion of the message. @@ -176,8 +176,8 @@ int sha1_result(SHA1_CONTEXT *context, != SHA_SUCCESS sha Error Code. */ -int sha1_input(SHA1_CONTEXT *context, const uint8 *message_array, - unsigned length) +int mysql_sha1_input(SHA1_CONTEXT *context, const uint8 *message_array, + unsigned length) { if (!length) return SHA_SUCCESS; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 60cb3348590..04765e18191 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -131,11 +131,13 @@ String *Item_func_sha::val_str(String *str) SHA1_CONTEXT context; /* Context used to generate SHA1 hash */ /* Temporary buffer to store 160bit digest */ uint8 digest[SHA1_HASH_SIZE]; - sha1_reset(&context); /* We do not have to check for error here */ + mysql_sha1_reset(&context); /* We do not have to check for error here */ /* No need to check error as the only case would be too long message */ - sha1_input(&context,(const unsigned char *) sptr->ptr(), sptr->length()); + mysql_sha1_input(&context, + (const unsigned char *) sptr->ptr(), sptr->length()); /* Ensure that memory is free and we got result */ - if (!( str->alloc(SHA1_HASH_SIZE*2) || (sha1_result(&context,digest)))) + if (!( str->alloc(SHA1_HASH_SIZE*2) || + (mysql_sha1_result(&context,digest)))) { sprintf((char *) str->ptr(), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\ diff --git a/sql/password.c b/sql/password.c index 04b3a46bd48..94b9dc440be 100644 --- a/sql/password.c +++ b/sql/password.c @@ -392,15 +392,15 @@ make_scrambled_password(char *to, const char *password) SHA1_CONTEXT sha1_context; uint8 hash_stage2[SHA1_HASH_SIZE]; - sha1_reset(&sha1_context); + mysql_sha1_reset(&sha1_context); /* stage 1: hash password */ - sha1_input(&sha1_context, (uint8 *) password, strlen(password)); - sha1_result(&sha1_context, (uint8 *) to); + mysql_sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + mysql_sha1_result(&sha1_context, (uint8 *) to); /* stage 2: hash stage1 output */ - sha1_reset(&sha1_context); - sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); + mysql_sha1_reset(&sha1_context); + mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); /* separate buffer is used to pass 'to' in octet2hex */ - sha1_result(&sha1_context, hash_stage2); + mysql_sha1_result(&sha1_context, hash_stage2); /* convert hash_stage2 to hex string */ *to++= PVERSION41_CHAR; octet2hex(to, hash_stage2, SHA1_HASH_SIZE); @@ -431,20 +431,20 @@ scramble(char *to, const char *message, const char *password) uint8 hash_stage1[SHA1_HASH_SIZE]; uint8 hash_stage2[SHA1_HASH_SIZE]; - sha1_reset(&sha1_context); + mysql_sha1_reset(&sha1_context); /* stage 1: hash password */ - sha1_input(&sha1_context, (uint8 *) password, strlen(password)); - sha1_result(&sha1_context, hash_stage1); + mysql_sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + mysql_sha1_result(&sha1_context, hash_stage1); /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */ - sha1_reset(&sha1_context); - sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE); - sha1_result(&sha1_context, hash_stage2); + mysql_sha1_reset(&sha1_context); + mysql_sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE); + mysql_sha1_result(&sha1_context, hash_stage2); /* create crypt string as sha1(message, hash_stage2) */; - sha1_reset(&sha1_context); - sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); - sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + mysql_sha1_reset(&sha1_context); + mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); /* xor allows 'from' and 'to' overlap: lets take advantage of it */ - sha1_result(&sha1_context, (uint8 *) to); + mysql_sha1_result(&sha1_context, (uint8 *) to); my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH); } @@ -477,17 +477,17 @@ check_scramble(const char *scramble, const char *message, uint8 buf[SHA1_HASH_SIZE]; uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; - sha1_reset(&sha1_context); + mysql_sha1_reset(&sha1_context); /* create key to encrypt scramble */ - sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); - sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); - sha1_result(&sha1_context, buf); + mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + mysql_sha1_result(&sha1_context, buf); /* encrypt scramble */ my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH); /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ - sha1_reset(&sha1_context); - sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); - sha1_result(&sha1_context, hash_stage2_reassured); + mysql_sha1_reset(&sha1_context); + mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); + mysql_sha1_result(&sha1_context, hash_stage2_reassured); return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE); } From 605f62fce80ed89c2720f697ba17f381ec28c91a Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 11 Jan 2006 22:49:43 +0300 Subject: [PATCH 117/154] Fixed bug #15633: Evaluation of Item_equal for non-const table caused wrong select result Item equal objects are employed only at the optimize phase. Usually they are not supposed to be evaluated. Yet in some cases we call the method val_int() for them. Here we have to take care of restricting the predicate such an object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik. Added a check for field's table being const in Item_equal::val_int(). If the field's table is not const val_int() just skips that field when evaluating Item_equal. --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/select.result | 13 +++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/item_cmpfunc.cc | 11 ++++++++--- sql/item_cmpfunc.h | 5 +++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 2b0176179ed..cfa4cc0ef68 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -865,6 +865,7 @@ select 1, min(a) from t1m where 1=99; 1 NULL select 1, min(1) from t1m where a=99; 1 min(1) +1 NULL select 1, min(1) from t1m where 1=99; 1 min(1) 1 NULL @@ -876,6 +877,7 @@ select 1, max(a) from t1m where 1=99; 1 NULL select 1, max(1) from t1m where a=99; 1 max(1) +1 NULL select 1, max(1) from t1m where 1=99; 1 max(1) 1 NULL diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 598ea2b10d1..198493d0a02 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3337,3 +3337,16 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index 1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 DROP TABLE t1,t2,t3; +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +f3 +NULL +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +f2 +1 +drop table t1,t2,t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a73d08f5f18..595362dbb65 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2805,3 +2805,17 @@ EXPLAIN SELECT t2.key_a,foo WHERE t2.key_a=2 and key_b=5; DROP TABLE t1,t2,t3; + +# +# Bug #15633 Evaluation of Item_equal for non-const table caused wrong +# select result +# +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +drop table t1,t2,t3; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 15614a32c39..306277aa438 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3765,6 +3765,7 @@ void Item_equal::update_used_tables() longlong Item_equal::val_int() { + Item_field *item_field; if (cond_false) return 0; List_iterator_fast it(fields); @@ -3772,10 +3773,14 @@ longlong Item_equal::val_int() if ((null_value= item->null_value)) return 0; eval_item->store_value(item); - while ((item= it++)) + while ((item_field= it++)) { - if ((null_value= item->null_value) || eval_item->cmp(item)) - return 0; + /* Skip fields of non-const tables. They haven't been read yet */ + if (item_field->field->table->const_table) + { + if ((null_value= item_field->null_value) || eval_item->cmp(item_field)) + return 0; + } } return 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index bfd32223d4c..89d117ee4ec 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1150,6 +1150,11 @@ public: are deleted in the end of execution. All changes made to these objects need not be registered in the list of changes of the parse tree and do not harm PS/SP re-execution. + + Item equal objects are employed only at the optimize phase. Usually they are + not supposed to be evaluated. Yet in some cases we call the method val_int() + for them. We have to take care of restricting the predicate such an + object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik. */ class Item_equal: public Item_bool_func From 3e23d458f931362a4d787fa8086dff38073870a8 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 11 Jan 2006 23:16:21 +0300 Subject: [PATCH 118/154] Fixed bug #15347: Wrong result of subselect when records cache and set functions are involved. When subselect is a join with set functions and no record have been found in it, end_send_group() sets null_row for all tables in order aggregate functions to calculate their values correctly. Normally this null_row flag is cleared for each table in sub_select(), but flush_cached_records() doesn't do so. Due to this all fields from the table processed by flush_cached_records() are always evaluated as nulls and whole select produces wrong result. flush_cached_records() now clears null_row flag at the very beginning. --- mysql-test/r/select.result | 11 +++++++++++ mysql-test/t/select.test | 13 +++++++++++++ sql/sql_select.cc | 1 + 3 files changed, 25 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 598ea2b10d1..b9b0c1ee9e8 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3337,3 +3337,14 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index 1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 DROP TABLE t1,t2,t3; +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +f1 count +1 0 +2 3 +drop table t1,t2,t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a73d08f5f18..6044982d57c 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2805,3 +2805,16 @@ EXPLAIN SELECT t2.key_a,foo WHERE t2.key_a=2 and key_b=5; DROP TABLE t1,t2,t3; + +# +# Bug#15347 Wrong result of subselect when records cache and set functions +# are involved +# +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +drop table t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8538372d607..4573598cd29 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9853,6 +9853,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) int error; READ_RECORD *info; + join_tab->table->null_row= 0; if (!join_tab->cache.records) return NESTED_LOOP_OK; /* Nothing to do */ if (skip_last) From 41ef34356c74c280c1d615e773ce32843aa9966b Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Wed, 11 Jan 2006 23:39:09 +0300 Subject: [PATCH 119/154] Fixed bug #15538: unchecked table absence caused server crash. Absence of table in left part of LEFT/RIGHT join wasn't checked before name resolution which resulted in NULL dereferencing and server crash. Modified rules: "table_ref LEFT opt_outer JOIN_SYM table_ref" and "table_ref RIGHT opt_outer JOIN_SYM table_ref" NULL check is moved before push_new_name_resolution_context() --- mysql-test/r/select.result | 2 ++ mysql-test/t/select.test | 6 ++++++ sql/sql_yacc.yy | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index e2c4609d902..943ab88223c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3345,3 +3345,5 @@ select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; f1 f2 f2 NULL a NULL drop table t1,t2; +select * from (select * left join t on f1=f2) tt; +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 'on f1=f2) tt' at line 1 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a85b82a7767..53f82690888 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2815,3 +2815,9 @@ create table t2 (f2 char not null); insert into t2 values('b'); select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; drop table t1,t2; + +# +# Bug#15538 unchecked table absense caused server crash. +# +--error 1064 +select * from (select * left join t on f1=f2) tt; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 25e10362ece..f1a00fca383 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5248,13 +5248,13 @@ join_table: | table_ref LEFT opt_outer JOIN_SYM table_ref ON { + YYERROR_UNLESS($1 && $5); /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; } expr { - YYERROR_UNLESS($1 && $5); add_join_on($5,$8); Lex->pop_context(); $5->outer_join|=JOIN_TYPE_LEFT; @@ -5279,6 +5279,7 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_ref ON { + YYERROR_UNLESS($1 && $5); /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; @@ -5286,7 +5287,6 @@ join_table: expr { LEX *lex= Lex; - YYERROR_UNLESS($1 && $5); if (!($$= lex->current_select->convert_right_join())) YYABORT; add_join_on($$, $8); From 8de137a3aa3c1e6d072665c350bb46415e94219f Mon Sep 17 00:00:00 2001 From: "reggie@linux.site" <> Date: Wed, 11 Jan 2006 16:18:11 -0600 Subject: [PATCH 120/154] simple Windows compile fixes. --- include/config-win.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 53483f3f39d..b2bd63efc30 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -108,11 +108,17 @@ functions */ #undef _REENTRANT /* Crashes something for win32 */ #undef SAFE_MUTEX /* Can't be used on windows */ -#define LONGLONG_MIN ((__int64) 0x8000000000000000) -#define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF) -#define ULONGLONG_MAX ((unsigned __int64) 0xFFFFFFFFFFFFFFFF) -#define LL(A) ((__int64) A) -#define ULL(A) ((unsigned __int64) A) +#if defined(_MSC_VER) && _MSC_VER >= 1310 +#define LL(A) A##ll +#define ULL(A) A##ull +#else +#define LL(A) ((__int64) A) +#define ULL(A) ((unsigned __int64) A) +#endif + +#define LONGLONG_MIN LL(0x8000000000000000) +#define LONGLONG_MAX LL(0x7FFFFFFFFFFFFFFF) +#define ULONGLONG_MAX ULL(0xFFFFFFFFFFFFFFFF) /* Type information */ @@ -333,11 +339,7 @@ inline double ulonglong2double(ulonglong value) #define SPRINTF_RETURNS_INT #define HAVE_SETFILEPOINTER #define HAVE_VIO_READ_BUFF - -#if defined(_WIN64) && defined(_M_X64) -/* Avoid type conflicts with built-in functions. */ #define HAVE_STRNLEN -#endif #ifndef __NT__ #undef FILE_SHARE_DELETE From dae00c191ff26ef9be312560cac0e5c5aeabfa4b Mon Sep 17 00:00:00 2001 From: "anozdrin@mysql.com" <> Date: Thu, 12 Jan 2006 03:02:52 +0300 Subject: [PATCH 121/154] Fix for BUG#15103: SHOW TRIGGERS: small output alignment problem. --- mysql-test/r/information_schema.result | 18 ++++++---------- mysql-test/r/mysqldump.result | 30 ++++++++++---------------- mysql-test/r/rpl_ddl.result | 4 ++-- mysql-test/r/trigger-compat.result | 6 ++---- mysql-test/r/trigger-grant.result | 21 ++++++------------ mysql-test/r/trigger.result | 4 ++-- sql/sql_yacc.yy | 2 ++ 7 files changed, 32 insertions(+), 53 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 05f2118a8c7..e7d82f48691 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -816,40 +816,34 @@ end if; end| show triggers; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 -begin +trg1 INSERT t1 begin if new.j > 10 then set new.j := 10; end if; end BEFORE NULL root@localhost -trg2 UPDATE t1 -begin +trg2 UPDATE t1 begin if old.i % 2 = 0 then set new.j := -1; end if; end BEFORE NULL root@localhost -trg3 UPDATE t1 -begin +trg3 UPDATE t1 begin if new.j = -1 then set @fired:= "Yes"; end if; end AFTER NULL root@localhost select * from information_schema.triggers; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER -NULL test trg1 INSERT NULL test t1 0 NULL -begin +NULL test trg1 INSERT NULL test t1 0 NULL begin if new.j > 10 then set new.j := 10; end if; end ROW BEFORE NULL NULL OLD NEW NULL root@localhost -NULL test trg2 UPDATE NULL test t1 0 NULL -begin +NULL test trg2 UPDATE NULL test t1 0 NULL begin if old.i % 2 = 0 then set new.j := -1; end if; end ROW BEFORE NULL NULL OLD NEW NULL root@localhost -NULL test trg3 UPDATE NULL test t1 0 NULL -begin +NULL test trg3 UPDATE NULL test t1 0 NULL begin if new.j = -1 then set @fired:= "Yes"; end if; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 4e2564c69da..717d9f67774 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1937,18 +1937,16 @@ end| set sql_mode=default| show triggers like "t1"; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 -begin +trg1 INSERT t1 begin if new.a > 10 then set new.a := 10; set new.a := 11; end if; end BEFORE 0000-00-00 00:00:00 root@localhost -trg2 UPDATE t1 begin +trg2 UPDATE t1 begin if old.a % 2 = 0 then set new.b := 12; end if; end BEFORE 0000-00-00 00:00:00 root@localhost -trg3 UPDATE t1 -begin +trg3 UPDATE t1 begin if new.a = -1 then set @fired:= "Yes"; end if; @@ -1986,8 +1984,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="" */;; -/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW -begin +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW begin if new.a > 10 then set new.a := 10; set new.a := 11; @@ -2000,8 +1997,7 @@ if old.a % 2 = 0 then set new.b := 12; end if; end */;; /*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; -/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW -begin +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW begin if new.a = -1 then set @fired:= "Yes"; end if; @@ -2023,8 +2019,7 @@ UNLOCK TABLES; /*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER" */;; -/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW -begin +/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW begin if new.a > 10 then set @fired:= "No"; end if; @@ -2096,24 +2091,21 @@ t1 t2 show triggers; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 -begin +trg1 INSERT t1 begin if new.a > 10 then set new.a := 10; set new.a := 11; end if; end BEFORE # root@localhost -trg2 UPDATE t1 begin +trg2 UPDATE t1 begin if old.a % 2 = 0 then set new.b := 12; end if; end BEFORE # root@localhost -trg3 UPDATE t1 -begin +trg3 UPDATE t1 begin if new.a = -1 then set @fired:= "Yes"; end if; end AFTER # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER root@localhost -trg4 INSERT t2 -begin +trg4 INSERT t2 begin if new.a > 10 then set @fired:= "No"; end if; @@ -2141,7 +2133,7 @@ a2 1 SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer -testref INSERT test1 BEGIN +testref INSERT test1 BEGIN INSERT INTO test2 SET a2 = NEW.a1; END BEFORE NULL root@localhost SELECT * FROM `test1`; a1 diff --git a/mysql-test/r/rpl_ddl.result b/mysql-test/r/rpl_ddl.result index 4d8f2f11d4a..c56c9f20cf8 100644 --- a/mysql-test/r/rpl_ddl.result +++ b/mysql-test/r/rpl_ddl.result @@ -1466,12 +1466,12 @@ flush logs; -------- switch to master ------- SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost -------- switch to slave ------- SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost ######## DROP TRIGGER trg1 ######## diff --git a/mysql-test/r/trigger-compat.result b/mysql-test/r/trigger-compat.result index 5c104a2d2d5..7721a55449b 100644 --- a/mysql-test/r/trigger-compat.result +++ b/mysql-test/r/trigger-compat.result @@ -34,7 +34,5 @@ Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'wl2818_trg1'. The SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER -NULL mysqltest_db1 wl2818_trg1 INSERT NULL mysqltest_db1 t1 0 NULL -INSERT INTO t2 VALUES(CURRENT_USER()) ROW BEFORE NULL NULL OLD NEW NULL -NULL mysqltest_db1 wl2818_trg2 INSERT NULL mysqltest_db1 t1 0 NULL -INSERT INTO t2 VALUES(CURRENT_USER()) ROW AFTER NULL NULL OLD NEW NULL mysqltest_dfn@localhost +NULL mysqltest_db1 wl2818_trg1 INSERT NULL mysqltest_db1 t1 0 NULL INSERT INTO t2 VALUES(CURRENT_USER()) ROW BEFORE NULL NULL OLD NEW NULL +NULL mysqltest_db1 wl2818_trg2 INSERT NULL mysqltest_db1 t1 0 NULL INSERT INTO t2 VALUES(CURRENT_USER()) ROW AFTER NULL NULL OLD NEW NULL mysqltest_dfn@localhost diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result index eda1adfdf65..858cab7a04a 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger-grant.result @@ -185,10 +185,8 @@ INSERT INTO t1 VALUES(6); ERROR 42000: Access denied; you need the SUPER privilege for this operation SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer -trg1 INSERT t1 -SET @new_sum = 0 BEFORE NULL mysqltest_inv@localhost -trg2 INSERT t1 -SET @new_sum = 0 AFTER NULL mysqltest_nonexs@localhost +trg1 INSERT t1 SET @new_sum = 0 BEFORE NULL mysqltest_inv@localhost +trg2 INSERT t1 SET @new_sum = 0 AFTER NULL mysqltest_nonexs@localhost DROP TRIGGER trg1; DROP TRIGGER trg2; CREATE TRIGGER trg1 BEFORE INSERT ON t1 @@ -219,16 +217,11 @@ Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigge SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER -NULL mysqltest_db1 trg1 INSERT NULL mysqltest_db1 t1 0 NULL -SET @a = 1 ROW BEFORE NULL NULL OLD NEW NULL -NULL mysqltest_db1 trg2 INSERT NULL mysqltest_db1 t1 0 NULL -SET @a = 2 ROW AFTER NULL NULL OLD NEW NULL @ -NULL mysqltest_db1 trg3 UPDATE NULL mysqltest_db1 t1 0 NULL -SET @a = 3 ROW BEFORE NULL NULL OLD NEW NULL @abc@def@@ -NULL mysqltest_db1 trg4 UPDATE NULL mysqltest_db1 t1 0 NULL -SET @a = 4 ROW AFTER NULL NULL OLD NEW NULL @hostname -NULL mysqltest_db1 trg5 DELETE NULL mysqltest_db1 t1 0 NULL -SET @a = 5 ROW BEFORE NULL NULL OLD NEW NULL @abcdef@@@hostname +NULL mysqltest_db1 trg1 INSERT NULL mysqltest_db1 t1 0 NULL SET @a = 1 ROW BEFORE NULL NULL OLD NEW NULL +NULL mysqltest_db1 trg2 INSERT NULL mysqltest_db1 t1 0 NULL SET @a = 2 ROW AFTER NULL NULL OLD NEW NULL @ +NULL mysqltest_db1 trg3 UPDATE NULL mysqltest_db1 t1 0 NULL SET @a = 3 ROW BEFORE NULL NULL OLD NEW NULL @abc@def@@ +NULL mysqltest_db1 trg4 UPDATE NULL mysqltest_db1 t1 0 NULL SET @a = 4 ROW AFTER NULL NULL OLD NEW NULL @hostname +NULL mysqltest_db1 trg5 DELETE NULL mysqltest_db1 t1 0 NULL SET @a = 5 ROW BEFORE NULL NULL OLD NEW NULL @abcdef@@@hostname ---> connection: default DROP USER mysqltest_dfn@localhost; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 38dff6f8ca5..9cfecde7610 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -613,7 +613,7 @@ select @a; show triggers; Trigger Event Table Statement Timing Created sql_mode Definer t1_bi INSERT t1 set new."t1 column" = 5 BEFORE # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI root@localhost -t1_af INSERT t1 set @a=10 AFTER # root@localhost +t1_af INSERT t1 set @a=10 AFTER # root@localhost drop table t1; set sql_mode="traditional"; create table t1 (a date); @@ -634,7 +634,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 show triggers; Trigger Event Table Statement Timing Created sql_mode Definer -t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # root@localhost +t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # root@localhost drop table t1; create table t1 (id int); create trigger t1_ai after insert on t1 for each row flush tables; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 25e10362ece..ce0cb35dcf8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9103,6 +9103,8 @@ trigger_tail: bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->m_body_begin= lex->ptr; + while (my_isspace(system_charset_info, lex->sphead->m_body_begin[0])) + ++lex->sphead->m_body_begin; } sp_proc_stmt { From e40759e370cca0a34698e6bcc8e3b9849e1bbbac Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Thu, 12 Jan 2006 10:48:27 +0300 Subject: [PATCH 122/154] BUG#16166, "Can't use index_merge with FORCE INDEX": adjust the heurstics check to take into account that "FORCE INDEX" disables full table scans, and not range/index_merge scans. (with post-review fixes) --- mysql-test/r/index_merge.result | 18 +++++++++++++++++ mysql-test/t/index_merge.test | 30 ++++++++++++++++++++++++++++ sql/sql_select.cc | 35 ++++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index d039d5a04c9..db87253e19a 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -384,3 +384,21 @@ max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.ke 8186 set join_buffer_size= @save_join_buffer_size; drop table t0, t1, t2, t3, t4; +CREATE TABLE t1 ( +cola char(3) not null, colb char(3) not null, filler char(200), +key(cola), key(colb) +); +INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +select count(*) from t1; +count(*) +8704 +explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where +explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where +drop table t1; diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index 42175a757c2..10512902409 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -327,3 +327,33 @@ set join_buffer_size= @save_join_buffer_size; drop table t0, t1, t2, t3, t4; +# BUG#16166 +CREATE TABLE t1 ( + cola char(3) not null, colb char(3) not null, filler char(200), + key(cola), key(colb) +); +INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); + +--disable_query_log +let $1=9; +while ($1) +{ + eval INSERT INTO t1 SELECT * from t1 WHERE cola = 'foo'; + dec $1; +} + +let $1=13; +while ($1) +{ + eval INSERT INTO t1 SELECT * from t1 WHERE cola <> 'foo'; + dec $1; +} + +--enable_query_log + +OPTIMIZE TABLE t1; +select count(*) from t1; +explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; +drop table t1; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c282a5bd42c..4a31a297c25 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3471,13 +3471,32 @@ best_access_path(JOIN *join, parts of the row from any of the used index. This is because table scans uses index and we would not win anything by using a table scan. + + A word for word translation of the below if-statement in psergey's + understanding: we check if we should use table scan if: + (1) The found 'ref' access produces more records than a table scan + (or index scan, or quick select), or 'ref' is more expensive than + any of them. + (2) This doesn't hold: the best way to perform table scan is to to perform + 'range' access using index IDX, and the best way to perform 'ref' + access is to use the same index IDX, with the same or more key parts. + (note: it is not clear how this rule is/should be extended to + index_merge quick selects) + (3) See above note about InnoDB. + (4) NOT ("FORCE INDEX(...)" is used for table and there is 'ref' access + path, but there is no quick select) + If the condition in the above brackets holds, then the only possible + "table scan" access method is ALL/index (there is no quick select). + Since we have a 'ref' access path, and FORCE INDEX instructs us to + choose it over ALL/index, there is no need to consider a full table + scan. */ - if ((records >= s->found_records || best > s->read_time) && - !(s->quick && best_key && s->quick->index == best_key->key && - best_max_key_part >= s->table->quick_key_parts[best_key->key]) && - !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && - ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key)) + if ((records >= s->found_records || best > s->read_time) && // (1) + !(s->quick && best_key && s->quick->index == best_key->key && // (2) + best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2) + !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3) + ! s->table->used_keys.is_clear_all() && best_key) && // (3) + !(s->table->force_index && best_key && !s->quick)) // (4) { // Check full join ha_rows rnd_records= s->found_records; /* @@ -4460,13 +4479,15 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, parts of the row from any of the used index. This is because table scans uses index and we would not win anything by using a table scan. + (see comment in best_access_path() for more details on the below + condition) */ if ((records >= s->found_records || best > s->read_time) && !(s->quick && best_key && s->quick->index == best_key->key && best_max_key_part >= s->table->quick_key_parts[best_key->key]) && !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key)) + !(s->table->force_index && best_key & !s->quick)) { // Check full join ha_rows rnd_records= s->found_records; /* From aa00d65ead2b3ac14154a141497f25f1df6a000a Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Thu, 12 Jan 2006 11:11:16 +0300 Subject: [PATCH 123/154] Fix typo bug in previous cset --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4a31a297c25..e8f2cb2c6a0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4487,7 +4487,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, best_max_key_part >= s->table->quick_key_parts[best_key->key]) && !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key & !s->quick)) + !(s->table->force_index && best_key && !s->quick)) { // Check full join ha_rows rnd_records= s->found_records; /* From 832148ded2e1145296e873e78e8f1747d87efcf9 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 12 Jan 2006 13:08:49 +0400 Subject: [PATCH 124/154] ctype_utf8.result: After merge fix: fixing order of results. --- mysql-test/r/ctype_utf8.result | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index fee561941f0..b2a22036cb5 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1058,6 +1058,14 @@ char(a) 1 2 drop table t1; +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +LENGTH(bug) +100 +DROP TABLE t2; +DROP TABLE t1; CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8; INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa'); SELECT id FROM t1; @@ -1167,11 +1175,3 @@ set @a:=null; execute my_stmt using @a; a b drop table if exists t1; -CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); -INSERT INTO t1 VALUES(REPEAT('a', 100)); -CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; -SELECT LENGTH(bug) FROM t2; -LENGTH(bug) -100 -DROP TABLE t2; -DROP TABLE t1; From 5f17cbaba47576378eebc1ce0277750c7e6f7c28 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 12 Jan 2006 16:05:46 +0400 Subject: [PATCH 125/154] sql_show.cc: after-merge fix for bug#15581 COALESCE function truncates mutli-byte TINYTEXT values --- sql/sql_show.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d15df686e40..59008b1b77f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2623,12 +2623,15 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type field->real_type() == MYSQL_TYPE_STRING) // For binary type { + uint32 octet_max_length= field->max_length(); + if (octet_max_length != (uint32) 4294967295U) + octet_max_length /= field->charset()->mbmaxlen; longlong char_max_len= is_blob ? - (longlong) field->max_length() / field->charset()->mbminlen : - (longlong) field->max_length() / field->charset()->mbmaxlen; + (longlong) octet_max_length / field->charset()->mbminlen : + (longlong) octet_max_length / field->charset()->mbmaxlen; table->field[8]->store(char_max_len, TRUE); table->field[8]->set_notnull(); - table->field[9]->store((longlong) field->max_length(), TRUE); + table->field[9]->store((longlong) octet_max_length, TRUE); table->field[9]->set_notnull(); } From af845f6eff7d04963e01ef474e41bdb5adafd403 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Thu, 12 Jan 2006 15:10:12 +0200 Subject: [PATCH 126/154] NetWare specific change to increase thread stack size. Changes to Netware specific mysqld_safe.c --- include/config-netware.h | 3 +++ innobase/os/os0thread.c | 9 +++++++++ netware/mysqld_safe.c | 42 ++++++++++++++-------------------------- sql/mysqld.cc | 5 +++++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/include/config-netware.h b/include/config-netware.h index e07e972ba4b..43ee05e39ee 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -92,6 +92,9 @@ extern "C" { /* On NetWare, stack grows towards lower address*/ #define STACK_DIRECTION -1 +/* On NetWare, we need to set stack size for threads, otherwise default 16K is used */ +#define NW_THD_STACKSIZE 65536 + /* On NetWare, to fix the problem with the deletion of open files */ #define CANT_DELETE_OPEN_FILES 1 diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 59d0fdbd8c9..cb72310f23d 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -147,6 +147,15 @@ os_thread_create( "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); exit(1); } +#endif +#ifdef __NETWARE__ + ret = pthread_attr_setstacksize(&attr, + (size_t) NW_THD_STACKSIZE); + if (ret) { + fprintf(stderr, + "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); + exit(1); + } #endif os_mutex_enter(os_sync_mutex); os_thread_count++; diff --git a/netware/mysqld_safe.c b/netware/mysqld_safe.c index dbb49882140..5f65e2f45b7 100644 --- a/netware/mysqld_safe.c +++ b/netware/mysqld_safe.c @@ -252,51 +252,39 @@ void finish_defaults() ******************************************************************************/ void read_defaults(arg_list_t *pal) { - arg_list_t al; - char defaults_file[PATH_MAX]; char mydefaults[PATH_MAX]; + char mydefaults_command[3*PATH_MAX]; char line[PATH_MAX]; FILE *fp; - // defaults output file - snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir); - remove(defaults_file); - - // mysqladmin file + // my_print_defaults file snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir); - // args - init_args(&al); - add_arg(&al, mydefaults); - if (default_option[0]) add_arg(&al, default_option); - add_arg(&al, "mysqld"); - add_arg(&al, "server"); - add_arg(&al, "mysqld_safe"); - add_arg(&al, "safe_mysqld"); - - spawn(mydefaults, &al, TRUE, NULL, defaults_file, NULL); - - free_args(&al); - + // args to my_print_defaults + if (default_option[0]) + { + snprintf(mydefaults_command, 3*PATH_MAX, "%s %s mysqld server mysqld_safe safe_mysqld", mydefaults, default_option); + } + else + { + snprintf(mydefaults_command, 3*PATH_MAX, "%s mysqld server mysqld_safe safe_mysqld", mydefaults); + } // gather defaults - if((fp = fopen(defaults_file, "r")) != NULL) + if((fp = popen(mydefaults_command, "r")) != NULL) { while(fgets(line, PATH_MAX, fp)) { char *p; // remove end-of-line character - if ((p = strrchr(line, '\n')) != NULL) *p = '\0'; + if ((p = strrchr(line, '\n')) != NULL) + *p = '\0'; // add the option as an argument add_arg(pal, line); } - - fclose(fp); + pclose(fp); } - - // remove file - remove(defaults_file); } /****************************************************************************** diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f7df7233795..00bcdbf7132 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2401,6 +2401,11 @@ You should consider changing lower_case_table_names to 1 or 2", thread_stack= stack_size; } } +#endif +#ifdef __NETWARE__ + /* Increasing stacksize of threads on NetWare */ + + pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE); #endif if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR); From 7f919f9ef731c1a9ed42c38cce810ef69c48eb11 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 12 Jan 2006 18:19:57 +0100 Subject: [PATCH 127/154] Use "test ! -s" to check that file does not exist --- mysql-test/t/mysqltest.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index ee309fbd7c9..5cf49185c30 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1037,7 +1037,7 @@ drop table t1; --error 1 --exec $MYSQL_TEST --record -x $MYSQL_TEST_DIR/var/tmp/bug11731.sql -R $MYSQL_TEST_DIR/var/tmp/bug11731.out 2>&1 # The .out file should be non existent ---exec test ! -e $MYSQL_TEST_DIR/var/tmp/bug11731.out +--exec test ! -s $MYSQL_TEST_DIR/var/tmp/bug11731.out drop table t1; From 8f3645e6f08acf9300063cef8ec940277467a7a0 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Thu, 12 Jan 2006 20:31:00 +0200 Subject: [PATCH 128/154] Fix for Netware build. --- netware/BUILD/compile-linux-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools index 14422ea5a3f..fab92b8d4df 100755 --- a/netware/BUILD/compile-linux-tools +++ b/netware/BUILD/compile-linux-tools @@ -57,7 +57,7 @@ make cp extra/comp_err extra/comp_err.linux cp libmysql/conf_to_src libmysql/conf_to_src.linux #cp libmysql_r/conf_to_src libmysql_r/conf_to_src.linux -cp sql/gen_lex_hash sql/gen_lex_hash.linux +cp sql/.libs/gen_lex_hash sql/gen_lex_hash.linux cp strings/conf_to_src strings/conf_to_src.linux # Delete mysql_version.h From 4d59111a1c21a4bde64fc18ee536d3ca9b42d772 Mon Sep 17 00:00:00 2001 From: "jani@ua141d10.elisa.omakaista.fi" <> Date: Thu, 12 Jan 2006 20:49:47 +0200 Subject: [PATCH 129/154] Fixed a bug in merge. --- sql/sql_handler.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 3370a0a1957..e9e1e79daaf 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -426,9 +426,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, { if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - if ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)) - goto err0; + goto err0; } if (keyname) From d14e7014463d791ffd96ef5a8ed062ccca545ecf Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Fri, 13 Jan 2006 01:51:56 +0300 Subject: [PATCH 130/154] Fix for bug #12198 "Temporary table aliasing does not work inside stored functions". We should ignore alias when we check if table was already marked as temporary when we calculate set of tables to be prelocked. Otherwise we will erroneously treat tables which are used in same routine and have same name but different alias as non-temporary. --- mysql-test/r/sp.result | 67 +++++++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 80 ++++++++++++++++++++++++++++++++++++++++-- sql/sp_head.cc | 31 +++++++++++----- 3 files changed, 168 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 231ca329f3d..6d231b35a89 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -918,6 +918,11 @@ drop function if exists f5| drop function if exists f6| drop function if exists f7| drop function if exists f8| +drop function if exists f9| +drop function if exists f10| +drop function if exists f11| +drop function if exists f12_1| +drop function if exists f12_2| drop view if exists v0| drop view if exists v1| drop view if exists v2| @@ -1087,6 +1092,62 @@ ERROR HY000: Table 't1' was not locked with LOCK TABLES select f4()| ERROR HY000: Table 't2' was not locked with LOCK TABLES unlock tables| +create function f9() returns int +begin +declare a, b int; +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +set a:= (select count(*) from t3); +set b:= (select count(*) from t3 t3_alias); +return a + b; +end| +select f9()| +f9() +6 +Warnings: +Note 1051 Unknown table 't3' +select f9() from t1 limit 1| +f9() +6 +create function f10() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 select id from t4; +return (select count(*) from t3); +end| +select f10()| +ERROR 42S02: Table 'test.t4' doesn't exist +create table t4 as select 1 as id| +select f10()| +f10() +1 +create function f11() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +return (select count(*) from t3 as a, t3 as b); +end| +select f11()| +ERROR HY000: Can't reopen table: 'a' +select f11() from t1| +ERROR HY000: Can't reopen table: 'a' +create function f12_1() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +return f12_2(); +end| +create function f12_2() returns int +return (select count(*) from t3)| +drop temporary table t3| +select f12_1()| +ERROR 42S02: Table 'test.t3' doesn't exist +select f12_1() from t1 limit 1| +ERROR 42S02: Table 'test.t3' doesn't exist drop function f0| drop function f1| drop function f2| @@ -1096,11 +1157,17 @@ drop function f5| drop function f6| drop function f7| drop function f8| +drop function f9| +drop function f10| +drop function f11| +drop function f12_1| +drop function f12_2| drop view v0| drop view v1| drop view v2| delete from t1 | delete from t2 | +drop table t4| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| drop procedure if exists ifac| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index fba3cfcbfbc..6aa27969299 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1154,6 +1154,11 @@ drop function if exists f5| drop function if exists f6| drop function if exists f7| drop function if exists f8| +drop function if exists f9| +drop function if exists f10| +drop function if exists f11| +drop function if exists f12_1| +drop function if exists f12_2| drop view if exists v0| drop view if exists v1| drop view if exists v2| @@ -1233,8 +1238,6 @@ create function f7() returns int select f6()| select id, f6() from t1| -# TODO Test temporary table handling - # # Let us test how new locking work with views # @@ -1318,6 +1321,73 @@ select * from v1, t1| select f4()| unlock tables| +# Tests for handling of temporary tables in functions. +# +# Unlike for permanent tables we should be able to create, use +# and drop such tables in functions. +# +# Simplest function using temporary table. It is also test case for bug +# #12198 "Temporary table aliasing does not work inside stored functions" +create function f9() returns int +begin + declare a, b int; + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + set a:= (select count(*) from t3); + set b:= (select count(*) from t3 t3_alias); + return a + b; +end| +# This will emit warning as t3 was not existing before. +select f9()| +select f9() from t1 limit 1| + +# Function which uses both temporary and permanent tables. +create function f10() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 select id from t4; + return (select count(*) from t3); +end| +# Check that we don't ignore completely tables used in function +--error ER_NO_SUCH_TABLE +select f10()| +create table t4 as select 1 as id| +select f10()| + +# Practical cases which we don't handle well (yet) +# +# Function which does not work because of well-known and documented +# limitation of MySQL. We can't use the several instances of the +# same temporary table in statement. +create function f11() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + return (select count(*) from t3 as a, t3 as b); +end| +--error ER_CANT_REOPEN_TABLE +select f11()| +--error ER_CANT_REOPEN_TABLE +select f11() from t1| +# We don't handle temporary tables used by nested functions well +create function f12_1() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + return f12_2(); +end| +create function f12_2() returns int + return (select count(*) from t3)| +# We need clean start to get error +drop temporary table t3| +--error ER_NO_SUCH_TABLE +select f12_1()| +--error ER_NO_SUCH_TABLE +select f12_1() from t1 limit 1| # Cleanup drop function f0| @@ -1329,11 +1399,17 @@ drop function f5| drop function f6| drop function f7| drop function f8| +drop function f9| +drop function f10| +drop function f11| +drop function f12_1| +drop function f12_2| drop view v0| drop view v1| drop view v2| delete from t1 | delete from t2 | +drop table t4| # End of non-bug tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a6e88c08789..8d0212a31da 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2992,7 +2992,14 @@ sp_restore_security_context(THD *thd, Security_context *backup) typedef struct st_sp_table { - LEX_STRING qname; /* Multi-set key: db_name\0table_name\0alias\0 */ + /* + Multi-set key: + db_name\0table_name\0alias\0 - for normal tables + db_name\0table_name\0 - for temporary tables + Note that in both cases we don't take last '\0' into account when + we count length of key. + */ + LEX_STRING qname; uint db_length, table_name_length; bool temp; /* true if corresponds to a temporary table */ thr_lock_type lock_type; /* lock type used for prelocking */ @@ -3062,10 +3069,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tname[tlen]= '\0'; /* - It is safe to store pointer to table list elements in hash, - since they are supposed to have the same lifetime. + We ignore alias when we check if table was already marked as temporary + (and therefore should not be prelocked). Otherwise we will erroneously + treat table with same name but with different alias as non-temporary. */ - if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen))) + if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) || + ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, + tlen - alen - 1)) && + tab->temp)) { if (tab->lock_type < table->lock_type) tab->lock_type= table->lock_type; // Use the table with the highest lock type @@ -3077,14 +3088,18 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) { if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) return FALSE; - tab->qname.length= tlen; - tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1); - if (!tab->qname.str) - return FALSE; if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && lex_for_tmp_check->query_tables == table && lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) + { tab->temp= TRUE; + tab->qname.length= tlen - alen - 1; + } + else + tab->qname.length= tlen; + tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1); + if (!tab->qname.str) + return FALSE; tab->table_name_length= table->table_name_length; tab->db_length= table->db_length; tab->lock_type= table->lock_type; From 8dce5e198d069079f5fc2b614e003082ce303b2e Mon Sep 17 00:00:00 2001 From: "jonas@perch.ndb.mysql.com" <> Date: Fri, 13 Jan 2006 07:40:15 +0100 Subject: [PATCH 131/154] bug#15619 - ndb_autodiscover sometimes fails --- ndb/src/mgmsrv/MgmtSrvr.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 34a0adf46b9..816b71bd816 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -1868,6 +1868,16 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, m_connect_address[id_found].s_addr= 0; } m_reserved_nodes.set(id_found); + if (theFacade && id_found != theFacade->ownId()) + { + /** + * Make sure we're ready to accept connections from this node + */ + theFacade->lock_mutex(); + theFacade->doConnect(id_found); + theFacade->unlock_mutex(); + } + char tmp_str[128]; m_reserved_nodes.getText(tmp_str); g_eventLogger.info("Mgmt server state: nodeid %d reserved for ip %s, m_reserved_nodes %s.", From 9d4562e5fe6f3485bf8b0e34a04122538e5ab127 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Fri, 13 Jan 2006 16:25:20 +0100 Subject: [PATCH 132/154] extra/comp_err.c + scripts/mysqld_multi.sh : Copyright string fixes (bug#16106) --- extra/comp_err.c | 4 +++- scripts/mysqld_multi.sh | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/extra/comp_err.c b/extra/comp_err.c index bd7e6231908..e627a47b21f 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -137,7 +137,9 @@ static void get_options(register int *argc,register char **argv[]) case 'I': case '?': printf(" %s (Compile errormessage) Ver 1.3\n",progname); - puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); + puts("This software comes with ABSOLUTELY NO WARRANTY. " + "This is free software,\n" + "and you are welcome to modify and redistribute it under the GPL license.\n"); printf("Usage: %s [-?] [-I] [-V] fromfile[s] tofile\n",progname); puts("Options: -Info -Version\n"); help=1; diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index b75aa1a7c31..21439650ef3 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -624,9 +624,6 @@ sub usage print < Date: Fri, 13 Jan 2006 21:25:12 +0400 Subject: [PATCH 133/154] BUG#13835: max key length is 1000 bytes when trying to create a fulltext index Allow fulltext index on VARCHAR columns longer than max key length. --- mysql-test/r/fulltext.result | 8 ++++++++ mysql-test/t/fulltext.test | 8 ++++++++ sql/sql_table.cc | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 7e2e0a56212..3e6dd896ed8 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -437,3 +437,11 @@ SELECT a FROM t1 WHERE MATCH a AGAINST('testword\'\'' IN BOOLEAN MODE); a testword'' DROP TABLE t1; +CREATE TABLE t1 (a VARCHAR(10000), FULLTEXT(a)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(10000) default NULL, + FULLTEXT KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index ea92ec944ed..a90344784cd 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -357,4 +357,12 @@ SELECT a FROM t1 WHERE MATCH a AGAINST('testword' IN BOOLEAN MODE); SELECT a FROM t1 WHERE MATCH a AGAINST('testword\'\'' IN BOOLEAN MODE); DROP TABLE t1; +# +# BUG#13835: max key length is 1000 bytes when trying to create +# a fulltext index +# +CREATE TABLE t1 (a VARCHAR(10000), FULLTEXT(a)); +SHOW CREATE TABLE t1; +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ba4a606537f..849619ae0f8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1296,7 +1296,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name); DBUG_RETURN(-1); } - if (length > file->max_key_part_length()) + if (length > file->max_key_part_length() && key->type != Key::FULLTEXT) { length=file->max_key_part_length(); if (key->type == Key::MULTIPLE) From e58314d4829246bf7ea7b15f8c3e3fec3f09a71a Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Fri, 13 Jan 2006 23:55:30 +0300 Subject: [PATCH 134/154] BUG#16393: Let the 'ref' optimizer use ON condition of nested join to construct 'ref' accesses to all tables that are direct children of the nested join and are not inner wrt their siblings. --- mysql-test/r/join_nested.result | 20 +++++++-- mysql-test/t/join_nested.test | 14 ++++++ sql/sql_select.cc | 80 ++++++++++++++++++++++++++++----- 3 files changed, 99 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result index 6b7293d46bc..faad969fcd1 100644 --- a/mysql-test/r/join_nested.result +++ b/mysql-test/r/join_nested.result @@ -960,7 +960,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where -1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where 1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where @@ -1009,7 +1009,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where -1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where 1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where @@ -1059,7 +1059,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where -1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where 1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where 1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where 1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where @@ -1467,3 +1467,17 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t6 ref a a 5 test.t4.b X 1 SIMPLE t5 ref a a 5 test.t3.b X drop table t0, t1, t2, t3, t4, t5, t6, t7; +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(100), key(a)); +insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B; +create table t3 like t2; +insert into t3 select * from t2; +explain select * from t1 left join +(t2 left join t3 on (t2.a = t3.a)) +on (t1.a = t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 10 +1 SIMPLE t2 ref a a 5 test.t1.a 1 +1 SIMPLE t3 ref a a 5 test.t2.a 1 +drop table t1, t2, t3; diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test index 9f23e2d0e2f..145edded486 100644 --- a/mysql-test/t/join_nested.test +++ b/mysql-test/t/join_nested.test @@ -900,3 +900,17 @@ explain select * from t2 left join join t5 on t5.a=t3.b) on t3.a=t2.b; drop table t0, t1, t2, t3, t4, t5, t6, t7; + +# BUG#16393 +create table t1 (a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (a int, filler char(100), key(a)); +insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B; +create table t3 like t2; +insert into t3 select * from t2; + +explain select * from t1 left join + (t2 left join t3 on (t2.a = t3.a)) + on (t1.a = t2.a); +drop table t1, t2, t3; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ad6375290cd..9436ad7e840 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2917,6 +2917,64 @@ sort_keyuse(KEYUSE *a,KEYUSE *b) } +/* + Add to KEY_FIELD array all 'ref' access candidates within nested join + + SYNPOSIS + add_key_fields_for_nj() + nested_join_table IN Nested join pseudo-table to process + end INOUT End of the key field array + and_level INOUT And-level + + DESCRIPTION + This function populates KEY_FIELD array with entries generated from the + ON condition of the given nested join, and does the same for nested joins + contained within this nested join. + + IMPLEMENTATION + We can add accesses to the tables that are direct children of this nested + join (1), and are not inner tables w.r.t their neighbours (2). + + Example for #1 (outer brackets pair denotes nested join this function is + invoked for): + + ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond + + Example for #2: + + ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond + + In examples 1-2 for condition cond, we can add 'ref' access candidates to + t1 only. + + Example #3: + + ... LEFT JOIN (t1, t2 JOIN t3 ON inner_cond) ON cond + + Here we can add 'ref' access candidates for t1 and t2, but not for t3. + +*/ + +static void add_key_fields_for_nj(TABLE_LIST *nested_join_table, + KEY_FIELD **end, uint *and_level) +{ + List_iterator li(nested_join_table->nested_join->join_list); + table_map tables= 0; + TABLE_LIST *table; + DBUG_ASSERT(nested_join_table->nested_join); + + while ((table= li++)) + { + if (table->nested_join) + add_key_fields_for_nj(table, end, and_level); + else + if (!table->on_expr) + tables |= table->table->map; + } + add_key_fields(end, and_level, nested_join_table->on_expr, tables); +} + + /* Update keyuse array with all possible keys we can use to fetch rows @@ -2981,23 +3039,21 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, into account as well. */ if (*join_tab[i].on_expr_ref) - { add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref, join_tab[i].table->map); - } - else + } + + /* Process ON conditions for the nested joins */ + { + List_iterator li(*join_tab->join->join_list); + TABLE_LIST *table; + while ((table= li++)) { - TABLE_LIST *tab= join_tab[i].table->pos_in_table_list; - TABLE_LIST *embedding= tab->embedding; - if (embedding) - { - NESTED_JOIN *nested_join= embedding->nested_join; - if (nested_join->join_list.head() == tab) - add_key_fields(&end, &and_level, embedding->on_expr, - nested_join->used_tables); - } + if (table->nested_join) + add_key_fields_for_nj(table, &end, &and_level); } } + /* fill keyuse with found key parts */ for ( ; field != end ; field++) add_key_part(keyuse,field); From dc14d007dba793e5366e258460fe6e34be024af8 Mon Sep 17 00:00:00 2001 From: "sergefp@mysql.com" <> Date: Sat, 14 Jan 2006 01:26:42 +0300 Subject: [PATCH 135/154] BUG#16393: post-review fixes: fix comments. --- sql/sql_select.cc | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9436ad7e840..1c7293fd89d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2925,34 +2925,26 @@ sort_keyuse(KEYUSE *a,KEYUSE *b) nested_join_table IN Nested join pseudo-table to process end INOUT End of the key field array and_level INOUT And-level - + DESCRIPTION This function populates KEY_FIELD array with entries generated from the ON condition of the given nested join, and does the same for nested joins contained within this nested join. - - IMPLEMENTATION + + NOTES We can add accesses to the tables that are direct children of this nested join (1), and are not inner tables w.r.t their neighbours (2). Example for #1 (outer brackets pair denotes nested join this function is invoked for): - ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond - Example for #2: - ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond - In examples 1-2 for condition cond, we can add 'ref' access candidates to t1 only. - Example #3: - - ... LEFT JOIN (t1, t2 JOIN t3 ON inner_cond) ON cond - + ... LEFT JOIN (t1, t2 LEFT JOIN t3 ON inner_cond) ON cond Here we can add 'ref' access candidates for t1 and t2, but not for t3. - */ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table, @@ -2969,7 +2961,7 @@ static void add_key_fields_for_nj(TABLE_LIST *nested_join_table, add_key_fields_for_nj(table, end, and_level); else if (!table->on_expr) - tables |= table->table->map; + tables |= table->table->map; } add_key_fields(end, and_level, nested_join_table->on_expr, tables); } From 48d48bc93603d9f77db4e86907f84103d45c5709 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Sat, 14 Jan 2006 04:55:07 +0300 Subject: [PATCH 136/154] A fix and a test case for Bug#12734 " prepared statement may return incorrect result set for a select SQL request" --- mysql-test/r/ps.result | 34 ++++++++++++++++++++++++++++++++++ mysql-test/t/ps.test | 30 ++++++++++++++++++++++++++++++ sql/item_cmpfunc.cc | 6 ++++++ sql/item_cmpfunc.h | 1 + 4 files changed, 71 insertions(+) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index d46c2d5b3d5..aa9ff083cbb 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -718,3 +718,37 @@ execute stmt; drop table t1; set names default; deallocate prepare stmt; +create table t1 ( +word_id mediumint(8) unsigned not null default '0', +formatted varchar(20) not null default '' +); +insert into t1 values +(80,'pendant'), (475,'pretendants'), (989,'tendances'), +(1019,'cependant'),(1022,'abondance'),(1205,'independants'), +(13,'lessiver'),(25,'lambiner'),(46,'situer'),(71,'terminer'), +(82,'decrocher'); +select count(*) from t1 where formatted like '%NDAN%'; +count(*) +6 +select count(*) from t1 where formatted like '%ER'; +count(*) +5 +prepare stmt from "select count(*) from t1 where formatted like ?"; +set @like="%NDAN%"; +execute stmt using @like; +count(*) +6 +set @like="%ER"; +execute stmt using @like; +count(*) +5 +set @like="%NDAN%"; +execute stmt using @like; +count(*) +6 +set @like="%ER"; +execute stmt using @like; +count(*) +5 +deallocate prepare stmt; +drop table t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 82dfc643801..23eb2e11ae3 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -746,5 +746,35 @@ drop table t1; set names default; deallocate prepare stmt; +# +# A test case for Bug#12734 "prepared statement may return incorrect result +# set for a select SQL request": test that canDoTurboBM is reset for each +# execute of a prepared statement. +# +create table t1 ( + word_id mediumint(8) unsigned not null default '0', + formatted varchar(20) not null default '' +); + +insert into t1 values + (80,'pendant'), (475,'pretendants'), (989,'tendances'), + (1019,'cependant'),(1022,'abondance'),(1205,'independants'), + (13,'lessiver'),(25,'lambiner'),(46,'situer'),(71,'terminer'), + (82,'decrocher'); + +select count(*) from t1 where formatted like '%NDAN%'; +select count(*) from t1 where formatted like '%ER'; +prepare stmt from "select count(*) from t1 where formatted like ?"; +set @like="%NDAN%"; +execute stmt using @like; +set @like="%ER"; +execute stmt using @like; +set @like="%NDAN%"; +execute stmt using @like; +set @like="%ER"; +execute stmt using @like; +deallocate prepare stmt; +drop table t1; + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 2c76c7ec7b3..f9aa220c181 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2524,6 +2524,12 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) return 0; } +void Item_func_like::cleanup() +{ + canDoTurboBM= FALSE; + Item_bool_func2::cleanup(); +} + #ifdef USE_REGEX bool diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 045566a46d5..ade09113c63 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -911,6 +911,7 @@ public: cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + void cleanup(); }; #ifdef USE_REGEX From 750f9fee90b0214c9be52051cd92cd6b2aba6e85 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Sat, 14 Jan 2006 21:20:42 +0300 Subject: [PATCH 137/154] A post-merge fix (Bug#12734) --- mysql-test/r/ps.result | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index bc3d2a6108c..a7c05e9acad 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -825,6 +825,40 @@ execute stmt; drop table t1; set names default; deallocate prepare stmt; +create table t1 ( +word_id mediumint(8) unsigned not null default '0', +formatted varchar(20) not null default '' +); +insert into t1 values +(80,'pendant'), (475,'pretendants'), (989,'tendances'), +(1019,'cependant'),(1022,'abondance'),(1205,'independants'), +(13,'lessiver'),(25,'lambiner'),(46,'situer'),(71,'terminer'), +(82,'decrocher'); +select count(*) from t1 where formatted like '%NDAN%'; +count(*) +6 +select count(*) from t1 where formatted like '%ER'; +count(*) +5 +prepare stmt from "select count(*) from t1 where formatted like ?"; +set @like="%NDAN%"; +execute stmt using @like; +count(*) +6 +set @like="%ER"; +execute stmt using @like; +count(*) +5 +set @like="%NDAN%"; +execute stmt using @like; +count(*) +6 +set @like="%ER"; +execute stmt using @like; +count(*) +5 +deallocate prepare stmt; +drop table t1; create table t1 (id int); prepare ins_call from "insert into t1 (id) values (1)"; execute ins_call; From ee2b765751226cb07f787053aed9f6c89e11b18e Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Sun, 15 Jan 2006 14:50:47 +0300 Subject: [PATCH 138/154] Changes from innodb-4.1-ss14 snapshot Fixed BUG#14056: Column prefix index on UTF-8 primary key causes "Can't find record.." Also fixed bug 15991. --- innobase/include/os0file.h | 5 +- innobase/os/os0file.c | 8 ++- mysql-test/r/innodb.result | 40 +++++++++++ mysql-test/t/innodb.test | 36 ++++++++++ sql/ha_innodb.cc | 131 +++++++++++++++++++++++++++++++++---- 5 files changed, 203 insertions(+), 17 deletions(-) diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index cd07eb49cd6..0091e942d2c 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -86,9 +86,10 @@ log. */ #define OS_FILE_NOT_FOUND 71 #define OS_FILE_DISK_FULL 72 #define OS_FILE_ALREADY_EXISTS 73 -#define OS_FILE_AIO_RESOURCES_RESERVED 74 /* wait for OS aio resources +#define OS_FILE_PATH_ERROR 74 +#define OS_FILE_AIO_RESOURCES_RESERVED 75 /* wait for OS aio resources to become available again */ -#define OS_FILE_ERROR_NOT_SPECIFIED 75 +#define OS_FILE_ERROR_NOT_SPECIFIED 76 /* Types for aio operations */ #define OS_FILE_READ 10 diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 49f88c0d62a..6ef6f7cd545 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -303,6 +303,8 @@ os_file_get_last_error( return(OS_FILE_NOT_FOUND); } else if (err == EEXIST) { return(OS_FILE_ALREADY_EXISTS); + } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) { + return(OS_FILE_PATH_ERROR); } else { return(100 + err); } @@ -352,7 +354,8 @@ os_file_handle_error( return(TRUE); - } else if (err == OS_FILE_ALREADY_EXISTS) { + } else if (err == OS_FILE_ALREADY_EXISTS + || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { @@ -456,7 +459,8 @@ os_file_handle_error_no_exit( return(TRUE); - } else if (err == OS_FILE_ALREADY_EXISTS) { + } else if (err == OS_FILE_ALREADY_EXISTS + || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index b43d00bda1c..3ec78c518fc 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1754,3 +1754,43 @@ rename table t3 to t1; ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150) set foreign_key_checks=1; drop table t2,t3; +create table t2 ( +a int, b char(10), filler char(10), primary key(a, b(2)) +) character set utf8 engine = innodb; +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t2 ( +a int, b char(10), filler char(10), primary key(a, b(2)) +) character set ucs2 engine = innodb; +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +a hex(b) +1 61626364656667 +2 6465666768696A6B +6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 +7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 +update t1 set b = 'three' where a = 6; +drop table t1; +create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +a hex(b) +1 61626364656667 +2 6465666768696A6B +6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 +7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 +update t1 set b = 'three' where a = 6; +drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 03aa113c662..e2c12eedcae 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1329,4 +1329,40 @@ create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; rename table t3 to t1; set foreign_key_checks=1; drop table t2,t3; + +# tests for bug #14056 Column prefix index on UTF-8 primary key column causes 'Can't find record..' + +create table t2 ( + a int, b char(10), filler char(10), primary key(a, b(2)) +) character set utf8 engine = innodb; + +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t2 ( + a int, b char(10), filler char(10), primary key(a, b(2)) +) character set ucs2 engine = innodb; + +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; + +create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +update t1 set b = 'three' where a = 6; +drop table t1; +create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +update t1 set b = 'three' where a = 6; +drop table t1; # End of 4.1 tests diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b188cfcba21..d24587e23ea 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2015,6 +2015,22 @@ get_innobase_type_from_mysql_type( return(0); } +/*********************************************************************** +Writes an unsigned integer value < 64k to 2 bytes, in the little-endian +storage format. */ +inline +void +innobase_write_to_2_little_endian( +/*==============================*/ + byte* buf, /* in: where to store */ + ulint val) /* in: value to write, must be < 64k */ +{ + ut_a(val < 256 * 256); + + buf[0] = (byte)(val & 0xFF); + buf[1] = (byte)(val / 256); +} + /*********************************************************************** Stores a key value for a row to a buffer. */ @@ -2034,8 +2050,6 @@ ha_innobase::store_key_val_for_row( char* buff_start = buff; enum_field_types mysql_type; Field* field; - ulint blob_len; - byte* blob_data; ibool is_null; DBUG_ENTER("store_key_val_for_row"); @@ -2084,13 +2098,25 @@ ha_innobase::store_key_val_for_row( || mysql_type == FIELD_TYPE_BLOB || mysql_type == FIELD_TYPE_LONG_BLOB) { + CHARSET_INFO* cs; + ulint key_len; + ulint len; + ulint true_len; + int error=0; + ulint blob_len; + byte* blob_data; + ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + key_len = key_part->length; + if (is_null) { - buff += key_part->length + 2; + buff += key_len + 2; continue; } + + cs = field->charset(); blob_data = row_mysql_read_blob_ref(&blob_len, (byte*) (record @@ -2099,29 +2125,108 @@ ha_innobase::store_key_val_for_row( ut_a(get_field_offset(table, field) == key_part->offset); - if (blob_len > key_part->length) { - blob_len = key_part->length; + + true_len = blob_len; + + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + key_len / cs->mbmaxlen, + &error); + } + + /* All indexes on BLOB and TEXT are column prefix + indexes, and we may need to truncate the data to be + stored in the key value: */ + + if (true_len > key_len) { + true_len = key_len; } /* MySQL reserves 2 bytes for the length and the storage of the number is little-endian */ - ut_a(blob_len < 256); - *((byte*)buff) = (byte)blob_len; + innobase_write_to_2_little_endian( + (byte*)buff, true_len); buff += 2; - memcpy(buff, blob_data, blob_len); + memcpy(buff, blob_data, true_len); - buff += key_part->length; + /* Note that we always reserve the maximum possible + length of the BLOB prefix in the key value. */ + + buff += key_len; } else { + /* Here we handle all other data types except the + true VARCHAR, BLOB and TEXT. Note that the column + value we store may be also in a column prefix + index. */ + + CHARSET_INFO* cs; + ulint true_len; + ulint key_len; + const mysql_byte* src_start; + int error=0; + enum_field_types real_type; + + key_len = key_part->length; + if (is_null) { - buff += key_part->length; + buff += key_len; continue; } - memcpy(buff, record + key_part->offset, - key_part->length); - buff += key_part->length; + + src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; + + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != FIELD_TYPE_ENUM + && real_type != FIELD_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + key_len / cs->mbmaxlen, + &error); + } + } + + memcpy(buff, src_start, true_len); + buff += true_len; + + /* Pad the unused space with spaces. Note that no + padding is ever needed for UCS-2 because in MySQL, + all UCS2 characters are 2 bytes, as MySQL does not + support surrogate pairs, which are needed to represent + characters in the range U+10000 to U+10FFFF. */ + + if (true_len < key_len) { + ulint pad_len = key_len - true_len; + memset(buff, ' ', pad_len); + buff += pad_len; + } } } From e5598d2fad42a4f2a720f399f99ed680febac409 Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Mon, 16 Jan 2006 09:56:10 +0100 Subject: [PATCH 139/154] Windows Visual Studio 2003 fixes. --- VC++Files/client/mysqldump.vcproj | 27 +++++++++++ VC++Files/sql/mysqld.vcproj | 75 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/VC++Files/client/mysqldump.vcproj b/VC++Files/client/mysqldump.vcproj index b6a33596083..39b83fd46f3 100644 --- a/VC++Files/client/mysqldump.vcproj +++ b/VC++Files/client/mysqldump.vcproj @@ -226,6 +226,33 @@ PreprocessorDefinitions=""/> + + + + + + + + + + + diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj index 49bf74ae5a2..d5a10db380a 100644 --- a/VC++Files/sql/mysqld.vcproj +++ b/VC++Files/sql/mysqld.vcproj @@ -3744,6 +3744,81 @@ PreprocessorDefinitions=""/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Mon, 16 Jan 2006 12:17:30 +0100 Subject: [PATCH 140/154] BUG#6554 Problem Building MySql on Fedora Core 3 - Remove the local static var --- sql/ha_berkeley.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index b307b3a4b75..4ee844ac719 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -336,8 +336,9 @@ void berkeley_cleanup_log_files(void) ** Berkeley DB tables *****************************************************************************/ +static const char *bdb_bas_exts[]= { ha_berkeley_ext, NullS }; const char **ha_berkeley::bas_ext() const -{ static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; } +{ return bdb_bas_exts; } static int From 708f9b3ceb0eb4e19cb83e53c81dee85bb72aadb Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Mon, 16 Jan 2006 14:32:43 +0300 Subject: [PATCH 141/154] Changes from the innodb-5.0-ss115 snapshot. Fixed bugs: BUG#15991: "innodb-file-per-table + symlink database + rename = crash" BUG#15650: "DELETE with LEFT JOIN crashes server" BUG#15308: "Problem of Order with Enum Column in Primary Key" BUG#14189: "VARBINARY and BINARY variables: trailing space ignored" --- innobase/include/data0type.h | 3 +- innobase/include/data0type.ic | 39 ++- innobase/include/lock0lock.h | 20 +- innobase/include/os0file.h | 5 +- innobase/include/row0mysql.h | 5 +- innobase/lock/lock0lock.c | 71 +++- innobase/os/os0file.c | 112 ++++--- innobase/row/row0ins.c | 9 + innobase/row/row0mysql.c | 26 +- innobase/row/row0sel.c | 12 +- innobase/trx/trx0trx.c | 3 +- mysql-test/r/innodb.result | 332 ++++++++++++++++++- mysql-test/r/innodb_unsafe_binlog.result | 48 +++ mysql-test/t/innodb.test | 215 +++++++++++- mysql-test/t/innodb_unsafe_binlog-master.opt | 1 + mysql-test/t/innodb_unsafe_binlog.test | 67 ++++ sql/ha_innodb.cc | 164 +++++---- 17 files changed, 949 insertions(+), 183 deletions(-) create mode 100644 mysql-test/r/innodb_unsafe_binlog.result create mode 100644 mysql-test/t/innodb_unsafe_binlog-master.opt create mode 100644 mysql-test/t/innodb_unsafe_binlog.test diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index 7e9692eca5a..30c0f732c34 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -13,6 +13,7 @@ Created 1/16/1996 Heikki Tuuri extern ulint data_mysql_default_charset_coll; #define DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL 8 +#define DATA_MYSQL_BINARY_CHARSET_COLL 63 /* SQL data type struct */ typedef struct dtype_struct dtype_t; @@ -311,7 +312,7 @@ dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ - dtype_t* type); /* in: type */ + const dtype_t* type); /* in: type */ /*************************************************************************** Returns the size of a fixed size data type, 0 if not a fixed size type. */ UNIV_INLINE diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index d4a7b3c64b8..ad0f02fa63d 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -188,26 +188,35 @@ dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ - dtype_t* type) /* in: type */ + const dtype_t* type) /* in: type */ { - if (type->mtype == DATA_CHAR - || type->mtype == DATA_VARCHAR - || type->mtype == DATA_BINARY - || type->mtype == DATA_FIXBINARY - || type->mtype == DATA_MYSQL - || type->mtype == DATA_VARMYSQL - || (type->mtype == DATA_BLOB - && (type->prtype & DATA_BINARY_TYPE) == 0)) { - + switch (type->mtype) { + case DATA_FIXBINARY: + case DATA_BINARY: + if (UNIV_UNLIKELY(dtype_get_charset_coll(type->prtype) + == DATA_MYSQL_BINARY_CHARSET_COLL)) { + /* Starting from 5.0.18, do not pad + VARBINARY or BINARY columns. */ + return(ULINT_UNDEFINED); + } + /* Fall through */ + case DATA_CHAR: + case DATA_VARCHAR: + case DATA_MYSQL: + case DATA_VARMYSQL: /* Space is the padding character for all char and binary strings, and starting from 5.0.3, also for TEXT strings. */ - return((ulint)' '); + return(0x20); + case DATA_BLOB: + if ((type->prtype & DATA_BINARY_TYPE) == 0) { + return(0x20); + } + /* Fall through */ + default: + /* No padding specified */ + return(ULINT_UNDEFINED); } - - /* No padding specified */ - - return(ULINT_UNDEFINED); } /************************************************************************** diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index 20b1f1d7145..86e579bc007 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -64,14 +64,6 @@ lock_clust_rec_some_has_impl( dict_index_t* index, /* in: clustered index */ const ulint* offsets);/* in: rec_get_offsets(rec, index) */ /***************************************************************** -Resets the lock bits for a single record. Releases transactions -waiting for lock requests here. */ - -void -lock_rec_reset_and_release_wait( -/*============================*/ - rec_t* rec); /* in: record whose locks bits should be reset */ -/***************************************************************** Makes a record to inherit the locks of another record as gap type locks, but does not reset the lock bits of the other record. Also waiting lock requests on rec are inherited as GRANTED gap locks. */ @@ -427,6 +419,18 @@ lock_is_on_table( /*=============*/ /* out: TRUE if there are lock(s) */ dict_table_t* table); /* in: database table in dictionary cache */ +/***************************************************************** +Removes a granted record lock of a transaction from the queue and grants +locks to other transactions waiting in the queue if they now are entitled +to a lock. */ + +void +lock_rec_unlock( +/*============*/ + trx_t* trx, /* in: transaction that has set a record + lock */ + rec_t* rec, /* in: record */ + ulint lock_mode); /* in: LOCK_S or LOCK_X */ /************************************************************************* Releases a table lock. Releases possible other transactions waiting for this lock. */ diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 02a38dd49ef..d5bc5a2b115 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -91,9 +91,10 @@ log. */ #define OS_FILE_NOT_FOUND 71 #define OS_FILE_DISK_FULL 72 #define OS_FILE_ALREADY_EXISTS 73 -#define OS_FILE_AIO_RESOURCES_RESERVED 74 /* wait for OS aio resources +#define OS_FILE_PATH_ERROR 74 +#define OS_FILE_AIO_RESOURCES_RESERVED 75 /* wait for OS aio resources to become available again */ -#define OS_FILE_ERROR_NOT_SPECIFIED 75 +#define OS_FILE_ERROR_NOT_SPECIFIED 76 /* Types for aio operations */ #define OS_FILE_READ 10 diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index b5da4634d98..7d8740db044 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -250,8 +250,9 @@ trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, and also under prebuilt->clust_pcur. Currently, this is only used and tested in the case of an UPDATE or a DELETE statement, where the row lock is of the -LOCK_X type. -Thus, this implements a 'mini-rollback' that releases the latest record +LOCK_X or LOCK_S type. + +Thus, this implements a 'mini-rollback' that releases the latest record locks we set. */ int diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 7844991613f..06475c8ef7e 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -2392,7 +2392,7 @@ lock_rec_free_all_from_discard_page( /***************************************************************** Resets the lock bits for a single record. Releases transactions waiting for lock requests here. */ - +static void lock_rec_reset_and_release_wait( /*============================*/ @@ -3760,6 +3760,75 @@ lock_table_dequeue( /*=========================== LOCK RELEASE ==============================*/ +/***************************************************************** +Removes a granted record lock of a transaction from the queue and grants +locks to other transactions waiting in the queue if they now are entitled +to a lock. */ + +void +lock_rec_unlock( +/*============*/ + trx_t* trx, /* in: transaction that has set a record + lock */ + rec_t* rec, /* in: record */ + ulint lock_mode) /* in: LOCK_S or LOCK_X */ +{ + lock_t* lock; + lock_t* release_lock = NULL; + ulint heap_no; + + ut_ad(trx && rec); + + mutex_enter(&kernel_mutex); + + heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); + + lock = lock_rec_get_first(rec); + + /* Find the last lock with the same lock_mode and transaction + from the record. */ + + while (lock != NULL) { + if (lock->trx == trx && lock_get_mode(lock) == lock_mode) { + release_lock = lock; + ut_a(!lock_get_wait(lock)); + } + + lock = lock_rec_get_next(rec, lock); + } + + /* If a record lock is found, release the record lock */ + + if (UNIV_LIKELY(release_lock != NULL)) { + lock_rec_reset_nth_bit(release_lock, heap_no); + } else { + mutex_exit(&kernel_mutex); + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: unlock row could not find a %lu mode lock on the record\n", + (ulong)lock_mode); + + return; + } + + /* Check if we can now grant waiting lock requests */ + + lock = lock_rec_get_first(rec); + + while (lock != NULL) { + if (lock_get_wait(lock) + && !lock_rec_has_to_wait_in_queue(lock)) { + + /* Grant the lock */ + lock_grant(lock); + } + + lock = lock_rec_get_next(rec, lock); + } + + mutex_exit(&kernel_mutex); +} + /************************************************************************* Releases a table lock. Releases possible other transactions waiting for this lock. */ diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 20a3303d12d..3b8f7576049 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -160,15 +160,12 @@ time_t os_last_printout; ibool os_has_said_disk_full = FALSE; -/* The mutex protecting the following counts of pending pread and pwrite -operations */ +/* The mutex protecting the following counts of pending I/O operations */ static os_mutex_t os_file_count_mutex; ulint os_file_n_pending_preads = 0; ulint os_file_n_pending_pwrites = 0; - -/* These are not protected by any mutex */ -ulint os_n_pending_writes = 0; -ulint os_n_pending_reads = 0; +ulint os_n_pending_writes = 0; +ulint os_n_pending_reads = 0; /*************************************************************************** Gets the operating system version. Currently works only on Windows. */ @@ -314,6 +311,8 @@ os_file_get_last_error( return(OS_FILE_NOT_FOUND); } else if (err == EEXIST) { return(OS_FILE_ALREADY_EXISTS); + } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) { + return(OS_FILE_PATH_ERROR); } else { return(100 + err); } @@ -363,7 +362,8 @@ os_file_handle_error( return(TRUE); - } else if (err == OS_FILE_ALREADY_EXISTS) { + } else if (err == OS_FILE_ALREADY_EXISTS + || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { @@ -467,7 +467,8 @@ os_file_handle_error_no_exit( return(TRUE); - } else if (err == OS_FILE_ALREADY_EXISTS) { + } else if (err == OS_FILE_ALREADY_EXISTS + || err == OS_FILE_PATH_ERROR) { return(FALSE); } else { @@ -1905,12 +1906,14 @@ os_file_pread( #if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD) os_mutex_enter(os_file_count_mutex); os_file_n_pending_preads++; + os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); n_bytes = pread(file, buf, (ssize_t)n, offs); os_mutex_enter(os_file_count_mutex); os_file_n_pending_preads--; + os_n_pending_reads--; os_mutex_exit(os_file_count_mutex); return(n_bytes); @@ -1920,6 +1923,10 @@ os_file_pread( ssize_t ret; ulint i; + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads++; + os_mutex_exit(os_file_count_mutex); + /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; @@ -1928,15 +1935,17 @@ os_file_pread( ret_offset = lseek(file, offs, SEEK_SET); if (ret_offset < 0) { - os_mutex_exit(os_file_seek_mutexes[i]); - - return(-1); + ret = -1; + } else { + ret = read(file, buf, (ssize_t)n); } - - ret = read(file, buf, (ssize_t)n); os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads--; + os_mutex_exit(os_file_count_mutex); + return(ret); } #endif @@ -1981,12 +1990,14 @@ os_file_pwrite( #if defined(HAVE_PWRITE) && !defined(HAVE_BROKEN_PREAD) os_mutex_enter(os_file_count_mutex); os_file_n_pending_pwrites++; + os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); ret = pwrite(file, buf, (ssize_t)n, offs); os_mutex_enter(os_file_count_mutex); os_file_n_pending_pwrites--; + os_n_pending_writes--; os_mutex_exit(os_file_count_mutex); # ifdef UNIV_DO_FLUSH @@ -2008,6 +2019,10 @@ os_file_pwrite( off_t ret_offset; ulint i; + os_mutex_enter(os_file_count_mutex); + os_n_pending_writes++; + os_mutex_exit(os_file_count_mutex); + /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; @@ -2016,9 +2031,9 @@ os_file_pwrite( ret_offset = lseek(file, offs, SEEK_SET); if (ret_offset < 0) { - os_mutex_exit(os_file_seek_mutexes[i]); + ret = -1; - return(-1); + goto func_exit; } ret = write(file, buf, (ssize_t)n); @@ -2036,8 +2051,13 @@ os_file_pwrite( } # endif /* UNIV_DO_FLUSH */ +func_exit: os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_writes--; + os_mutex_exit(os_file_count_mutex); + return(ret); } #endif @@ -2082,9 +2102,13 @@ try_again: low = (DWORD) offset; high = (DWORD) offset_high; + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads++; + os_mutex_exit(os_file_count_mutex); + /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; - + os_mutex_enter(os_file_seek_mutexes[i]); ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); @@ -2093,17 +2117,21 @@ try_again: os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads--; + os_mutex_exit(os_file_count_mutex); + goto error_handling; } - os_n_pending_reads++; - ret = ReadFile(file, buf, (DWORD) n, &len, NULL); - os_n_pending_reads--; - os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads--; + os_mutex_exit(os_file_count_mutex); + if (ret && len == n) { return(TRUE); } @@ -2114,12 +2142,8 @@ try_again: os_bytes_read_since_printout += n; try_again: - os_n_pending_reads++; - ret = os_file_pread(file, buf, n, offset, offset_high); - os_n_pending_reads--; - if ((ulint)ret == n) { return(TRUE); @@ -2193,6 +2217,10 @@ try_again: low = (DWORD) offset; high = (DWORD) offset_high; + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads++; + os_mutex_exit(os_file_count_mutex); + /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; @@ -2204,17 +2232,21 @@ try_again: os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads--; + os_mutex_exit(os_file_count_mutex); + goto error_handling; } - os_n_pending_reads++; - ret = ReadFile(file, buf, (DWORD) n, &len, NULL); - os_n_pending_reads--; - os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_reads--; + os_mutex_exit(os_file_count_mutex); + if (ret && len == n) { return(TRUE); } @@ -2225,12 +2257,8 @@ try_again: os_bytes_read_since_printout += n; try_again: - os_n_pending_reads++; - ret = os_file_pread(file, buf, n, offset, offset_high); - os_n_pending_reads--; - if ((ulint)ret == n) { return(TRUE); @@ -2310,6 +2338,10 @@ retry: low = (DWORD) offset; high = (DWORD) offset_high; + os_mutex_enter(os_file_count_mutex); + os_n_pending_writes++; + os_mutex_exit(os_file_count_mutex); + /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; @@ -2321,6 +2353,10 @@ retry: os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_writes--; + os_mutex_exit(os_file_count_mutex); + ut_print_timestamp(stderr); fprintf(stderr, @@ -2335,12 +2371,8 @@ retry: return(FALSE); } - os_n_pending_writes++; - ret = WriteFile(file, buf, (DWORD) n, &len, NULL); - os_n_pending_writes--; - /* Always do fsync to reduce the probability that when the OS crashes, a database page is only partially physically written to disk. */ @@ -2352,6 +2384,10 @@ retry: os_mutex_exit(os_file_seek_mutexes[i]); + os_mutex_enter(os_file_count_mutex); + os_n_pending_writes--; + os_mutex_exit(os_file_count_mutex); + if (ret && len == n) { return(TRUE); @@ -2402,11 +2438,7 @@ retry: #else ssize_t ret; - os_n_pending_writes++; - ret = os_file_pwrite(file, buf, n, offset, offset_high); - - os_n_pending_writes--; if ((ulint)ret == n) { diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 32aa0385596..be1a48a4b46 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -549,6 +549,15 @@ row_ins_cascade_calc_update_vec( default: ut_error; case 1: + if (UNIV_UNLIKELY( + dtype_get_charset_coll( + dtype_get_prtype(type)) + == DATA_MYSQL_BINARY_CHARSET_COLL)) { + /* Do not pad BINARY + columns. */ + return(ULINT_UNDEFINED); + } + /* space=0x20 */ memset(pad_start, 0x20, pad_end - pad_start); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 723e305b2ab..937056c300e 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1436,8 +1436,9 @@ trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, and also under prebuilt->clust_pcur. Currently, this is only used and tested in the case of an UPDATE or a DELETE statement, where the row lock is of the -LOCK_X type. -Thus, this implements a 'mini-rollback' that releases the latest record +LOCK_X or LOCK_S type. + +Thus, this implements a 'mini-rollback' that releases the latest record locks we set. */ int @@ -1474,7 +1475,14 @@ row_unlock_for_mysql( index = btr_pcur_get_btr_cur(pcur)->index; - if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + if (UNIV_UNLIKELY(index == NULL)) { + fprintf(stderr, +"InnoDB: Error: Index is not set for persistent cursor.\n"); + ut_print_buf(stderr, (const byte*)pcur, sizeof(btr_pcur_t)); + ut_error; + } + + if (trx_new_rec_locks_contain(trx, index)) { mtr_start(&mtr); @@ -1486,11 +1494,7 @@ row_unlock_for_mysql( rec = btr_pcur_get_rec(pcur); - mutex_enter(&kernel_mutex); - - lock_rec_reset_and_release_wait(rec); - - mutex_exit(&kernel_mutex); + lock_rec_unlock(trx, rec, prebuilt->select_lock_type); mtr_commit(&mtr); @@ -1520,11 +1524,7 @@ row_unlock_for_mysql( rec = btr_pcur_get_rec(clust_pcur); - mutex_enter(&kernel_mutex); - - lock_rec_reset_and_release_wait(rec); - - mutex_exit(&kernel_mutex); + lock_rec_unlock(trx, rec, prebuilt->select_lock_type); mtr_commit(&mtr); } diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 1b66f14f5d7..d25023dc6be 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2771,8 +2771,8 @@ row_sel_get_clust_rec_for_mysql( func_exit: *out_rec = clust_rec; - if (prebuilt->select_lock_type == LOCK_X) { - /* We may use the cursor in update: store its position */ + if (prebuilt->select_lock_type != LOCK_NONE) { + /* We may use the cursor in unlock: store its position */ btr_pcur_store_position(prebuilt->clust_pcur, mtr); } @@ -3972,12 +3972,12 @@ got_row: /* We have an optimization to save CPU time: if this is a consistent read on a unique condition on the clustered index, then we do not store the pcur position, because any fetch next or prev will anyway - return 'end of file'. An exception is the MySQL HANDLER command - where the user can move the cursor with PREV or NEXT even after - a unique search. */ + return 'end of file'. Exceptions are locking reads and the MySQL + HANDLER command where the user can move the cursor with PREV or NEXT + even after a unique search. */ if (!unique_search_from_clust_index - || prebuilt->select_lock_type == LOCK_X + || prebuilt->select_lock_type != LOCK_NONE || prebuilt->used_in_HANDLER) { /* Inside an update always store the cursor position */ diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 090057f5d46..2637b28ef90 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -794,7 +794,8 @@ trx_commit_off_kernel( in trx sys header if MySQL binlogging is on or the database server is a MySQL replication slave */ - if (trx->mysql_log_file_name) { + if (trx->mysql_log_file_name + && trx->mysql_log_file_name[0] != '\0') { trx_sys_update_mysql_binlog_offset( trx->mysql_log_file_name, trx->mysql_log_offset, diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index dcff72ba7c0..973ad72042e 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2718,6 +2718,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +a hex(b) hex(c) filler +1 61626364656667 61626364656667 boo +4 D0B1 D0B1 eight +4 5B 5B five +4 E880BD E880BD four +4 E880BDD0B1E880BD E880BDD0B1E880BD seven +4 E880BDE880BD E880BDE880BD six +3 71727374757677 71727374757677 three +2 696A6B696C6D6E 696A6B696C6D6E two +select a,hex(b),hex(c),filler from t2 order by filler; +a hex(b) hex(c) filler +4 05630563 05630563 email +4 0563 0563 email +4 05612020 05612020 email +4 01FC 01FC email +4 0120 0120 email +4 00640065 00640065 email +4 00E400E50068 00E400E50068 email +4 0000E400 0000E400 email +4 0000563001FC0563 0000563001FC0563 email +1 0061006200630064006500660067 0061006200630064006500660067 one +3 0071007200730074007500760077 0071007200730074007500760077 three +2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two drop table t1; drop table t2; create table t1 ( @@ -2746,6 +2772,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +a hex(b) hex(c) filler +1 61626364656667 61626364656667 boo +4 D0B1 D0B1 eight +4 5B 5B five +4 E880BD E880BD four +4 E880BDD0B1E880BD E880BDD0B1E880BD seven +4 E880BDE880BD E880BDE880BD six +3 71727374757677 71727374757677 three +2 696A6B696C6D6E 696A6B696C6D6E two +select a,hex(b),hex(c),filler from t2 order by filler; +a hex(b) hex(c) filler +4 05630563 05630563 email +4 0563 0563 email +4 05612020 05612020 email +4 01FC 01FC email +4 0120 0120 email +4 00640065 00640065 email +4 00E400E50068 00E400E50068 email +4 0000E400 0000E400 email +4 0000563001FC0563 0000563001FC0563 email +1 0061006200630064006500660067 0061006200630064006500660067 one +3 0071007200730074007500760077 0071007200730074007500760077 three +2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two drop table t1; drop table t2; create table t1 ( @@ -2774,6 +2826,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +a hex(b) hex(c) filler +1 61626364656667 61626364656667 boo +4 D0B1 D0B1 eight +4 5B 5B five +4 E880BD E880BD four +4 E880BDD0B1E880BD E880BDD0B1E880BD seven +4 E880BDE880BD E880BDE880BD six +3 71727374757677 71727374757677 three +2 696A6B696C6D6E 696A6B696C6D6E two +select a,hex(b),hex(c),filler from t2 order by filler; +a hex(b) hex(c) filler +4 0120 0120 email +4 01FC 01FC email +4 0563 0563 email +4 0000563001FC0563 0000563001FC0563 email +4 0000E400 0000E400 email +4 00640065 00640065 email +4 00E400E50068 00E400E50068 email +4 05612020 05612020 email +4 05630563 05630563 email +1 0061006200630064006500660067 0061006200630064006500660067 one +3 0071007200730074007500760077 0071007200730074007500760077 three +2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two drop table t1; drop table t2; create table t1 ( @@ -2798,6 +2876,28 @@ insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +a hex(b) hex(c) filler +1 61626364656667 61626364656667 boo +4 D0B1 D0B1 eight +4 5B 5B five +4 E880BD E880BD four +3 71727374757677 71727374757677 three +2 696A6B696C6D6E 696A6B696C6D6E two +select a,hex(b),hex(c),filler from t2 order by filler; +a hex(b) hex(c) filler +4 0000E400 0000E400 email +4 00640065 00640065 email +4 00E400E50068 00E400E50068 email +4 0120 0120 email +4 01FC 01FC email +4 05612020 05612020 email +4 0563 0563 email +1 61626364656667 61626364656667 one +3 71727374757677 71727374757677 three +2 696A6B696C6D6E 696A6B696C6D6E two drop table t1; drop table t2; commit; @@ -2833,19 +2933,6 @@ rename table t3 to t1; ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150) set foreign_key_checks=1; drop table t2,t3; -create table t1 (a varchar(255) character set utf8, -b varchar(255) character set utf8, -c varchar(255) character set utf8, -d varchar(255) character set utf8, -key (a,b,c,d)) engine=innodb; -drop table t1; -create table t1 (a varchar(255) character set utf8, -b varchar(255) character set utf8, -c varchar(255) character set utf8, -d varchar(255) character set utf8, -e varchar(255) character set utf8, -key (a,b,c,d,e)) engine=innodb; -ERROR 42000: Specified key was too long; max key length is 3072 bytes create table t1(a int primary key) row_format=redundant engine=innodb; create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb; create table t3(a int primary key) row_format=compact engine=innodb; @@ -2875,4 +2962,221 @@ truncate t4; truncate t1; truncate t3; drop table t4,t3,t2,t1; -End of 5.0 tests +create table t1 (a varchar(255) character set utf8, +b varchar(255) character set utf8, +c varchar(255) character set utf8, +d varchar(255) character set utf8, +key (a,b,c,d)) engine=innodb; +drop table t1; +create table t1 (a varchar(255) character set utf8, +b varchar(255) character set utf8, +c varchar(255) character set utf8, +d varchar(255) character set utf8, +e varchar(255) character set utf8, +key (a,b,c,d,e)) engine=innodb; +ERROR 42000: Specified key was too long; max key length is 3072 bytes +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; +insert into t1 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 1 +insert into t2 values (0x41),(0x4120); +insert into t3 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A ' for key 1 +insert into t3 values (0x41),(0x4100); +insert into t4 values (0x41),(0x4120),(0x4100); +ERROR 23000: Duplicate entry 'A' for key 1 +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +hex(s1) +41 +4100 +4120 +select hex(s1) from t2; +hex(s1) +4100 +4120 +select hex(s1) from t3; +hex(s1) +4100 +41 +select hex(s1) from t4; +hex(s1) +4100 +41 +drop table t1,t2,t3,t4; +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +insert into t2 values(0x42); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +hex(s1) +4100 +update t1 set s1=0x12 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x12345678 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x123457 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +hex(s1) +1220 +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +hex(s1) +1200 +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +hex(s1) +4200 +delete from t1 where a=1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a=2; +update t2 set s1=0x4120; +delete from t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +delete from t1 where a!=3; +select a,hex(s1) from t1; +a hex(s1) +3 4120 +select hex(s1) from t2; +hex(s1) +4120 +drop table t2,t1; +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +hex(s1) +41 +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +hex(s1) +12 +delete from t1 where a=1; +delete from t1 where a=2; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) +select a,hex(s1) from t1; +a hex(s1) +2 12 +select hex(s1) from t2; +hex(s1) +12 +drop table t2,t1; +CREATE TABLE t1 ( +ind enum('0','1','2') NOT NULL default '0', +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +ind enum('0','1','2') NOT NULL default '0', +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; +INSERT INTO t1 VALUES ('1', ''),('2', ''); +INSERT INTO t2 VALUES ('1', ''),('2', ''); +SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1; +hex(ind) hex(string1) +31 +32 +SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1; +hex(ind) hex(string1) +0031 +0032 +drop table t1,t2; +CREATE TABLE t1 ( +ind set('0','1','2') NOT NULL default '0', +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +ind set('0','1','2') NOT NULL default '0', +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; +INSERT INTO t1 VALUES ('1', ''),('2', ''); +INSERT INTO t2 VALUES ('1', ''),('2', ''); +SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1; +hex(ind) hex(string1) +31 +32 +SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1; +hex(ind) hex(string1) +0031 +0032 +drop table t1,t2; +CREATE TABLE t1 ( +ind bit not null, +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( +ind bit not null, +string1 varchar(250) NOT NULL, +PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; +insert into t1 values(0,''),(1,''); +insert into t2 values(0,''),(1,''); +select hex(ind),hex(string1) from t1 order by string1; +hex(ind) hex(string1) +0 +1 +select hex(ind),hex(string1) from t2 order by string1; +hex(ind) hex(string1) +0 +1 +drop table t1,t2; +create table t2 ( +a int, b char(10), filler char(10), primary key(a, b(2)) +) character set utf8 engine = innodb; +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t2 ( +a int, b char(10), filler char(10), primary key(a, b(2)) +) character set ucs2 engine = innodb; +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +a hex(b) +1 61626364656667 +2 6465666768696A6B +6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 +7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 +update t1 set b = 'three' where a = 6; +drop table t1; +create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +a hex(b) +1 61626364656667 +2 6465666768696A6B +6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1 +7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2 +update t1 set b = 'three' where a = 6; +drop table t1; diff --git a/mysql-test/r/innodb_unsafe_binlog.result b/mysql-test/r/innodb_unsafe_binlog.result new file mode 100644 index 00000000000..4a4f0e0fae5 --- /dev/null +++ b/mysql-test/r/innodb_unsafe_binlog.result @@ -0,0 +1,48 @@ +drop table if exists t1,t2; +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +id f_id f +drop table t1,t2; +create table t1 (id int not null, f_id int not null, f int not null, +primary key(id),key(f_id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id),key(s_id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +delete ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null; +select ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null lock in share mode; +id f_id f +drop table t1,t2; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +a b +1 1 +2 2 +3 1 +4 2 +5 1 +6 2 +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 2 and b = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +commit; +drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 887d8193157..7ae2b6d4ac2 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1679,6 +1679,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +select a,hex(b),hex(c),filler from t2 order by filler; drop table t1; drop table t2; @@ -1708,6 +1712,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +select a,hex(b),hex(c),filler from t2 order by filler; drop table t1; drop table t2; @@ -1737,6 +1745,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven'); insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +select a,hex(b),hex(c),filler from t2 order by filler; drop table t1; drop table t2; @@ -1762,6 +1774,10 @@ insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven'); insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight'); insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten'); insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken'); +update t1 set filler = 'boo' where a = 1; +update t2 set filler ='email' where a = 4; +select a,hex(b),hex(c),filler from t1 order by filler; +select a,hex(b),hex(c),filler from t2 order by filler; drop table t1; drop table t2; commit; @@ -1816,23 +1832,6 @@ rename table t3 to t1; set foreign_key_checks=1; drop table t2,t3; -# -# Test that we can create a large (>1K) key -# -create table t1 (a varchar(255) character set utf8, - b varchar(255) character set utf8, - c varchar(255) character set utf8, - d varchar(255) character set utf8, - key (a,b,c,d)) engine=innodb; -drop table t1; ---error ER_TOO_LONG_KEY -create table t1 (a varchar(255) character set utf8, - b varchar(255) character set utf8, - c varchar(255) character set utf8, - d varchar(255) character set utf8, - e varchar(255) character set utf8, - key (a,b,c,d,e)) engine=innodb; - # test that foreign key errors are reported correctly (Bug #15550) create table t1(a int primary key) row_format=redundant engine=innodb; @@ -1867,4 +1866,184 @@ truncate t3; drop table t4,t3,t2,t1; ---echo End of 5.0 tests + +# +# Test that we can create a large (>1K) key +# +create table t1 (a varchar(255) character set utf8, + b varchar(255) character set utf8, + c varchar(255) character set utf8, + d varchar(255) character set utf8, + key (a,b,c,d)) engine=innodb; +drop table t1; +--error ER_TOO_LONG_KEY +create table t1 (a varchar(255) character set utf8, + b varchar(255) character set utf8, + c varchar(255) character set utf8, + d varchar(255) character set utf8, + e varchar(255) character set utf8, + key (a,b,c,d,e)) engine=innodb; + + +# test the padding of BINARY types and collations (Bug #14189) + +create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; +create table t2 (s1 binary(2),primary key (s1)) engine=innodb; +create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; + +insert into t1 values (0x41),(0x4120),(0x4100); +-- error 1062 +insert into t2 values (0x41),(0x4120),(0x4100); +insert into t2 values (0x41),(0x4120); +-- error 1062 +insert into t3 values (0x41),(0x4120),(0x4100); +insert into t3 values (0x41),(0x4100); +-- error 1062 +insert into t4 values (0x41),(0x4120),(0x4100); +insert into t4 values (0x41),(0x4100); +select hex(s1) from t1; +select hex(s1) from t2; +select hex(s1) from t3; +select hex(s1) from t4; +drop table t1,t2,t3,t4; + +create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; +create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); +-- error 1452 +insert into t2 values(0x42); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x123456 where a=2; +select hex(s1) from t2; +-- error 1451 +update t1 set s1=0x12 where a=1; +-- error 1451 +update t1 set s1=0x12345678 where a=1; +-- error 1451 +update t1 set s1=0x123457 where a=1; +update t1 set s1=0x1220 where a=1; +select hex(s1) from t2; +update t1 set s1=0x1200 where a=1; +select hex(s1) from t2; +update t1 set s1=0x4200 where a=1; +select hex(s1) from t2; +-- error 1451 +delete from t1 where a=1; +delete from t1 where a=2; +update t2 set s1=0x4120; +-- error 1451 +delete from t1; +delete from t1 where a!=3; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; + +create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; +create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; + +insert into t1 values(1,0x4100),(2,0x41); +insert into t2 values(0x41); +select hex(s1) from t2; +update t1 set s1=0x1234 where a=1; +select hex(s1) from t2; +update t1 set s1=0x12 where a=2; +select hex(s1) from t2; +delete from t1 where a=1; +-- error 1451 +delete from t1 where a=2; +select a,hex(s1) from t1; +select hex(s1) from t2; + +drop table t2,t1; +# +# Test cases for bug #15308 Problem of Order with Enum Column in Primary Key +# +CREATE TABLE t1 ( + ind enum('0','1','2') NOT NULL default '0', + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( + ind enum('0','1','2') NOT NULL default '0', + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; + +INSERT INTO t1 VALUES ('1', ''),('2', ''); +INSERT INTO t2 VALUES ('1', ''),('2', ''); +SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1; +SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1; +drop table t1,t2; + +CREATE TABLE t1 ( + ind set('0','1','2') NOT NULL default '0', + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( + ind set('0','1','2') NOT NULL default '0', + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; + +INSERT INTO t1 VALUES ('1', ''),('2', ''); +INSERT INTO t2 VALUES ('1', ''),('2', ''); +SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1; +SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1; +drop table t1,t2; + +CREATE TABLE t1 ( + ind bit not null, + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE t2 ( + ind bit not null, + string1 varchar(250) NOT NULL, + PRIMARY KEY (ind) +) ENGINE=InnoDB DEFAULT CHARSET=ucs2; +insert into t1 values(0,''),(1,''); +insert into t2 values(0,''),(1,''); +select hex(ind),hex(string1) from t1 order by string1; +select hex(ind),hex(string1) from t2 order by string1; +drop table t1,t2; + +# tests for bug #14056 Column prefix index on UTF-8 primary key column causes 'Can't find record..' + +create table t2 ( + a int, b char(10), filler char(10), primary key(a, b(2)) +) character set utf8 engine = innodb; + +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; +create table t2 ( + a int, b char(10), filler char(10), primary key(a, b(2)) +) character set ucs2 engine = innodb; + +insert into t2 values (1,'abcdefg','one'); +insert into t2 values (2,'ijkilmn','two'); +insert into t2 values (3, 'qrstuvw','three'); +update t2 set a=5, filler='booo' where a=1; +drop table t2; + +create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +update t1 set b = 'three' where a = 6; +drop table t1; +create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8; +insert into t1 values(1,'abcdefg'),(2,'defghijk'); +insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1); +insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2); +select a,hex(b) from t1 order by b; +update t1 set b = 'three' where a = 6; +drop table t1; diff --git a/mysql-test/t/innodb_unsafe_binlog-master.opt b/mysql-test/t/innodb_unsafe_binlog-master.opt new file mode 100644 index 00000000000..503c8457b2c --- /dev/null +++ b/mysql-test/t/innodb_unsafe_binlog-master.opt @@ -0,0 +1 @@ +--innodb_locks_unsafe_for_binlog=true diff --git a/mysql-test/t/innodb_unsafe_binlog.test b/mysql-test/t/innodb_unsafe_binlog.test new file mode 100644 index 00000000000..fa240eb7608 --- /dev/null +++ b/mysql-test/t/innodb_unsafe_binlog.test @@ -0,0 +1,67 @@ +-- source include/have_innodb.inc +# +# Note that these tests uses a innodb_locks_unsafe_for_binlog option. +# +# Test cases for a bug #15650 DELETE with LEFT JOIN crashes server +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +drop table t1,t2; + +create table t1 (id int not null, f_id int not null, f int not null, +primary key(id),key(f_id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id),key(s_id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +delete ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null; +select ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null lock in share mode; +drop table t1,t2; + +# +# Test case for unlock row bug where unlock releases all locks granted for +# a row. Only the latest lock should be released. +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update +# +--error 1205 +select * from t1 where a = 2 and b = 2 for update; +connection a; +commit; +connection b; +commit; +drop table t1; +disconnect a; +disconnect b; + diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 744bd242fca..4ae0bb52d17 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1218,7 +1218,7 @@ innobase_init(void) "innobase_buffer_pool_size can't be over 4GB" " on 32-bit systems"); - goto error; + DBUG_RETURN(0); } if (innobase_log_file_size > UINT_MAX32) { @@ -1226,7 +1226,7 @@ innobase_init(void) "innobase_log_file_size can't be over 4GB" " on 32-bit systems"); - goto error; + DBUG_RETURN(0); } } @@ -1391,6 +1391,7 @@ innobase_init(void) ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL == my_charset_latin1.number); + ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number); /* Store the latin1_swedish_ci character ordering table to InnoDB. For non-latin1_swedish_ci charsets we use the MySQL comparison functions, @@ -2847,8 +2848,6 @@ ha_innobase::store_key_val_for_row( char* buff_start = buff; enum_field_types mysql_type; Field* field; - ulint blob_len; - byte* blob_data; ibool is_null; DBUG_ENTER("store_key_val_for_row"); @@ -2903,14 +2902,18 @@ ha_innobase::store_key_val_for_row( ulint len; byte* data; ulint key_len; + ulint true_len; CHARSET_INFO* cs; int error=0; + key_len = key_part->length; + if (is_null) { - buff += key_part->length + 2; + buff += key_len + 2; continue; } + cs = field->charset(); lenlen = (ulint) (((Field_varstring*)field)->length_bytes); @@ -2920,32 +2923,33 @@ ha_innobase::store_key_val_for_row( + (ulint)get_field_offset(table, field)), lenlen); - /* In a column prefix index, we may need to truncate - the stored value: */ - - cs = key_part->field->charset(); + true_len = len; - if (cs->mbmaxlen > 1 && key_part->length > 0) { - key_len = (ulint) cs->cset->well_formed_len(cs, - (const char *) data, - (const char *) data + key_part->length, - key_part->length / cs->mbmaxlen, - &error); - } else { - key_len = key_part->length; + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) data, + (const char *) data + len, + key_len / cs->mbmaxlen, + &error); } - if (len > key_len) { - len = key_len; + /* In a column prefix index, we may need to truncate + the stored value: */ + + if (true_len > key_len) { + true_len = key_len; } /* The length in a key value is always stored in 2 bytes */ - row_mysql_store_true_var_len((byte*)buff, len, 2); + row_mysql_store_true_var_len((byte*)buff, true_len, 2); buff += 2; - memcpy(buff, data, len); + memcpy(buff, data, true_len); /* Note that we always reserve the maximum possible length of the true VARCHAR in the key value, though @@ -2953,7 +2957,7 @@ ha_innobase::store_key_val_for_row( actual data. The rest of the space was reset to zero in the bzero() call above. */ - buff += key_part->length; + buff += key_len; } else if (mysql_type == FIELD_TYPE_TINY_BLOB || mysql_type == FIELD_TYPE_MEDIUM_BLOB @@ -2963,58 +2967,66 @@ ha_innobase::store_key_val_for_row( CHARSET_INFO* cs; ulint key_len; ulint len; + ulint true_len; int error=0; + ulint blob_len; + byte* blob_data; ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); + key_len = key_part->length; + if (is_null) { - buff += key_part->length + 2; + buff += key_len + 2; continue; } + cs = field->charset(); + blob_data = row_mysql_read_blob_ref(&blob_len, (byte*) (record + (ulint)get_field_offset(table, field)), (ulint) field->pack_length()); + true_len = blob_len; + ut_a(get_field_offset(table, field) == key_part->offset); + /* For multi byte character sets we need to calculate + the true length of the key */ + + if (blob_len > 0 && cs->mbmaxlen > 1) { + true_len = (ulint) cs->cset->well_formed_len(cs, + (const char *) blob_data, + (const char *) blob_data + + blob_len, + key_len / cs->mbmaxlen, + &error); + } + /* All indexes on BLOB and TEXT are column prefix indexes, and we may need to truncate the data to be stored in the key value: */ - cs = key_part->field->charset(); - - if (cs->mbmaxlen > 1 && key_part->length > 0) { - key_len = (ulint) cs->cset->well_formed_len(cs, - (const char *) blob_data, - (const char *) blob_data - + key_part->length, - key_part->length / cs->mbmaxlen, - &error); - } else { - key_len = key_part->length; - } - - if (blob_len > key_len) { - blob_len = key_len; + if (true_len > key_len) { + true_len = key_len; } /* MySQL reserves 2 bytes for the length and the storage of the number is little-endian */ innobase_write_to_2_little_endian( - (byte*)buff, (ulint)blob_len); + (byte*)buff, true_len); buff += 2; - memcpy(buff, blob_data, blob_len); + memcpy(buff, blob_data, true_len); /* Note that we always reserve the maximum possible length of the BLOB prefix in the key value. */ - buff += key_part->length; + buff += key_len; } else { /* Here we handle all other data types except the true VARCHAR, BLOB and TEXT. Note that the column @@ -3022,38 +3034,64 @@ ha_innobase::store_key_val_for_row( index. */ CHARSET_INFO* cs; - ulint len; + ulint true_len; + ulint key_len; const mysql_byte* src_start; int error=0; + enum_field_types real_type; + + key_len = key_part->length; if (is_null) { - buff += key_part->length; + buff += key_len; continue; } - cs = key_part->field->charset(); src_start = record + key_part->offset; + real_type = field->real_type(); + true_len = key_len; - if (key_part->length > 0 && cs->mbmaxlen > 1) { - len = (ulint) cs->cset->well_formed_len(cs, - (const char *) src_start, - (const char *) src_start + key_part->length, - key_part->length / cs->mbmaxlen, - &error); - } else { - len = key_part->length; + /* Character set for the field is defined only + to fields whose type is string and real field + type is not enum or set. For these fields check + if character set is multi byte. */ + + if (real_type != FIELD_TYPE_ENUM + && real_type != FIELD_TYPE_SET + && ( mysql_type == MYSQL_TYPE_VAR_STRING + || mysql_type == MYSQL_TYPE_STRING)) { + + cs = field->charset(); + + /* For multi byte character sets we need to + calculate the true length of the key */ + + if (key_len > 0 && cs->mbmaxlen > 1) { + + true_len = (ulint) + cs->cset->well_formed_len(cs, + (const char *)src_start, + (const char *)src_start + + key_len, + key_len / cs->mbmaxlen, + &error); + } } - memcpy(buff, src_start, len); - buff+=len; + memcpy(buff, src_start, true_len); + buff += true_len; - /* Pad the unused space with spaces */ + /* Pad the unused space with spaces. Note that no + padding is ever needed for UCS-2 because in MySQL, + all UCS2 characters are 2 bytes, as MySQL does not + support surrogate pairs, which are needed to represent + characters in the range U+10000 to U+10FFFF. */ - if (len < key_part->length) { - len = key_part->length - len; - memset(buff, ' ', len); - buff+=len; + if (true_len < key_len) { + ulint pad_len = key_len - true_len; + memset(buff, ' ', pad_len); + buff += pad_len; } } } @@ -3770,9 +3808,8 @@ ha_innobase::delete_row( } /************************************************************************** -Removes a new lock set on a row. This can be called after a row has been read -in the processing of an UPDATE or a DELETE query, if the option -innodb_locks_unsafe_for_binlog is set. */ +Removes a new lock set on a row. This method does nothing unless the +option innodb_locks_unsafe_for_binlog is set.*/ void ha_innobase::unlock_row(void) @@ -3794,6 +3831,9 @@ ha_innobase::unlock_row(void) if (srv_locks_unsafe_for_binlog) { row_unlock_for_mysql(prebuilt, FALSE); } + + DBUG_VOID_RETURN; + } /********************************************************************** From 442dcf8be7133c368f3f7593e7ceb848c0d64d55 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Mon, 16 Jan 2006 15:23:02 +0300 Subject: [PATCH 142/154] Restore fix for bug #15108 (by ramil) erroneously erased by applying innodb-5.0-ss115 snapshot. --- sql/ha_innodb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4ae0bb52d17..c0f8559ab29 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1218,7 +1218,7 @@ innobase_init(void) "innobase_buffer_pool_size can't be over 4GB" " on 32-bit systems"); - DBUG_RETURN(0); + goto error; } if (innobase_log_file_size > UINT_MAX32) { @@ -1226,7 +1226,7 @@ innobase_init(void) "innobase_log_file_size can't be over 4GB" " on 32-bit systems"); - DBUG_RETURN(0); + goto error; } } From a1b2960a8abcaa6aa9696869f83435cd3121b47d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 16 Jan 2006 15:22:29 +0100 Subject: [PATCH 143/154] Post-review fix (BUG#14498). --- sql/sp_pcontext.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index bd2259cb6fb..2fd40159b6c 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -44,6 +44,15 @@ typedef struct sp_pvar #define SP_LAB_BEGIN 2 // Label at BEGIN #define SP_LAB_ITER 3 // Label at iteration control +/* + An SQL/PSM label. Can refer to the identifier used with the + "label_name:" construct which may precede some SQL/PSM statements, or + to an implicit implementation-dependent identifier which the parser + inserts before a high-level flow control statement such as + IF/WHILE/REPEAT/LOOP, when such statement is rewritten into + a combination of low-level jump/jump_if instructions and labels. +*/ + typedef struct sp_label { char *name; From 1b75cf8aa6495e65fea9eb833bd76581d91e8a9c Mon Sep 17 00:00:00 2001 From: "knielsen@mysql.com" <> Date: Mon, 16 Jan 2006 15:25:15 +0100 Subject: [PATCH 144/154] Two minor fixes to be able to run tests from within a Windows Max build directory. --- mysql-test/mysql-test-run.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 8ccd87fc7a8..35371bf32e7 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -922,11 +922,14 @@ sub executable_setup () { { $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", "$glob_basedir/bin"); - $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-nt", + $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", "$path_client_bindir/mysqld", "$path_client_bindir/mysqld-debug",); $path_language= mtr_path_exists("$glob_basedir/share/english/"); $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets"); + $exe_my_print_defaults= + mtr_exe_exists("$path_client_bindir/my_print_defaults"); } else { @@ -937,6 +940,8 @@ sub executable_setup () { $exe_im= mtr_exe_exists( "$glob_basedir/server-tools/instance-manager/mysqlmanager"); + $exe_my_print_defaults= + mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); } if ( $glob_use_embedded_server ) @@ -963,8 +968,6 @@ sub executable_setup () { $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); $exe_mysql_fix_system_tables= mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables"); - $exe_my_print_defaults= - mtr_script_exists("$glob_basedir/extra/my_print_defaults"); $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } From 5da306b57eea0bc41db438ea2bf4544421544cc6 Mon Sep 17 00:00:00 2001 From: "joerg@mysql.com" <> Date: Mon, 16 Jan 2006 17:23:39 +0100 Subject: [PATCH 145/154] extra/comp_err.c : Fix a merge error. --- extra/comp_err.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/comp_err.c b/extra/comp_err.c index 1083d029f4e..65fc131a5fc 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -542,6 +542,7 @@ static char *parse_default_language(char *str) fprintf(stderr, "Unexpected EOL: No short language name after the keyword\n"); DBUG_RETURN(0); + } /* reading the short language tag */ if (!(slang= get_word(&str))) @@ -877,7 +878,7 @@ static void usage(void) print_version(); printf("This software comes with ABSOLUTELY NO WARRANTY. " "This is free software,\n" - "and you are welcome to modify and redistribute it under the GPL license.\n" + "and you are welcome to modify and redistribute it under the GPL license.\n" "Usage:\n"); my_print_help(my_long_options); my_print_variables(my_long_options); From 5863337b8f5b07d0f043a406a36e9555350c6b58 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 16 Jan 2006 17:55:22 +0100 Subject: [PATCH 146/154] Post-merge fixes (BUG#14498) --- mysql-test/r/sp-code.result | 2 +- mysql-test/t/sp.test | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index e6c4ffe1731..943471c2261 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -49,7 +49,7 @@ Pos Instruction 9 set err@1 1 10 hreturn 5 11 cfetch c@0 n@4 -12 jump_if_not 15 isnull(n@4) +12 jump_if_not 15(17) isnull(n@4) 13 set nulls@2 (nulls@2 + 1) 14 jump 17 15 set count@3 (count@3 + 1) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7b311088090..b5751c6da63 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5230,7 +5230,9 @@ end| call bug14498_1()| call bug14498_2()| call bug14498_3()| -# QQ We can't call this at the moment, due to a known bug (BUG#14643) +# We couldn't call this before, due to a known bug (BUG#14643) +# QQ We still can't since the new set_case_expr instruction breaks +# the semantics of case; it won't crash, but will get the wrong result. #call bug14498_4()| call bug14498_5()| From f693473fff6e59014dc8d6f6d474d67ed346841f Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 16 Jan 2006 22:31:13 +0300 Subject: [PATCH 147/154] A test case for Bug#7670 "Loss of precision for some integer values stored into DOUBLE column" (Can't repeat) --- mysql-test/r/type_decimal.result | 13 +++++++++++++ mysql-test/t/type_decimal.test | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index d7f5f9fa328..df5abfe8ae3 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -772,3 +772,16 @@ productid zlevelprice 003trans 39.98 004trans 31.18 drop table t1, t2; +create table t1 (a double(53,0)); +insert into t1 values (9988317491112007680) ,(99883133042600208184115200); +select a from t1; +a +9988317491112007680 +99883133042600208184115200 +truncate t1; +insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); +select a from t1; +a +9988317491112007680 +99883133042600208184115200 +drop table t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 1f6310cb819..e06b828f9e6 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -376,3 +376,16 @@ insert INTO t2 SELECT * FROM t1; select * from t2; drop table t1, t2; + +# +# A test case for Bug#7670 "Loss of precision for some integer values stored +# into DOUBLE column": check that there is no truncation +# when inserting big integers into double columns. +# +create table t1 (a double(53,0)); +insert into t1 values (9988317491112007680) ,(99883133042600208184115200); +select a from t1; +truncate t1; +insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); +select a from t1; +drop table t1; From 41ff5c80daea1a52b33cff51d417a4127c9f7a27 Mon Sep 17 00:00:00 2001 From: "jani@a193-229-222-105.elisa-laajakaista.fi" <> Date: Mon, 16 Jan 2006 23:15:00 +0200 Subject: [PATCH 148/154] Changed condition similar to code in 4.1. --- sql/sql_handler.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e9e1e79daaf..1cd7778a053 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -421,12 +421,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already - if (cond && ((!cond->fixed && - cond->fix_fields(thd, &cond)) || cond->check_cols(1))) + if (cond) { if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - goto err0; + if ((!cond->fixed && + cond->fix_fields(thd, &cond)) || cond->check_cols(1)) + goto err0; } if (keyname) From 3d1675831169484000bbb783a36c3be0a19b8a96 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 00:28:00 +0300 Subject: [PATCH 149/154] A test case for Bug#6073 "ALTER TABLE minor glitch" (can't repeat) --- mysql-test/r/alter_table.result | 4 ++++ mysql-test/t/alter_table.test | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index f224a10c9bd..5c50b3cd79d 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -562,3 +562,7 @@ desc t1; Field Type Null Key Default Extra mycol int(10) NO 0 drop table t1; +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index f4245abfe86..cfa6182543b 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -412,3 +412,13 @@ create table t1 (mycol int(10) not null); alter table t1 alter column mycol set default 0; desc t1; drop table t1; + +# +# Bug#6073 "ALTER table minor glich": ALTER TABLE complains that an index +# without # prefix is not allowed for TEXT columns, while index +# is defined with prefix. +# +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; From 739ba76d646efe19d14e3aee068d92471fcf8f5a Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 01:03:03 +0300 Subject: [PATCH 150/154] A fix for Bug#13337 "ps test fails if configure wo/ usc2" --- mysql-test/r/ctype_ucs.result | 19 +++++++++++++++++++ mysql-test/r/ps.result | 19 ------------------- mysql-test/t/ctype_ucs.test | 14 ++++++++++++++ mysql-test/t/ps.test | 13 ------------- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 3ca56548de9..0e12ec88662 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -684,3 +684,22 @@ select f1 from t1 where f1 like 'a%'; f1 a drop table t1; +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +utext +lily +river +execute stmt using @param1; +utext +lily +river +select utext from t1 where utext like '%%'; +utext +lily +river +drop table t1; +deallocate prepare stmt; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index aa9ff083cbb..ba9336c20bb 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -639,25 +639,6 @@ execute stmt using @a, @b; ?=? 1 deallocate prepare stmt; -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -utext -lily -river -execute stmt using @param1; -utext -lily -river -select utext from t1 where utext like '%%'; -utext -lily -river -drop table t1; -deallocate prepare stmt; create table t1 (a int); prepare stmt from "select ??"; 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 '?' at line 1 diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 3b3c2c70f32..ed55287ca05 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -427,4 +427,18 @@ insert into t1 values('a'); create index t1f1 on t1(f1); select f1 from t1 where f1 like 'a%'; drop table t1; + +# +# Bug#9442 Set parameter make query fail if column character set is UCS2 +# +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +execute stmt using @param1; +select utext from t1 where utext like '%%'; +drop table t1; +deallocate prepare stmt; # End of 4.1 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 23eb2e11ae3..b0755d06414 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -665,19 +665,6 @@ set @b='CHRISTINE'; execute stmt using @a, @b; deallocate prepare stmt; # -# Bug#9442 Set parameter make query fail if column character set is UCS2 -# -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -execute stmt using @param1; -select utext from t1 where utext like '%%'; -drop table t1; -deallocate prepare stmt; -# # Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops # replication": check that errouneous queries with placeholders are not # allowed From 4fd615abdbf4049bf23fb4325ac2bdeaca2497a0 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 01:22:01 +0300 Subject: [PATCH 151/154] A post-merge fix. --- mysql-test/t/ctype_ucs.test | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index f2f872af9d0..04de13f8228 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -429,20 +429,6 @@ insert into t1 values('a'); create index t1f1 on t1(f1); select f1 from t1 where f1 like 'a%'; drop table t1; - -# -# Bug#9442 Set parameter make query fail if column character set is UCS2 -# -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -execute stmt using @param1; -select utext from t1 where utext like '%%'; -drop table t1; -deallocate prepare stmt; # End of 4.1 tests # From ba01e04a2cfc9a3d80dbc3bd5dd10eab4bbe8fa5 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 17 Jan 2006 12:48:48 +0100 Subject: [PATCH 152/154] Post-review fix. (BUG#15231) --- sql/sp_rcontext.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index c36c904f45d..215de01e657 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -220,7 +220,7 @@ sp_rcontext::find_handler(uint sql_errno, Only "exception conditions" are propagated to handlers in calling contexts. If no handler is found locally for a "completion condition" (warning or "not found") we will simply resume execution. - */ + */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level); From 8b243b3799b28145c3455fbfb68555fe49555a14 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 17 Jan 2006 19:02:42 +0100 Subject: [PATCH 153/154] Fix for connection not being added to connection pool if "disable_abort_on_error" was used. --- client/mysqltest.c | 13 +------------ mysql-test/r/mysqltest.result | 1 + mysql-test/t/mysqltest.test | 8 +++++++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 6a2a7b072de..ca28419fa4f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2143,19 +2143,8 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, *create_conn= 0; goto err; } - else - { - handle_no_error(q); - /* - Fail if there was no error but we expected it. - We also don't want to have connection in this case. - */ - mysql_close(con); - *create_conn= 0; - error= 1; - goto err; - } + handle_no_error(q); /* TODO: change this to 0 in future versions, but the 'kill' test relies on diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 067054510c2..df530eda285 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -362,6 +362,7 @@ OK mysqltest: In included file "./var/tmp/con.sql": At line 7: Connection limit exhausted - increase MAX_CONS in mysqltest.c mysqltest: In included file "./var/tmp/con.sql": At line 3: connection 'test_con1' not found in connection pool mysqltest: In included file "./var/tmp/con.sql": At line 2: Connection test_con1 already exists +connect(localhost,root,,test,MASTER_PORT,MASTER_SOCKET); Output from mysqltest-x.inc Output from mysqltest-x.inc Output from mysqltest-x.inc diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 5cf49185c30..e6dc4d356c2 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -910,7 +910,13 @@ select "a" as col1, "c" as col2; --error 1 --exec echo "source var/tmp/con.sql;" | $MYSQL_TEST 2>&1 - +# connect when "disable_abort_on_error" caused "connection not found" +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--disable_abort_on_error +connect (con1,localhost,root,,); +connection default; +connection con1; +--enable_abort_on_error # ---------------------------------------------------------------------------- # Test mysqltest arguments From 8d6c98ed90016e2b6a27f9dcd5bd8b9fb3959ef5 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 21:10:47 +0300 Subject: [PATCH 154/154] Bug#15206: "Misleading message "No data to FETCH": reword the misleading message. --- mysql-test/r/sp-error.result | 2 +- mysql-test/r/sp.result | 16 ++++++++-------- mysql-test/r/type_decimal.result | 13 ------------- mysql-test/r/variables.result | 4 ++-- mysql-test/r/view_grant.result | 8 ++++---- mysql-test/t/type_decimal.test | 12 ------------ sql/share/errmsg.txt | 4 ++-- 7 files changed, 17 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index d7bed7e88a7..9a148c3516e 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -535,7 +535,7 @@ fetch c into v; end| delete from t1| call bug7299()| -ERROR 02000: No data to FETCH +ERROR 02000: No data - zero rows fetched, selected, or processed drop procedure bug7299| create procedure bug9073() begin diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4c2f7b7f03b..19f3d033f53 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -522,7 +522,7 @@ delete from t1| create table t3 ( s char(16), d int)| call into_test4()| Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from t3| s d into4 NULL @@ -1787,10 +1787,10 @@ end| call bug1863(10)| Warnings: Note 1051 Unknown table 'temp_t1' -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed call bug1863(10)| Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from t4| f1 rc t3 2 0 NULL @@ -2084,10 +2084,10 @@ end| call bug4579_1()| call bug4579_1()| Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed call bug4579_1()| Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed drop procedure bug4579_1| drop procedure bug4579_2| drop table t3| @@ -2566,7 +2566,7 @@ call bug7743("OneWord")| var NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed call bug7743("anotherword")| var 2 @@ -2574,7 +2574,7 @@ call bug7743("AnotherWord")| var NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed drop procedure bug7743| drop table t4| delete from t3| @@ -4496,7 +4496,7 @@ After NOT FOUND condtition is triggered xid xdone 1 0 Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed call bug15231_3()| Result Missed it (correct) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index df5abfe8ae3..d7f5f9fa328 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -772,16 +772,3 @@ productid zlevelprice 003trans 39.98 004trans 31.18 drop table t1, t2; -create table t1 (a double(53,0)); -insert into t1 values (9988317491112007680) ,(99883133042600208184115200); -select a from t1; -a -9988317491112007680 -99883133042600208184115200 -truncate t1; -insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); -select a from t1; -a -9988317491112007680 -99883133042600208184115200 -drop table t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index df180218a09..4f6a6569443 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -537,10 +537,10 @@ select @@query_prealloc_size = @test; create table t1 (a int); select a into @x from t1; Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed show warnings; Level Code Message -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed drop table t1; set @@warning_count=1; ERROR HY000: Variable 'warning_count' is a read only variable diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index e2ee02351d7..ede69343a29 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -348,12 +348,12 @@ select * from v1; f2() NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from v2; f2() NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from v3; ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them select * from v4; @@ -394,12 +394,12 @@ select * from v3; f2() NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from v4; f2() NULL Warnings: -Warning 1329 No data to FETCH +Warning 1329 No data - zero rows fetched, selected, or processed select * from v5; ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them drop view v1, v2, v3, v4, v5; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index e06b828f9e6..07347322453 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -377,15 +377,3 @@ insert INTO t2 SELECT * FROM t1; select * from t2; drop table t1, t2; -# -# A test case for Bug#7670 "Loss of precision for some integer values stored -# into DOUBLE column": check that there is no truncation -# when inserting big integers into double columns. -# -create table t1 (a double(53,0)); -insert into t1 values (9988317491112007680) ,(99883133042600208184115200); -select a from t1; -truncate t1; -insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); -select a from t1; -drop table t1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 185b4326c5c..577173a36a1 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5175,8 +5175,8 @@ ER_SP_WRONG_NO_OF_FETCH_ARGS eng "Incorrect number of FETCH variables" ger "Falsche Anzahl von FETCH-Variablen" ER_SP_FETCH_NO_DATA 02000 - eng "No data to FETCH" - ger "Keine Daten mit FETCH abzuholen" + eng "No data - zero rows fetched, selected, or processed" + ger "Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet" ER_SP_DUP_PARAM 42000 eng "Duplicate parameter: %s" ger "Doppelter Parameter: %s"