diff options
56 files changed, 935 insertions, 197 deletions
diff --git a/client/Makefile.am b/client/Makefile.am index 24a4bece825..a9da284a753 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -17,7 +17,8 @@ # This file is public domain and comes with NO WARRANTY of any kind #AUTOMAKE_OPTIONS = nostdinc -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \ + $(openssl_includes) LIBS = @CLIENT_LIBS@ DEPLIB= ../libmysql/libmysqlclient.la LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB) @@ -36,6 +37,7 @@ mysqldump_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) mysqlimport_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) mysqltest_SOURCES= mysqltest.c ../mysys/my_getsystime.c mysqltest_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) +mysqltest_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c mysqlbinlog_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) mysqlmanagerc_SOURCES = mysqlmanagerc.c diff --git a/client/mysqltest.c b/client/mysqltest.c index 7623b9bde73..4c87561ab84 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "2.2" +#define MTEST_VERSION "2.3" #include <my_global.h> #include <mysql_embed.h> @@ -53,12 +53,13 @@ #include <mysqld_error.h> #include <m_ctype.h> #include <my_dir.h> +#include <errmsg.h> /* Error codes */ #include <hash.h> #include <my_getopt.h> #include <stdarg.h> #include <sys/stat.h> #include <violite.h> - +#include <regex.h> /* Our own version of lib */ #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 #define MAX_COLUMNS 256 @@ -93,7 +94,7 @@ 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_SSL_CIPHER,OPT_PS_PROTOCOL}; /* ************************************************************************ */ /* @@ -131,8 +132,8 @@ static int record = 0, opt_sleep=0; 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, - tty_password= 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 uint start_lineno, *lineno; const char* manager_user="root",*manager_host=0; char *manager_pass=0; @@ -157,7 +158,7 @@ static int block_stack[BLOCK_STACK_DEPTH]; static int block_ok_stack[BLOCK_STACK_DEPTH]; static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ -static char *charset_name = "latin1"; /* Default character set name */ +static const char *charset_name= "latin1"; /* Default character set name */ static int embedded_server_arg_count=0; static char *embedded_server_args[MAX_SERVER_ARGS]; @@ -171,6 +172,12 @@ static int got_end_timer= FALSE; static void timer_output(void); static ulonglong timer_now(void); +static 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); + static const char *embedded_server_groups[] = { "server", "embedded", @@ -270,7 +277,7 @@ Q_EXEC, Q_DELIMITER, Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_START_TIMER, Q_END_TIMER, -Q_CHARACTER_SET, +Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -352,6 +359,8 @@ const char *command_names[]= "start_timer", "end_timer", "character_set", + "disable_ps_protocol", + "enable_ps_protocol", 0 }; @@ -523,6 +532,8 @@ 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(); my_end(MY_CHECK_ERROR); DBUG_VOID_RETURN; } @@ -2089,6 +2100,9 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"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}, {"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.", @@ -2367,7 +2381,36 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) * the result will be read - for regular query, both bits must be on */ -int run_query(MYSQL* mysql, struct st_query* q, int flags) +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 int run_query_stmt_handle_error(char *query, struct st_query *q, + MYSQL_STMT *stmt, 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) +{ + + /* + 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; @@ -2377,7 +2420,7 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) DYNAMIC_STRING eval_query; char* query; int query_len, got_error_on_send= 0; - DBUG_ENTER("run_query"); + DBUG_ENTER("run_query_normal"); DBUG_PRINT("enter",("flags: %d", flags)); if (q->type != Q_EVAL) @@ -2520,56 +2563,14 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) { if (res) { - MYSQL_FIELD *field, *field_end; + MYSQL_FIELD *field= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); if (display_metadata) - { - dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tName\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n"); - for (field= mysql_fetch_fields(res), field_end= field+num_fields ; - field < field_end ; - field++) - { - char buff[22]; - dynstr_append_mem(ds, field->catalog, field->catalog_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->db, field->db_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->org_table, field->org_table_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->table, field->table_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->org_name, field->org_name_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->name, field->name_length); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->type, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->length, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->max_length, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? - "N" : "Y"), 1); - dynstr_append_mem(ds, "\t", 1); - - int10_to_str((int) field->flags, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->decimals, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->charsetnr, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\n", 1); - } - } + run_query_display_metadata(field, num_fields, ds); + if (!display_result_vertically) { - field= mysql_fetch_fields(res); for (i = 0; i < num_fields; i++) { if (i) @@ -2645,6 +2646,576 @@ end: } +/****************************************************************************\ + * 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, got_error_on_execute; + uint 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("At line %u: 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) + { + if (q->abort_on_error) + { + die("At line %u: unable to prepare statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + } + else + { + /* + Preparing is part of normal execution and some errors may be expected + */ + error= run_query_stmt_handle_error(query, q, stmt, ds); + goto end; + } + } + + /* We may have got warnings already, collect them if any */ + /* FIXME we only want this if the statement succeeds I think */ + 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 ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */ + { + if (q->abort_on_error) + { + /* We got an error, unexpected */ + die("At line %u: unable to execute statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, mysql_stmt_error(stmt), + mysql_stmt_errno(stmt), got_error_on_execute); + } + else + { + /* We got an error, maybe expected */ + error= run_query_stmt_handle_error(query, q, 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) != 0) + die("At line %u: unable to set stmt attribute " + "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", + start_lineno, query, 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) + { + if (q->abort_on_error) + { + /* We got an error, unexpected */ + die("At line %u: unable to execute statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, mysql_stmt_error(stmt), + mysql_stmt_errno(stmt), got_error_on_execute); + } + else + { + /* We got an error, maybe expected */ + error= run_query_stmt_handle_error(query, q, stmt, ds); + goto end; + } + } + + /* If we got here the statement was both executed and read succeesfully */ + + if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); + error= 1; + goto end; + } + + 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)) + { + /* Take the column count from meta info */ + MYSQL_FIELD *field= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + /* FIXME check error from the above? */ + + if (display_metadata) + run_query_display_metadata(field, num_fields, ds); + + 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_mem(ds, field[col_idx].name, + strlen(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)); + 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("At line %u: unable to bind result to statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, 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("At line %u: unable to fetch all rows from statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, 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, len); + } + else + { + dynstr_append(ds, field[col_idx].name); + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, 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("At line %u: fetch didn't end with MYSQL_NO_DATA from statement " + "'%s': %s (mysql_stmt_errno=%d returned=%d)", + start_lineno, 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 (!q->record_file[0] && !result_file) + die("At line %u: Missing result file", start_lineno); + 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); /* Free normal result set with meta data */ + last_result= 0; /* FIXME have no idea what this is about... */ + + if (err >= 1) + mysql_error(mysql); /* FIXME strange, has no effect... */ + +end: + free_replace(); + last_result=0; + if (ds == &ds_tmp) + dynstr_free(&ds_tmp); + if (q->type == Q_EVAL) + dynstr_free(&eval_query); + mysql_stmt_close(stmt); + DBUG_RETURN(error); +} + + +/****************************************************************************\ + * Broken out sub functions to run_query_stmt() +\****************************************************************************/ + +static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, + DYNAMIC_STRING *ds) +{ + MYSQL_FIELD *field_end; + dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t" + "Column_alias\tName\tType\tLength\tMax length\tIs_null\t" + "Flags\tDecimals\tCharsetnr\n"); + + for (field_end= field+num_fields ; + field < field_end ; + field++) + { + char buff[22]; + dynstr_append_mem(ds, field->catalog, + field->catalog_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->db, field->db_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->org_table, + field->org_table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->table, + field->table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->org_name, + field->org_name_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field->name, field->name_length); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->type, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->max_length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? + "N" : "Y"), 1); + dynstr_append_mem(ds, "\t", 1); + + int10_to_str((int) field->flags, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->decimals, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field->charsetnr, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\n", 1); + } +} + + +static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) +{ + uint count; + DBUG_ENTER("run_query_stmt_handle_warnings"); + + if (!disable_warnings && (count= mysql_warning_count(mysql))) + { + if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0) + { + MYSQL_RES *warn_res= mysql_store_result(mysql); + if (!warn_res) + verbose_msg("Warning count is %u but didn't get any warnings\n", + count); + else + { + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); + } + } + } + DBUG_VOID_RETURN; +} + + +static int run_query_stmt_handle_error(char *query, struct st_query *q, + MYSQL_STMT *stmt, DYNAMIC_STRING *ds) +{ + if (q->require_file) /* FIXME don't understand this one */ + { + abort_not_supported_test(); + } + + if (q->abort_on_error) + die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + else + { + int i; + + for (i=0 ; (uint) i < q->expected_errors ; i++) + { + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == mysql_stmt_errno(stmt))) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate, + mysql_stmt_sqlstate(stmt)) == 0))) + { + if (i == 0 && q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds,"ERROR ",6); + replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), + strlen(mysql_stmt_sqlstate(stmt))); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append_mem(ds,mysql_stmt_error(stmt), + strlen(mysql_stmt_error(stmt))); + 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"); + return 0; /* Ok */ + } + } + DBUG_PRINT("info",("i: %d expected_errors: %d", i, + q->expected_errors)); + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), + strlen(mysql_stmt_sqlstate(stmt))); + dynstr_append_mem(ds,": ",2); + replace_dynstr_append_mem(ds, mysql_stmt_error(stmt), + strlen(mysql_stmt_error(stmt))); + dynstr_append_mem(ds,"\n",1); + if (i) + { + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); + return 1; /* Error */ + } + verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + /* + if we do not abort on error, failure to run the query does + not fail the whole test case + */ + return 0; + } + + return 0; +} + +/****************************************************************************\ + * Functions to match SQL statements that can be prepared +\****************************************************************************/ + +static void ps_init_re(void) +{ + const char *ps_re_str = + "^(" + "[[:space:]]*REPLACE[[:space:]]|" + "[[:space:]]*INSERT[[:space:]]|" + "[[:space:]]*UPDATE[[:space:]]|" + "[[:space:]]*DELETE[[:space:]]|" + "[[:space:]]*SELECT[[:space:]]|" + "[[:space:]]*CREATE[[:space:]]+TABLE[[:space:]]|" + "[[:space:]]*DO[[:space:]]|" + "[[:space:]]*SET[[:space:]]+OPTION[[:space:]]|" + "[[:space:]]*DELETE[[:space:]]+MULTI[[:space:]]|" + "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" + "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; + + int err= regcomp(&ps_re, ps_re_str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), + &my_charset_latin1); + if (err) + { + char erbuf[100]; + int len= 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); + } +} + + +static int ps_match_re(char *stmt_str) +{ + int err= regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); + + if (err == 0) + return 1; + else if (err == REG_NOMATCH) + return 0; + else + { + char erbuf[100]; + int len= 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); + } +} + +static char *ps_eprint(int err) +{ + static char epbuf[100]; + size_t len= regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); + assert(len <= sizeof(epbuf)); + return(epbuf); +} + + +static void ps_free_reg(void) +{ + regfree(&ps_re); +} + +/****************************************************************************/ + void get_query_type(struct st_query* q) { char save; @@ -2798,6 +3369,11 @@ int main(int argc, char **argv) if (manager_host) init_manager(); #endif + if (ps_protocol) + { + ps_protocol_enabled= 1; + ps_init_re(); + } if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) @@ -2991,6 +3567,13 @@ int main(int argc, char **argv) case Q_CHARACTER_SET: set_charset(q); break; + case Q_DISABLE_PS_PROTOCOL: + ps_protocol_enabled= 0; + break; + case Q_ENABLE_PS_PROTOCOL: + ps_protocol_enabled= ps_protocol; + break; + default: processed = 0; break; } } diff --git a/configure.in b/configure.in index 656af354607..f85c3e1421a 100644 --- a/configure.in +++ b/configure.in @@ -2811,7 +2811,7 @@ thread_dirs= dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs="libmysql client" +sql_client_dirs="libmysql strings regex client" linked_client_targets="linked_libmysql_sources" CLIENT_LIBS=$NON_THREADED_CLIENT_LIBS if test "$THREAD_SAFE_CLIENT" != "no" diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 6a67697169a..2dfdfbb687b 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1880,6 +1880,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) } stmt->field_count= (uint) field_count; stmt->param_count= (ulong) param_count; + mysql->warning_count= 0; DBUG_RETURN(0); } @@ -3263,7 +3264,6 @@ static void read_binary_time(MYSQL_TIME *tm, uchar **pos) tm->minute= (uint) to[6]; tm->second= (uint) to[7]; tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0; - tm->year= tm->month= 0; *pos+= length; @@ -3489,7 +3489,16 @@ static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, char buff[22]; /* Enough for longlong */ char *end= longlong10_to_str(value, buff, field_is_unsigned ? 10: -10); /* Resort to string conversion which supports all typecodes */ - fetch_string_with_conversion(param, buff, (uint) (end - buff)); + uint length= (uint) (end-buff); + + if (field->flags & ZEROFILL_FLAG && length < field->length && + field->length < 21) + { + bmove_upp((char*) buff+field->length,buff+length, length); + bfill((char*) buff, field->length - length,'0'); + length= field->length; + } + fetch_string_with_conversion(param, buff, length); break; } } @@ -3556,8 +3565,14 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, if (field->decimals >= NOT_FIXED_DEC) #undef NOT_FIXED_DEC { - sprintf(buff, "%-*.*g", (int) min(sizeof(buff)-1, param->buffer_length), - width, value); + /* + The 14 below is to ensure that the server and client has the same + precisions. This will ensure that on the same machine you get the + same value as a string independent of the protocol you use. + */ + sprintf(buff, "%-*.*g", (int) min(sizeof(buff)-1, + param->buffer_length), + min(14,width), value); end= strcend(buff, ' '); *end= 0; } @@ -3868,12 +3883,12 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) { MYSQL_BIND *param, *end; MYSQL_FIELD *field; - ulong bind_count; + ulong bind_count= stmt->field_count; uint param_count= 0; DBUG_ENTER("mysql_stmt_bind_result"); - DBUG_ASSERT(stmt != 0); + DBUG_PRINT("enter",("field_count: %d", bind_count)); - if (!stmt->field_count) + if (!bind_count) { if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) { @@ -3881,7 +3896,6 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) } DBUG_RETURN(0); } - bind_count= stmt->field_count; /* We only need to check that stmt->field_count - if it is not null @@ -3894,6 +3908,8 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) param < end ; param++, field++) { + DBUG_PRINT("info",("buffer_type: %u field_type: %u", + (uint) param->buffer_type, (uint) field->type)); /* Set param->is_null to point to a dummy variable if it's not set. This is to make the execute code easier @@ -4221,6 +4237,8 @@ int cli_read_binary_rows(MYSQL_STMT *stmt) *prev_ptr= 0; mysql->warning_count= uint2korr(cp+1); mysql->server_status= uint2korr(cp+3); + DBUG_PRINT("info",("status: %u warning_count: %u", + mysql->server_status, mysql->warning_count)); DBUG_RETURN(0); } } @@ -4316,11 +4334,12 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) bind < end ; bind++, field++) { - bind->buffer_type= field->type; + bind->buffer_type= MYSQL_TYPE_NULL; bind->buffer_length=1; } - mysql_stmt_bind_result(stmt, stmt->bind); + if (mysql_stmt_bind_result(stmt, stmt->bind)) + DBUG_RETURN(1); stmt->bind_result_done= 0; /* No normal bind done */ } diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index 2712e0dff48..5b0a86e679c 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -14,13 +14,14 @@ link_sources: DEFS = -DEMBEDDED_LIBRARY INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir) \ - -I$(top_srcdir) -I$(top_srcdir)/client $(openssl_includes) + -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ + $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS) mysqltest_LINK = $(CXXLINK) - mysqltest_SOURCES = mysqltest.c +mysqltest_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a mysql_SOURCES = mysql.cc readline.cc completion_hash.cc \ my_readline.h sql_string.h completion_hash.h diff --git a/mysql-test/include/have_query_cache.inc b/mysql-test/include/have_query_cache.inc index e5e6052c9a7..39549157849 100644 --- a/mysql-test/include/have_query_cache.inc +++ b/mysql-test/include/have_query_cache.inc @@ -1,4 +1,7 @@ -- require r/have_query_cache.require +# As PS are not cached we disable them to ensure the we get the right number +# of query cache hits +-- disable_ps_protocol disable_query_log; show variables like "have_query_cache"; enable_query_log; diff --git a/mysql-test/include/ps_conv.inc b/mysql-test/include/ps_conv.inc index 03d93b6190d..0a5bec26fe7 100644 --- a/mysql-test/include/ps_conv.inc +++ b/mysql-test/include/ps_conv.inc @@ -73,7 +73,9 @@ create table t5 as select show create table t5 ; --vertical_results --enable_metadata +--disable_ps_protocol select * from t5 ; +--enable_ps_protocol --disable_metadata --horizontal_results drop table t5 ; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index b12f7afb9f1..6b40fb3e974 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -321,6 +321,8 @@ while test $# -gt 0; do EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" SLEEP_TIME_AFTER_RESTART=`$ECHO "$1" | $SED -e "s;--sleep=;;"` ;; + --ps-protocol) + EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; --user-test=*) USER_TEST=`$ECHO "$1" | $SED -e "s;--user-test=;;"` ;; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index e65eb96cb68..482a6502490 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -766,9 +766,7 @@ list_id smallint unsigned NOT NULL, term text NOT NULL, PRIMARY KEY(id), INDEX(list_id, term(19)) -) TYPE=MyISAM CHARSET=utf8; -Warnings: -Warning 1287 'TYPE=storage_engine' is deprecated; use 'ENGINE=storage_engine' instead +) ENGINE=MyISAM CHARSET=utf8; INSERT INTO t1 set list_id = 1, term = "testétest"; INSERT INTO t1 set list_id = 1, term = "testetest"; INSERT INTO t1 set list_id = 1, term = "testètest"; diff --git a/mysql-test/r/fulltext_cache.result b/mysql-test/r/fulltext_cache.result index c489bdefeb8..6a94189d8b4 100644 --- a/mysql-test/r/fulltext_cache.result +++ b/mysql-test/r/fulltext_cache.result @@ -21,17 +21,17 @@ INSERT INTO t2 VALUES (5,2,'um copo de Vodka'); INSERT INTO t2 VALUES (6,2,'um chocolate Snickers'); INSERT INTO t2 VALUES (7,1,'Bife'); INSERT INTO t2 VALUES (8,1,'Pizza de Salmao'); -SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') +SELECT t1.q, t2.item, t2.id, round(MATCH t2.item AGAINST ('sushi'),8) as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; q item id x -aaaaaaaaa dsaass de sushi 1 1.92378664016724 -aaaaaaaaa dsaass de Bolo de Chocolate 2 0 -aaaaaaaaa dsaass de Feijoada 3 0 -aaaaaaaaa dsaass de Mousse de Chocolate 4 0 -ssde df s fsda sad er um copo de Vodka 5 0 -ssde df s fsda sad er um chocolate Snickers 6 0 -aaaaaaaaa dsaass de Bife 7 0 -aaaaaaaaa dsaass de Pizza de Salmao 8 0 +aaaaaaaaa dsaass de sushi 1 1.92378664 +aaaaaaaaa dsaass de Bolo de Chocolate 2 0.00000000 +aaaaaaaaa dsaass de Feijoada 3 0.00000000 +aaaaaaaaa dsaass de Mousse de Chocolate 4 0.00000000 +ssde df s fsda sad er um copo de Vodka 5 0.00000000 +ssde df s fsda sad er um chocolate Snickers 6 0.00000000 +aaaaaaaaa dsaass de Bife 7 0.00000000 +aaaaaaaaa dsaass de Pizza de Salmao 8 0.00000000 SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE) as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; q item id x @@ -43,17 +43,17 @@ ssde df s fsda sad er um copo de Vodka 5 0 ssde df s fsda sad er um chocolate Snickers 6 0 aaaaaaaaa dsaass de Bife 7 0 aaaaaaaaa dsaass de Pizza de Salmao 8 0 -SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') +SELECT t1.q, t2.item, t2.id, round(MATCH t2.item AGAINST ('sushi'),8) as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; q item id x -aaaaaaaaa dsaass de sushi 1 1.92378664016724 -aaaaaaaaa dsaass de Bolo de Chocolate 2 0 -aaaaaaaaa dsaass de Feijoada 3 0 -aaaaaaaaa dsaass de Mousse de Chocolate 4 0 -ssde df s fsda sad er um copo de Vodka 5 0 -ssde df s fsda sad er um chocolate Snickers 6 0 -aaaaaaaaa dsaass de Bife 7 0 -aaaaaaaaa dsaass de Pizza de Salmao 8 0 +aaaaaaaaa dsaass de sushi 1 1.92378664 +aaaaaaaaa dsaass de Bolo de Chocolate 2 0.00000000 +aaaaaaaaa dsaass de Feijoada 3 0.00000000 +aaaaaaaaa dsaass de Mousse de Chocolate 4 0.00000000 +ssde df s fsda sad er um copo de Vodka 5 0.00000000 +ssde df s fsda sad er um chocolate Snickers 6 0.00000000 +aaaaaaaaa dsaass de Bife 7 0.00000000 +aaaaaaaaa dsaass de Pizza de Salmao 8 0.00000000 SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE) as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; q item id x diff --git a/mysql-test/r/fulltext_left_join.result b/mysql-test/r/fulltext_left_join.result index bf3fe73690a..f3dad290525 100644 --- a/mysql-test/r/fulltext_left_join.result +++ b/mysql-test/r/fulltext_left_join.result @@ -16,13 +16,13 @@ author VARCHAR(255) NOT NULL INSERT INTO t2 VALUES('123', 'moi'); INSERT INTO t2 VALUES('123', 'lui'); INSERT INTO t2 VALUES('456', 'lui'); -select match(t1.texte,t1.sujet,t1.motsclefs) against('droit') +select round(match(t1.texte,t1.sujet,t1.motsclefs) against('droit'),5) from t1 left join t2 on t2.id=t1.id; -match(t1.texte,t1.sujet,t1.motsclefs) against('droit') -0 -0 -0.67003107070923 -0 +round(match(t1.texte,t1.sujet,t1.motsclefs) against('droit'),5) +0.00000 +0.00000 +0.67003 +0.00000 select match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE) from t1 left join t2 on t2.id=t1.id; match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE) diff --git a/mysql-test/r/fulltext_multi.result b/mysql-test/r/fulltext_multi.result index 968b00020e2..289ee004395 100644 --- a/mysql-test/r/fulltext_multi.result +++ b/mysql-test/r/fulltext_multi.result @@ -11,19 +11,19 @@ FULLTEXT KEY a(b,c) INSERT INTO t1 VALUES (1,'lala lolo lili','oooo aaaa pppp'); INSERT INTO t1 VALUES (2,'asdf fdsa','lkjh fghj'); INSERT INTO t1 VALUES (3,'qpwoei','zmxnvb'); -SELECT a, MATCH b AGAINST ('lala lkjh') FROM t1; -a MATCH b AGAINST ('lala lkjh') -1 0.67003107070923 -2 0 -3 0 -SELECT a, MATCH c AGAINST ('lala lkjh') FROM t1; -a MATCH c AGAINST ('lala lkjh') -1 0 -2 0.67756325006485 -3 0 -SELECT a, MATCH b,c AGAINST ('lala lkjh') FROM t1; -a MATCH b,c AGAINST ('lala lkjh') -1 0.64840710163116 -2 0.66266459226608 -3 0 +SELECT a, round(MATCH b AGAINST ('lala lkjh'),5) FROM t1; +a round(MATCH b AGAINST ('lala lkjh'),5) +1 0.67003 +2 0.00000 +3 0.00000 +SELECT a, round(MATCH c AGAINST ('lala lkjh'),5) FROM t1; +a round(MATCH c AGAINST ('lala lkjh'),5) +1 0.00000 +2 0.67756 +3 0.00000 +SELECT a, round(MATCH b,c AGAINST ('lala lkjh'),5) FROM t1; +a round(MATCH b,c AGAINST ('lala lkjh'),5) +1 0.64841 +2 0.66266 +3 0.00000 drop table t1; diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/r/innodb-lock.result index 407a85ed038..4ace4065c34 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/r/innodb-lock.result @@ -1,3 +1,4 @@ +set global innodb_table_locks=1; select @@innodb_table_locks; @@innodb_table_locks 1 diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 26c527ca7cb..6f222eedec1 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -272,8 +272,11 @@ insert into t2 values(10),(20); create table t3 like t1; show create table t3; select * from t3; +# Disable PS becasue of @@warning_count +--disable_ps_protocol create table if not exists t3 like t1; select @@warning_count; +--enable_ps_protocol create temporary table t3 like t2; show create table t3; select * from t3; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 238cd6daef3..2ee796eeb67 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -621,7 +621,7 @@ CREATE TABLE t1 ( term text NOT NULL, PRIMARY KEY(id), INDEX(list_id, term(19)) -) TYPE=MyISAM CHARSET=utf8; +) ENGINE=MyISAM CHARSET=utf8; INSERT INTO t1 set list_id = 1, term = "testétest"; INSERT INTO t1 set list_id = 1, term = "testetest"; INSERT INTO t1 set list_id = 1, term = "testètest"; diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index f769fe7af04..c369a9c85d5 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -118,8 +118,11 @@ SET datetime_format=default; # Test of str_to_date # +# PS doesn't support fraction of a seconds +--disable_ps_protocol select str_to_date(concat('15-01-2001',' 2:59:58.999'), concat('%d-%m-%Y',' ','%H:%i:%s.%f')); +--enable_ps_protocol create table t1 (date char(30), format char(30) not null); insert into t1 values @@ -153,7 +156,8 @@ insert into t1 values ('15-01-20', '%d-%m-%y'), ('15-2001-1', '%d-%Y-%c'); -# Use through protocol functions +# PS doesn't support fractional seconds +--disable_ps_protocol select date,format,str_to_date(date, format) as str_to_date from t1; # Use as a string select date,format,concat('',str_to_date(date, format)) as con from t1; @@ -198,6 +202,7 @@ select date,format,str_to_date(date, format) as str_to_date from t1; select date,format,concat(str_to_date(date, format),'') as con from t1; drop table t1; +--enable_ps_protocol # # Test of get_format @@ -221,6 +226,8 @@ insert into t1 values ('2004-07-14'),('2005-07-14'); select date_format(d,"%d") from t1 order by 1; drop table t1; +# PS doesn't support fractional seconds +--disable_ps_protocol select str_to_date("2003-....01ABCD-02 10:11:12.0012", "%Y-%.%m%@-%d %H:%i:%S.%f") as a; @@ -249,3 +256,4 @@ select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1 select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1, str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2; +--enable_ps_protocol diff --git a/mysql-test/t/fulltext_cache.test b/mysql-test/t/fulltext_cache.test index 15f32fdb5a0..234deab91e6 100644 --- a/mysql-test/t/fulltext_cache.test +++ b/mysql-test/t/fulltext_cache.test @@ -29,13 +29,13 @@ INSERT INTO t2 VALUES (6,2,'um chocolate Snickers'); INSERT INTO t2 VALUES (7,1,'Bife'); INSERT INTO t2 VALUES (8,1,'Pizza de Salmao'); -SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') +SELECT t1.q, t2.item, t2.id, round(MATCH t2.item AGAINST ('sushi'),8) as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE) as x FROM t1, t2 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; -SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi') +SELECT t1.q, t2.item, t2.id, round(MATCH t2.item AGAINST ('sushi'),8) as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE) diff --git a/mysql-test/t/fulltext_left_join.test b/mysql-test/t/fulltext_left_join.test index f8dcfb2aad6..96751ef8678 100644 --- a/mysql-test/t/fulltext_left_join.test +++ b/mysql-test/t/fulltext_left_join.test @@ -24,7 +24,7 @@ INSERT INTO t2 VALUES('123', 'moi'); INSERT INTO t2 VALUES('123', 'lui'); INSERT INTO t2 VALUES('456', 'lui'); -select match(t1.texte,t1.sujet,t1.motsclefs) against('droit') +select round(match(t1.texte,t1.sujet,t1.motsclefs) against('droit'),5) from t1 left join t2 on t2.id=t1.id; select match(t1.texte,t1.sujet,t1.motsclefs) against('droit' IN BOOLEAN MODE) from t1 left join t2 on t2.id=t1.id; diff --git a/mysql-test/t/fulltext_multi.test b/mysql-test/t/fulltext_multi.test index c312a5938b2..3a622a551bc 100644 --- a/mysql-test/t/fulltext_multi.test +++ b/mysql-test/t/fulltext_multi.test @@ -17,7 +17,7 @@ INSERT INTO t1 VALUES (1,'lala lolo lili','oooo aaaa pppp'); INSERT INTO t1 VALUES (2,'asdf fdsa','lkjh fghj'); INSERT INTO t1 VALUES (3,'qpwoei','zmxnvb'); -SELECT a, MATCH b AGAINST ('lala lkjh') FROM t1; -SELECT a, MATCH c AGAINST ('lala lkjh') FROM t1; -SELECT a, MATCH b,c AGAINST ('lala lkjh') FROM t1; +SELECT a, round(MATCH b AGAINST ('lala lkjh'),5) FROM t1; +SELECT a, round(MATCH c AGAINST ('lala lkjh'),5) FROM t1; +SELECT a, round(MATCH b,c AGAINST ('lala lkjh'),5) FROM t1; drop table t1; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 3e001961f90..8d8779e9d1b 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -30,7 +30,11 @@ select grp, sum(a)+count(a)+avg(a)+std(a)+variance(a)+bit_or(a)+bit_and(a)+min(a create table t2 (grp int, a bigint unsigned, c char(10)); insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp; + +# REPLACE ... SELECT doesn't yet work with PS +--disable_ps_protocol replace into t2 select grp, a, c from t1 limit 2,1; +--enable_ps_protocol select * from t2; drop table t1,t2; diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test index 24028437fde..2ae3c438243 100644 --- a/mysql-test/t/func_sapdb.test +++ b/mysql-test/t/func_sapdb.test @@ -47,17 +47,23 @@ select subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); select subtime("01:00:00.999999", "02:00:00.999998"); select subtime("02:01:01.999999", "01:01:01.999999"); +# PS doesn't support fractional seconds +--disable_ps_protocol select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +--enable_ps_protocol select maketime(10,11,12); select maketime(25,11,12); select maketime(-25,11,12); -#Extraction functions +# Extraction functions + +# PS doesn't support fractional seconds +--disable_ps_protocol select timestamp("2001-12-01", "01:01:01.999999"); select timestamp("2001-13-01", "01:01:01.000001"); select timestamp("2001-12-01", "25:01:01"); @@ -69,6 +75,7 @@ select date("1997-13-31 23:59:59.000001"); select time("1997-12-31 23:59:59.000001"); select time("1997-12-31 25:59:59.000001"); select microsecond("1997-12-31 23:59:59.000001"); +--enable_ps_protocol create table t1 select makedate(1997,1) as f1, @@ -81,7 +88,10 @@ select makedate(1997,1) as f1, date("1997-12-31 23:59:59.000001") as f8, time("1997-12-31 23:59:59.000001") as f9; describe t1; +# PS doesn't support fractional seconds +--disable_ps_protocol select * from t1; +--enable_ps_protocol create table test(t1 datetime, t2 time, t3 time, t4 datetime); insert into test values @@ -94,7 +104,10 @@ insert into test values ('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01'); SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test; +# PS doesn't support fractional seconds +--disable_ps_protocol SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test; +--enable_ps_protocol drop table t1, test; @@ -102,4 +115,7 @@ select addtime("-01:01:01.01", "-23:59:59.1") as a; select microsecond("1997-12-31 23:59:59.01") as a; select microsecond(19971231235959.01) as a; select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; +# PS doesn't support fractional seconds +--disable_ps_protocol select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f"); +--enable_ps_protocol diff --git a/mysql-test/t/innodb-lock-master.opt b/mysql-test/t/innodb-lock-master.opt deleted file mode 100644 index 403fcde87ed..00000000000 --- a/mysql-test/t/innodb-lock-master.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb-table-lock=1 diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 2bbbac82ad5..a3b6f8993f2 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -4,6 +4,8 @@ # Check and select innodb lock type # +set global innodb_table_locks=1; + select @@innodb_table_locks; # diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index fd728c453aa..54379685731 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -92,6 +92,8 @@ drop database mysqltest; # Test of wrong values for float data (bug #2082) # +# PS gives sligthly different numbers for max-float/max-double +--disable_ps_protocol use test; create table t1(number int auto_increment primary key, original_value varchar(50), f_double double, f_float float, f_double_7_2 double(7,2), f_float_4_3 float (4,3), f_double_u double unsigned, f_float_u float unsigned, f_double_15_1_u double(15,1) unsigned, f_float_3_1_u float (3,1) unsigned); @@ -140,3 +142,4 @@ insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@val --query_vertical select * from t1 where number =last_insert_id() drop table t1; +--enable_ps_protocol diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 234a5ec0eef..db5dc8d91da 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -122,7 +122,10 @@ insert into t2 values (2,"t2:2"), (3,"t2:3"); --error 1062 insert into t1 select * from t2; select * from t1; +# REPLACE .. SELECT is not yet supported by PS +--disable_ps_protocol replace into t1 select * from t2; +--enable_ps_protocol select * from t1; drop table t1,t2; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index d2a70208022..fc54ce88f8a 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -35,10 +35,10 @@ create table t1(a int primary key, b int); insert into t1 values(1,1),(2,2),(3,3),(4,4),(5,5); select * from t1; -enable_info; +--enable_info insert into t1 values(4,14),(5,15),(6,16),(7,17),(8,18) on duplicate key update b=b+10; -disable_info; +--disable_info select * from t1; diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index c426ab9864b..d11cb62b04e 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -6,6 +6,8 @@ drop table if exists t1,t2; --enable_warnings --enable_metadata +# PS protocol gives slightly different metadata +--disable_ps_protocol # # First some simple tests diff --git a/mysql-test/t/multi_statement.test b/mysql-test/t/multi_statement.test index bd90275c9f5..862f2294641 100644 --- a/mysql-test/t/multi_statement.test +++ b/mysql-test/t/multi_statement.test @@ -1,3 +1,6 @@ +# PS doesn't support multi-statements +--disable_ps_protocol + select 1; delimiter ||||; select 2; diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index f27aca7a452..9e4acc2bf24 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -501,6 +501,8 @@ prepare stmt1 from ' KILL 0 '; ## simple explain # cases derived from client_test.c: test_explain_bug() prepare stmt1 from ' explain select a from t1 order by b '; +# PS protocol gives slightly different metadata +--disable_ps_protocol --enable_metadata execute stmt1; --disable_metadata @@ -509,6 +511,7 @@ prepare stmt1 from ' explain select a from t1 where a > ? order by b '; --enable_metadata execute stmt1 using @arg00; --disable_metadata +--enable_ps_protocol ## parameters with probably problematic characters (quote, double quote) # cases derived from client_test.c: test_logs() diff --git a/mysql-test/t/rollback.test b/mysql-test/t/rollback.test index 87f59417d90..3cb1ea3024b 100644 --- a/mysql-test/t/rollback.test +++ b/mysql-test/t/rollback.test @@ -5,6 +5,8 @@ --disable_warnings drop table if exists t1; --enable_warnings +# PS doesn't work with BEGIN ... ROLLBACK +--disable_ps_protocol create table t1 (n int not null primary key) engine=myisam; begin work; diff --git a/mysql-test/t/rpl_redirect.test b/mysql-test/t/rpl_redirect.test index 3b5ad6ba88d..c533c0052f0 100644 --- a/mysql-test/t/rpl_redirect.test +++ b/mysql-test/t/rpl_redirect.test @@ -3,6 +3,8 @@ # source include/master-slave.inc; +# We disable this for now as PS doesn't handle redirection +--disable_ps_protocol #first, make sure the slave has had enough time to register save_master_pos; diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test index 35fbec72ac8..73b3ace473e 100644 --- a/mysql-test/t/rpl_user_variables.test +++ b/mysql-test/t/rpl_user_variables.test @@ -2,6 +2,9 @@ # Test of replicating user variables # source include/master-slave.inc; +# Disable PS as the log positions differs +--disable_ps_protocol + # Clean up old slave's binlogs. # The slave is started with --log-slave-updates diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index c260c7777e2..5bae44796dc 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1706,12 +1706,18 @@ select t2.companynr,companyname,count(*) from t2,t4 where t2.companynr=t4.compan select count(*) from t2; select count(*) from t2 where fld1 < 098024; +# PS does correct pre-zero here. MySQL can't do it as it returns a number. +--disable_ps_protocol select min(fld1) from t2 where fld1>= 098024; +--enable_ps_protocol select max(fld1) from t2 where fld1>= 098024; select count(*) from t3 where price2=76234234; select count(*) from t3 where companynr=512 and price2=76234234; explain select min(fld1),max(fld1),count(*) from t2; +# PS does correct pre-zero here. MySQL can't do it as it returns a number. +--disable_ps_protocol select min(fld1),max(fld1),count(*) from t2; +--enable_ps_protocol select min(t2nr),max(t2nr) from t3 where t2nr=2115 and price2=823742; select count(*),min(t2nr),max(t2nr) from t3 where name='spates' and companynr=78; select t2nr,count(*) from t3 where name='gems' group by t2nr limit 20; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 7be494bd0e7..31d9c8154d5 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -5,6 +5,8 @@ # connection in a separate thread. # --source include/not_embedded.inc +# PS causes different statistics +--disable_ps_protocol connect (con1,localhost,root,,); connect (con2,localhost,root,,); diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index bd571deff49..b67fa7a552d 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -16,7 +16,10 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7; CREATE TABLE t1 (a blob, b text, c blob(250), d text(70000), e text(70000000)); show columns from t1; +# PS doesn't give errors on prepare yet +--disable_ps_protocol CREATE TABLE t2 (a char(257), b varbinary(70000), c varchar(70000000)); +--enable_ps_protocol show columns from t2; create table t3 (a long, b long byte); show create TABLE t3; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 4b627ea9b99..216d5bbd286 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -39,7 +39,10 @@ create table t1 (c1 double, c2 varchar(20)); insert t1 values (121,"16"); select c1 + c1 * (c2 / 100) as col from t1; create table t2 select c1 + c1 * (c2 / 100) as col1, round(c1, 5) as col2, round(c1, 35) as col3, sqrt(c1*1e-15) col4 from t1; +# Floats are a bit different in PS +--disable_ps_protocol select * from t2; +--enable_ps_protocol show create table t2; drop table t1,t2; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 6e16a2b02aa..36027e8c4cb 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -5,6 +5,9 @@ --disable_warnings drop table if exists t1,t2,t3,t4,t5,t6; --enable_warnings +# PS doesn't work correctly with found_rows: to be fixed +--disable_ps_protocol + CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); @@ -73,6 +76,7 @@ select * from t1 union select SQL_BUFFER_RESULT * from t2; # Test CREATE, INSERT and REPLACE create table t3 select a,b from t1 union all select a,b from t2; insert into t3 select a,b from t1 union all select a,b from t2; +# PS can't handle REPLACE ... SELECT replace into t3 select a,b as c from t1 union all select a,b from t2; drop table t1,t2,t3; diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test index b6042df51f1..4bd659606f6 100644 --- a/mysql-test/t/warnings.test +++ b/mysql-test/t/warnings.test @@ -26,8 +26,11 @@ show warnings limit 1; drop database if exists not_exists_db; show count(*) warnings; create table t1(id int); +# PS doesn't give warnings on prepare +--disable_ps_protocol create table if not exists t1(id int); select @@warning_count; +--enable_ps_protocol drop table t1; # @@ -36,7 +39,10 @@ drop table t1; create table t1(a tinyint, b int not null, c date, d char(5)); load data infile '../../std_data/warnings_loaddata.dat' into table t1 fields terminated by ','; +# PS doesn't work good with @@warning_count +--disable_ps_protocol select @@warning_count; +--enable_ps_protocol drop table t1; # @@ -74,7 +80,9 @@ enable_query_log; alter table t1 add b char; set max_error_count=10; update t1 set b=a; +--disable_ps_protocol select @@warning_count; +--enable_ps_protocol # # Test for handler type @@ -87,12 +95,15 @@ drop table t1; # # Test for deprecated TYPE= syntax # + +# PS doesn't give warnings on prepare +--disable_ps_protocol create table t1 (id int) type=heap; alter table t1 type=myisam; drop table t1; +--enable_ps_protocol # # Test for deprecated table_type variable # set table_type=MYISAM; - diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index f0bc62b10a0..d8c19d86e5c 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -158,6 +158,8 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) next->next= mem_root->used; next->size= Size; mem_root->used= next; + DBUG_PRINT("exit",("ptr: 0x%lx", (((char*) next)+ + ALIGN_SIZE(sizeof(USED_MEM))))); DBUG_RETURN((gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)))); #else uint get_size, block_size; diff --git a/sql-common/client.c b/sql-common/client.c index 9fca38f3857..7bf9c90254d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -727,6 +727,7 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) static void cli_flush_use_result(MYSQL *mysql) { /* Clear the current execution status */ + DBUG_ENTER("cli_flush_use_result"); DBUG_PRINT("warning",("Not all packets read, clearing them")); for (;;) { @@ -744,6 +745,7 @@ static void cli_flush_use_result(MYSQL *mysql) break; /* End of data */ } } + DBUG_VOID_RETURN; } diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 93549f7340c..be349285b88 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -742,9 +742,13 @@ void set_zero_time(MYSQL_TIME *tm) int my_time_to_str(const MYSQL_TIME *l_time, char *to) { + uint extra_hours= 0; + /* Get extra hours, if we are getting data from the server */ + if (l_time->year == 0 && l_time->month == 0) + extra_hours= l_time->day*24; return my_sprintf(to, (to, "%s%02d:%02d:%02d", (l_time->neg ? "-" : ""), - l_time->hour, + extra_hours+ l_time->hour, l_time->minute, l_time->second)); } diff --git a/sql/field.cc b/sql/field.cc index aae507cd0ec..55351ad9a87 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3508,8 +3508,8 @@ bool Field_time::send_binary(Protocol *protocol) { TIME tm; Field_time::get_time(&tm); - tm.day= tm.hour/3600; // Move hours to days - tm.hour-= tm.day*3600; + tm.day= tm.hour/24; // Move hours to days + tm.hour-= tm.day*24; return protocol->store_time(&tm); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f6730c84979..c9396aaa67c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1760,6 +1760,7 @@ void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; uint const_itm= 1; + THD *thd= current_thd; agg_cmp_type(&cmp_type, args, arg_count); @@ -1797,6 +1798,9 @@ void Item_func_in::fix_length_and_dec() Conversion is possible: All IN arguments are constants. */ + Item_arena *arena= thd->current_arena, backup; + if (arena->is_stmt_prepare()) + thd->set_n_backup_item_arena(arena, &backup); for (arg= args+1, arg_end= args+arg_count; arg < arg_end; arg++) { if (!my_charset_same(cmp_collation.collation, @@ -1812,6 +1816,8 @@ void Item_func_in::fix_length_and_dec() arg[0]= conv; } } + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); } } @@ -1839,7 +1845,7 @@ void Item_func_in::fix_length_and_dec() DBUG_ASSERT(0); return; } - if (array && !(current_thd->is_fatal_error)) // If not EOM + if (array && !(thd->is_fatal_error)) // If not EOM { uint j=0; for (uint i=1 ; i < arg_count ; i++) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index dfcc5789ea4..a869e2d24fb 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -365,9 +365,9 @@ Item_singlerow_subselect::select_transformer(JOIN *join) if (!(substitution= new Item_func_if(cond, substitution, new Item_null()))) goto err; + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); } - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); return RES_REDUCE; } return RES_OK; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index fc3cf9d4aa9..e6c96dd6a9a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1693,8 +1693,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, SQL_LIST *is_order, String *is_separator) :Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0), - warning_available(0), key_length(0), - tree_mode(0), distinct(is_distinct), warning_for_row(0), + key_length(0), tree_mode(0), distinct(is_distinct), warning_for_row(0), separator(is_separator), tree(&tree_base), table(0), order(0), tables_list(0), arg_count_order(0), arg_count_field(0), @@ -1752,7 +1751,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tmp_table_param(item->tmp_table_param), max_elements_in_tree(item->max_elements_in_tree), warning(item->warning), - warning_available(item->warning_available), key_length(item->key_length), tree_mode(item->tree_mode), distinct(item->distinct), @@ -1779,10 +1777,6 @@ void Item_func_group_concat::cleanup() DBUG_ENTER("Item_func_group_concat::cleanup"); Item_sum::cleanup(); - /* fix order list */ - for (uint i= 0; i < arg_count_order ; i++) - order[i]->item= &order[i]->item_ptr; - /* Free table and tree if they belong to this item (if item have not pointer to original item from which was made copy => it own its objects ) @@ -1802,6 +1796,13 @@ void Item_func_group_concat::cleanup() tree_mode= 0; delete_tree(tree); } + if (warning) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); + warning->set_msg(thd, warn_buff); + warning= 0; + } } DBUG_VOID_RETURN; } @@ -1809,19 +1810,6 @@ void Item_func_group_concat::cleanup() Item_func_group_concat::~Item_func_group_concat() { - /* - Free table and tree if they belong to this item (if item have not pointer - to original item from which was made copy => it own its objects ) - */ - if (!original) - { - if (warning_available) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); - warning->set_msg(current_thd, warn_buff); - } - } } @@ -2072,12 +2060,10 @@ String* Item_func_group_concat::val_str(String* str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - if (count_cut_values && !warning_available) - { - warning_available= TRUE; + if (count_cut_values && !warning) warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CUT_VALUE_GROUP_CONCAT, NULL); - } + ER_CUT_VALUE_GROUP_CONCAT, + ER(ER_CUT_VALUE_GROUP_CONCAT)); if (result.length()) return &result; if (tree_mode) diff --git a/sql/item_sum.h b/sql/item_sum.h index 2e85ba87468..5aa0d37190b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -674,7 +674,6 @@ class Item_func_group_concat : public Item_sum TMP_TABLE_PARAM *tmp_table_param; uint max_elements_in_tree; MYSQL_ERROR *warning; - bool warning_available; uint key_length; bool tree_mode; bool distinct; diff --git a/sql/protocol.cc b/sql/protocol.cc index 060dc14be10..887177c0a19 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1141,6 +1141,13 @@ bool Protocol_prep::store_time(TIME *tm) field_pos++; pos= buff+1; pos[0]= tm->neg ? 1 : 0; + if (tm->hour >= 24) + { + /* Fix if we come from Item::send */ + uint days= tm->hour/24; + tm->hour-= days*24; + tm->day+= days; + } int4store(pos+1, tm->day); pos[5]= (uchar) tm->hour; pos[6]= (uchar) tm->minute; diff --git a/sql/set_var.cc b/sql/set_var.cc index b5e479b9985..b16676de80e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2959,7 +2959,8 @@ void sys_var_thd_table_type::warn_deprecated(THD *thd) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DEPRECATED_SYNTAX, - ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", "storage_engine"); + ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", + "storage_engine"); } void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cd7b643e146..9313f8e2c1b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -363,6 +363,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) { + bool found_old_table; DBUG_ENTER("close_thread_tables"); if (thd->derived_tables && !skip_derived) @@ -385,8 +386,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_VOID_RETURN; // LOCK TABLES in use } - bool found_old_table=0; - if (thd->lock) { mysql_unlock_tables(thd, thd->lock); @@ -399,6 +398,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables)); + found_old_table= 0; while (thd->open_tables) found_old_table|=close_thread_table(thd, &thd->open_tables); thd->some_tables_deleted=0; @@ -2305,22 +2305,26 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> *sum_func_list, uint wild_num) { + bool is_stmt_prepare; + DBUG_ENTER("setup_wild"); if (!wild_num) - return 0; + DBUG_RETURN(0); + Item_arena *arena= thd->current_arena, backup; /* If we are in preparing prepared statement phase then we have change temporary mem_root to statement mem root to save changes of SELECT list */ - if (arena->is_stmt_prepare()) + if ((is_stmt_prepare= arena->is_stmt_prepare())) thd->set_n_backup_item_arena(arena, &backup); reg2 Item *item; List_iterator<Item> it(fields); while ( wild_num && (item= it++)) { - if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name && + if (item->type() == Item::FIELD_ITEM && + ((Item_field*) item)->field_name && ((Item_field*) item)->field_name[0] == '*' && !((Item_field*) item)->field) { @@ -2339,9 +2343,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, else if (insert_fields(thd,tables,((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it)) { - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); - return (-1); + DBUG_RETURN(-1); } if (sum_func_list) { @@ -2355,9 +2359,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, wild_num--; } } - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); - return 0; + if (is_stmt_prepare) + thd->restore_backup_item_arena(arena, &backup); + DBUG_RETURN(0); } /**************************************************************************** @@ -2398,19 +2402,20 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, SYNOPSIS setup_tables() - tables - tables list + tables table list - RETURN - 0 ok; In this case *map will includes the choosed index - 1 error - NOTE - Remap table numbers if INSERT ... SELECT - Check also that the 'used keys' and 'ignored keys' exists and set up the - table structure accordingly + NOTE + Remap table numbers if INSERT ... SELECT + Check also that the 'used keys' and 'ignored keys' exists and set up the + table structure accordingly + + This has to be called for all tables that are used by items, as otherwise + table->map is not set and all Item_field will be regarded as const items. - This has to be called for all tables that are used by items, as otherwise - table->map is not set and all Item_field will be regarded as const items. + RETURN + 0 ok; In this case *map will includes the choosed index + 1 error */ bool setup_tables(TABLE_LIST *tables) @@ -2584,7 +2589,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { table_map not_null_tables= 0; Item_arena *arena= thd->current_arena, backup; - + bool is_stmt_prepare= arena->is_stmt_prepare(); DBUG_ENTER("setup_conds"); thd->set_query_id=1; @@ -2622,11 +2627,11 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) !(specialflag & SPECIAL_NO_NEW_FUNC))) { table->outer_join= 0; - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->set_n_backup_item_arena(arena, &backup); *conds= and_conds(*conds, table->on_expr); table->on_expr=0; - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if ((*conds) && !(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds)) @@ -2635,7 +2640,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } if (table->natural_join) { - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->set_n_backup_item_arena(arena, &backup); /* Make a join of all fields with have the same name */ TABLE *t1= table->table; @@ -2677,7 +2682,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { *conds= and_conds(*conds, cond_and); // fix_fields() should be made with temporary memory pool - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { @@ -2689,7 +2694,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { table->on_expr= and_conds(table->on_expr, cond_and); // fix_fields() should be made with temporary memory pool - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if (table->on_expr && !table->on_expr->fixed) { @@ -2698,10 +2703,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } } } + else if (is_stmt_prepare) + thd->restore_backup_item_arena(arena, &backup); } } - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) { /* We are in prepared statement preparation code => we should store @@ -2714,7 +2721,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) DBUG_RETURN(test(thd->net.report_error)); err: - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); DBUG_RETURN(1); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f1c75a3b365..aa9d96e8b2a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -841,7 +841,8 @@ bool select_send::send_eof() /* Unlock tables before sending packet to gain some speed */ if (thd->lock) { - mysql_unlock_tables(thd, thd->lock); thd->lock=0; + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; } if (!thd->net.report_error) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index c94d5e52bcf..87644300535 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -102,12 +102,11 @@ void mysql_reset_errors(THD *thd) MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, const char *msg) { + MYSQL_ERROR *err= 0; DBUG_ENTER("push_warning"); if (thd->query_id != thd->warn_id) mysql_reset_errors(thd); - MYSQL_ERROR *err= NULL; - if (thd->warn_list.elements < thd->variables.max_error_count) { /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a0496a04bb2..2c48d1dca8f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1680,7 +1680,12 @@ bool select_create::send_eof() We should be able to just keep the table in the table cache. */ if (!table->tmp_table) + { hash_delete(&open_cache,(byte*) table); + /* Tell threads waiting for refresh that something has happened */ + if (table->version != refresh_version) + VOID(pthread_cond_broadcast(&COND_refresh)); + } lock=0; table=0; VOID(pthread_mutex_unlock(&LOCK_open)); @@ -1705,6 +1710,9 @@ void select_create::abort() hash_delete(&open_cache,(byte*) table); if (!create_info->table_existed) quick_rm_table(table_type, db, name); + /* Tell threads waiting for refresh that something has happened */ + if (table->version != refresh_version) + VOID(pthread_cond_broadcast(&COND_refresh)); } else if (!create_info->table_existed) close_temporary_table(thd, db, name); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 040a52ae30e..268198f74a2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -290,6 +290,7 @@ class THD; class select_result; class JOIN; class select_union; +class Procedure; class st_select_lex_unit: public st_select_lex_node { protected: TABLE_LIST result_table_list; @@ -336,6 +337,7 @@ public: st_select_lex *union_distinct; /* pointer to the last UNION DISTINCT */ bool describe; /* union exec() called for EXPLAIN */ + Procedure *last_procedure; /* Pointer to procedure, if such exists */ void init_query(); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a01b8c895c3..e727eced38f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3590,8 +3590,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors) { DBUG_ENTER("check_access"); - DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access, - thd->master_access)); + DBUG_PRINT("enter",("db: '%s' want_access: %lu master_access: %lu", + db ? db : "", want_access, thd->master_access)); #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; #endif @@ -3645,7 +3645,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, thd->priv_user, db, test(want_access & GRANT_ACL)); else db_access=thd->db_access; - // Remove SHOW attribute and access rights we already have + DBUG_PRINT("info",("db_access: %lu", db_access)); + /* Remove SHOW attribute and access rights we already have */ want_access &= ~(thd->master_access | EXTRA_ACL); db_access= ((*save_priv=(db_access | thd->master_access)) & want_access); @@ -4617,6 +4618,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->db= empty_c_string; ptr->db_length= 0; } + if (thd->current_arena->is_stmt_prepare()) + ptr->db= thd->strdup(ptr->db); ptr->alias= alias_str; if (lower_case_table_names && table->table.length) @@ -5142,9 +5145,12 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) */ for (table= update_list; table; table= table->next) { - if ((check_access(thd, UPDATE_ACL, table->db, - &table->grant.privilege, 0, 1) || - grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && + if (table->derived) + table->grant.privilege= SELECT_ACL; + else if ((check_access(thd, UPDATE_ACL, table->db, + &table->grant.privilege, 0, 1) || + grant_option && + check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))) @@ -5162,6 +5168,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) */ if (&lex->select_lex != lex->all_selects_list) { + DBUG_PRINT("info",("Checking sub query list")); for (table= tables; table; table= table->next) { if (table->table_in_update_from_clause) @@ -5174,7 +5181,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) if (table->table_list) table->grant= table->table_list->grant; } - else + else if (!table->derived) { if (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0e939498925..5a311eefacd 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1093,7 +1093,14 @@ static int mysql_test_select(Prepared_statement *stmt, } else { - List<Item> &fields= lex->select_lex.item_list; + /* Make copy of item list, as change_columns may change it */ + List<Item> fields(lex->select_lex.item_list); + + /* Change columns if a procedure like analyse() */ + if (unit->last_procedure && + unit->last_procedure->change_columns(fields)) + goto err_prep; + /* We can use lex->result as it should've been prepared in unit->prepare call above. @@ -1596,6 +1603,8 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, thd->current_arena= stmt; mysql_init_query(thd, (uchar *) thd->query, thd->query_length); + /* Reset warnings from previous command */ + mysql_reset_errors(thd); lex= thd->lex; lex->safe_to_cache_query= 0; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index f9a1908355b..0be554f58a2 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -229,8 +229,12 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, (ORDER*) 0 : (ORDER *)sl->order_list.first, (ORDER*) sl->group_list.first, sl->having, - (ORDER*) NULL, + (is_union ? (ORDER*) 0 : + (ORDER*) thd_arg->lex->proc_list.first), sl, this); + /* There are no * in the statement anymore (for PS) */ + sl->with_wild= 0; + last_procedure= join->procedure; if (res || thd_arg->is_fatal_error) goto err; if (sl == first_select) @@ -344,7 +348,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, 0, 0, fake_select_lex->order_list.elements, (ORDER*) fake_select_lex->order_list.first, - (ORDER*) NULL, NULL, (ORDER*) NULL, + (ORDER*) NULL, NULL, + (ORDER*) NULL, fake_select_lex, this); fake_select_lex->table_list.empty(); } |