summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore3
-rw-r--r--client/Makefile.am7
-rw-r--r--client/mysqldump.c35
-rw-r--r--client/mysqltest.c1723
-rw-r--r--config/ac-macros/yassl.m44
-rw-r--r--include/Makefile.am6
-rw-r--r--include/config-netware.h3
-rw-r--r--include/config-win.h20
-rw-r--r--include/my_user.h35
-rw-r--r--include/mysql_com.h8
-rw-r--r--include/sha1.h6
-rw-r--r--innobase/os/os0thread.c9
-rw-r--r--libmysql_r/Makefile.am4
-rw-r--r--libmysqld/Makefile.am2
-rw-r--r--mysql-test/include/have_euckr.inc4
-rw-r--r--mysql-test/include/have_gb2312.inc4
-rw-r--r--mysql-test/include/have_multi_ndb.inc8
-rw-r--r--mysql-test/include/master-slave.inc6
-rw-r--r--mysql-test/include/ps_query.inc1
-rwxr-xr-xmysql-test/mysql-test-run.pl58
-rw-r--r--mysql-test/mysql-test-run.sh67
-rw-r--r--mysql-test/r/ctype_euckr.result167
-rw-r--r--mysql-test/r/ctype_gb2312.result167
-rw-r--r--mysql-test/r/ctype_utf8.result8
-rw-r--r--mysql-test/r/fulltext.result8
-rw-r--r--mysql-test/r/func_group.result2
-rw-r--r--mysql-test/r/grant.result9
-rw-r--r--mysql-test/r/have_euckr.require2
-rw-r--r--mysql-test/r/have_gb2312.require2
-rw-r--r--mysql-test/r/having.result13
-rw-r--r--mysql-test/r/index_merge.result18
-rw-r--r--mysql-test/r/information_schema.result18
-rw-r--r--mysql-test/r/init_file.result1
-rw-r--r--mysql-test/r/mysql_client_test.result1
-rw-r--r--mysql-test/r/mysqldump.result36
-rw-r--r--mysql-test/r/mysqltest.result27
-rw-r--r--mysql-test/r/ndb_bitfield.result6
-rw-r--r--mysql-test/r/ps_2myisam.result2
-rw-r--r--mysql-test/r/ps_3innodb.result2
-rw-r--r--mysql-test/r/ps_4heap.result2
-rw-r--r--mysql-test/r/ps_5merge.result4
-rw-r--r--mysql-test/r/ps_6bdb.result2
-rw-r--r--mysql-test/r/ps_7ndb.result2
-rw-r--r--mysql-test/r/rpl_ddl.result4
-rw-r--r--mysql-test/r/rpl_ignore_revoke.result28
-rw-r--r--mysql-test/r/select.result26
-rw-r--r--mysql-test/r/sp.result67
-rw-r--r--mysql-test/r/trigger-compat.result6
-rw-r--r--mysql-test/r/trigger-grant.result21
-rw-r--r--mysql-test/r/trigger.result4
-rw-r--r--mysql-test/r/type_time.result24
-rw-r--r--mysql-test/r/view.result29
-rw-r--r--mysql-test/t/alias.test2
-rw-r--r--mysql-test/t/ctype_euckr.test33
-rw-r--r--mysql-test/t/ctype_gb2312.test33
-rw-r--r--mysql-test/t/ctype_utf8.test10
-rw-r--r--mysql-test/t/disabled.def1
-rw-r--r--mysql-test/t/fulltext.test8
-rw-r--r--mysql-test/t/grant.test12
-rw-r--r--mysql-test/t/group_by.test4
-rw-r--r--mysql-test/t/having.test12
-rw-r--r--mysql-test/t/index_merge.test30
-rw-r--r--mysql-test/t/init_file.test1
-rw-r--r--mysql-test/t/mysql_client_test.test2
-rw-r--r--mysql-test/t/mysqltest.test111
-rw-r--r--mysql-test/t/ndb_bitfield.test8
-rw-r--r--mysql-test/t/rpl_ignore_revoke-slave.opt1
-rw-r--r--mysql-test/t/rpl_ignore_revoke.test43
-rw-r--r--mysql-test/t/select.test33
-rw-r--r--mysql-test/t/sp.test80
-rw-r--r--mysql-test/t/type_time.test16
-rw-r--r--mysql-test/t/union.test21
-rw-r--r--mysql-test/t/view.test24
-rw-r--r--mysys/sha1.c16
-rw-r--r--ndb/config/common.mk.am2
-rw-r--r--ndb/include/util/Bitmask.hpp4
-rw-r--r--ndb/src/common/portlib/Makefile.am2
-rw-r--r--ndb/src/common/portlib/gcc.cpp7
-rw-r--r--ndb/src/kernel/blocks/ERROR_codes.txt4
-rw-r--r--ndb/src/kernel/blocks/dblqh/DblqhMain.cpp9
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp10
-rw-r--r--ndb/test/ndbapi/testDataBuffers.cpp26
-rw-r--r--ndb/test/ndbapi/test_event_merge.cpp1243
-rwxr-xr-xnetware/BUILD/compile-linux-tools2
-rw-r--r--netware/mysqld_safe.c12
-rw-r--r--sql-common/Makefile.am2
-rw-r--r--sql-common/my_user.c57
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/field.cc6
-rw-r--r--sql/item_cmpfunc.cc11
-rw-r--r--sql/item_cmpfunc.h5
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/password.c46
-rw-r--r--sql/sp.cc4
-rw-r--r--sql/sp_head.cc61
-rw-r--r--sql/sql_acl.cc9
-rw-r--r--sql/sql_base.cc20
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_handler.cc4
-rw-r--r--sql/sql_parse.cc22
-rw-r--r--sql/sql_select.cc46
-rw-r--r--sql/sql_show.cc15
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_yacc.yy6
-rw-r--r--strings/ctype-euc_kr.c37
-rw-r--r--strings/ctype-gb2312.c37
109 files changed, 3523 insertions, 1446 deletions
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 <my_global.h>
#include <my_sys.h>
+#include <my_user.h>
#include <m_string.h>
#include <m_ctype.h>
#include <hash.h>
@@ -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/client/mysqltest.c b/client/mysqltest.c
index 3a4ce5ce7cf..6a2a7b072de 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -42,7 +42,7 @@
**********************************************************************/
-#define MTEST_VERSION "2.5"
+#define MTEST_VERSION "2.6"
#include <my_global.h>
#include <mysql_embed.h>
@@ -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};
/* ************************************************************************ */
/*
@@ -118,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,
@@ -158,9 +159,12 @@ 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;
char *manager_pass=0;
int manager_port=MYSQL_MANAGER_PORT;
@@ -175,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;
@@ -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[]=
{
@@ -239,7 +247,10 @@ typedef struct
struct connection
{
MYSQL mysql;
+ /* Used when creating views and sp, to avoid implicit commit */
+ MYSQL* util_mysql;
char *name;
+ MYSQL_STMT* stmt;
};
typedef struct
@@ -247,8 +258,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 */
@@ -293,7 +302,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,
@@ -435,8 +444,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*);
@@ -463,9 +471,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;
@@ -490,10 +497,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)
{
@@ -540,11 +547,14 @@ 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)
{
+ if (next_con->stmt)
+ 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;
@@ -598,8 +608,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;
}
@@ -623,6 +632,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);
}
@@ -649,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");
@@ -665,7 +678,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;
@@ -733,7 +746,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);
@@ -745,17 +772,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;
}
@@ -872,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);
}
@@ -1042,7 +1070,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;
@@ -1069,14 +1096,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);
}
@@ -1117,47 +1137,54 @@ 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();
+ DBUG_VOID_RETURN;
}
+/*
+ Set variable from the result of a query
+
+ 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
+
-int var_query_set(VAR* v, const char *p, const char** p_end)
+ DESCRIPTION
+ let @<var_name> = `<query>`
+
+ 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 "$<var_name>_<column_name>"
+ Thus the tab separated output can be read from $<var_name> and
+ and each individual column can be read as $<var_name>_<col_name>
+
+*/
+
+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])
@@ -1170,21 +1197,40 @@ 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])
+ {
+#ifdef NOT_YET
+ /* Add to <var_name>_<col_name> */
+ 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]);
+#endif
+ /* 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;
@@ -1302,10 +1348,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];
@@ -1318,8 +1367,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
@@ -1353,25 +1405,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;
}
@@ -1400,7 +1443,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);
@@ -1417,7 +1460,6 @@ wait_for_position:
goto wait_for_position;
}
mysql_free_result(res);
- last_result=0;
if (rpl_parse)
mysql_enable_rpl_parse(mysql);
@@ -1456,13 +1498,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);
@@ -1594,6 +1636,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;
@@ -1661,7 +1704,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++)
@@ -1831,7 +1874,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;
}
@@ -1910,6 +1953,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"
@@ -1935,13 +1981,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)
@@ -1949,7 +1995,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);
@@ -2002,16 +2048,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;
@@ -2023,7 +2068,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;
}
@@ -2056,21 +2101,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)
{
@@ -2103,13 +2138,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.
@@ -2126,20 +2163,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;
}
@@ -2269,7 +2294,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);
@@ -2287,10 +2312,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,
@@ -2472,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;
@@ -2487,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:
@@ -2537,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 == '}')
@@ -2646,14 +2669,13 @@ 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 @<file_name> this will specify a file to ....
*/
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");
@@ -2672,10 +2694,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 == '#')
{
@@ -2700,20 +2725,12 @@ 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:
while (*p && my_isspace(charset_info, *p))
p++;
+
if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME))))
die(NullS);
@@ -2772,6 +2789,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.",
@@ -2833,8 +2859,6 @@ void usage()
#include <help_end.h>
-#include <help_end.h>
-
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -2868,6 +2892,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':
@@ -2952,27 +2977,29 @@ 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;
-}
-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];
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)))
@@ -2980,7 +3007,8 @@ 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);
@@ -3002,6 +3030,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)
@@ -3020,7 +3049,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;
@@ -3062,210 +3091,380 @@ 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)
{
+ MYSQL_BIND *bind;
+ my_bool *is_null;
+ ulong *length;
+ ulonglong num_rows;
+ uint col_idx, row_idx;
- /*
- Try to find out if we can run this statement using the prepared
- statement protocol.
+ /* 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 */
+ uint max_length= field[col_idx].max_length + 1;
+ char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE));
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP.
+ 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];
- If it is a '?' in the query it may be a SQL level prepared
- statement already and we can't do it twice
- */
+ 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 */
+ 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);
+ for (row_idx= 0; row_idx < num_rows; row_idx++)
+ {
+ 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++)
+ {
+ const char *val;
+ ulonglong len;
+ if (col_idx < max_replace_column && replace_column[col_idx])
+ {
+ val= replace_column[col_idx];
+ len= strlen(val);
+ }
+ 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 */
+ 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 (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);
+ 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 */
+ 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));
}
-static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
+/*
+ Append metadata for fields to output
+*/
+
+static void append_metadata(DYNAMIC_STRING *ds,
+ MYSQL_FIELD *field,
+ uint num_fields)
{
- 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)
+ MYSQL_FIELD *field_end;
+ dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
+ "Column_alias\tType\tLength\tMax length\tIs_null\t"
+ "Flags\tDecimals\tCharsetnr\n");
+
+ for (field_end= field+num_fields ;
+ field < field_end ;
+ field++)
{
- query = q->query;
- query_len = strlen(query);
+ 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);
+ longlong10_to_str((unsigned int) field->length, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ longlong10_to_str((unsigned 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);
}
- else
+}
+
+
+/*
+ Append affected row count and other info to output
+*/
+
+static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows,
+ const char *info)
+{
+ char buf[40];
+ sprintf(buf,"affected rows: %llu\n", affected_rows);
+ dynstr_append(ds, buf);
+ if (info)
{
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
+ dynstr_append(ds, "info: ");
+ dynstr_append(ds, info);
+ dynstr_append_mem(ds, "\n", 1);
}
- DBUG_PRINT("enter", ("query: '%-.60s'", query));
+}
+
- if (q->record_file[0])
+/*
+ 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++)
{
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds = &ds_tmp;
+ if (col_idx)
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append(ds, field[col_idx].name);
}
- else
- ds= &ds_res;
+ dynstr_append_mem(ds, "\n", 1);
+}
+
+/*
+ Fetch warnings from server and append to ds
+
+ RETURN VALUE
+ Number of warnings appended to ds
+*/
+
+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_RETURN(0);
+
+ /*
+ 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));
+
+ if (!(warn_res= mysql_store_result(mysql)))
+ die("Warning count is %u but didn't get any warnings",
+ count);
+
+ append_result(ds, warn_res);
+ mysql_free_result(warn_res);
+
+ DBUG_PRINT("warnings", ("%s", ds->str));
+
+ DBUG_RETURN(count);
+}
+
+
+
+/*
+ Run query using MySQL C API
+
+ SYNPOSIS
+ 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
+
+ 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, DYNAMIC_STRING *ds_warnings)
+{
+ 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)
{
- 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);
+ /*
+ Send the query
+ */
+ if (mysql_send_query(mysql, query, query_len))
+ {
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+ }
}
+ if (!(flags & QUERY_REAP))
+ DBUG_VOID_RETURN;
+
do
{
- if ((flags & QUERY_SEND) && !disable_query_log && !counter)
+ /*
+ 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))
{
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+
}
- 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)))
+ /*
+ 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))
{
- if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), ds))
- error= 1;
+ 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 */
+ ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */
LINT_INIT(affected_rows);
if (res)
{
- MYSQL_FIELD *field= mysql_fetch_fields(res);
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
uint num_fields= mysql_num_fields(res);
if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ append_metadata(ds, fields, num_fields);
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_table_headings(ds, fields, num_fields);
+
append_result(ds, res);
}
/*
- Need to call mysql_affected_rows() before the new
+ Need to call mysql_affected_rows() before the "new"
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
the middle of processing results from multi-statement, because
this will break protocol.
*/
- if (!disable_warnings && !mysql_more_results(mysql) &&
- mysql_warning_count(mysql))
+ if (!disable_warnings && !mysql_more_results(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
+ if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
{
dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
+ dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
}
}
+
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);
- }
- }
+ append_info(ds, affected_rows, mysql_info(mysql));
}
- 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;
+ /* 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 */
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
+ handle_no_error(command);
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
@@ -3273,12 +3472,12 @@ end:
variable then can be used from the test case itself.
*/
var_set_errno(mysql_errno(mysql));
- DBUG_RETURN(error);
+ DBUG_VOID_RETURN;
}
/*
- Handle errors which occurred after execution
+ Handle errors which occurred during execution
SYNOPSIS
handle_error()
@@ -3294,21 +3493,20 @@ end:
immediately.
RETURN VALUE
- 0 - OK
- 1 - Some other error was expected.
+ error - function will not return
*/
-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 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);
@@ -3337,7 +3535,7 @@ static int handle_error(const char *query, struct st_query *q,
dynstr_append(ds,"Got one of the listed errors\n");
}
/* OK */
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
}
@@ -3355,21 +3553,15 @@ static int 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);
- DBUG_RETURN(1);
+ die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
+ q->query, err_sqlstate, err_error,
+ 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_RETURN(0);
+ DBUG_VOID_RETURN;
}
@@ -3381,11 +3573,10 @@ static int handle_error(const char *query, struct st_query *q,
q - context of query
RETURN VALUE
- 0 - OK
- 1 - Some error was expected from this query.
+ error - function will not return
*/
-static int handle_no_error(struct st_query *q)
+static void handle_no_error(struct st_query *q)
{
DBUG_ENTER("handle_no_error");
@@ -3395,7 +3586,6 @@ static int handle_no_error(struct st_query *q)
/* 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)
@@ -3403,111 +3593,97 @@ static int handle_no_error(struct st_query *q)
/* 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);
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * 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
+ 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 int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
+static void run_query_stmt(MYSQL *mysql, struct st_query *command,
+ char *query, int query_len, DYNAMIC_STRING *ds,
+ DYNAMIC_STRING *ds_warnings)
{
- int error= 0; /* Function return code if "goto end;" */
- int err; /* Temporary storage of return code from calls */
- int query_len;
- 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;
+ DYNAMIC_STRING ds_prepare_warnings;
+ DYNAMIC_STRING ds_execute_warnings;
DBUG_ENTER("run_query_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
/*
- We must allocate a new stmt for each query in this program becasue this
- may be a new connection.
+ Init a new stmt if it's not alreday one created for this connectoon
*/
- if (!(stmt= mysql_stmt_init(mysql)))
- die("unable init stmt structure");
-
- if (q->type != Q_EVAL)
- {
- query= q->query;
- query_len= strlen(query);
- }
- else
+ if(!(stmt= cur_con->stmt))
{
- 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;
+ if (!(stmt= mysql_stmt_init(mysql)))
+ die("unable to init stmt structure");
+ cur_con->stmt= stmt;
}
- else
- ds= &ds_res;
- /* Store the query into the output buffer if not disabled */
- if (!disable_query_log)
+ /* Init dynamic strings for warnings */
+ if (!disable_warnings)
{
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
+ init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
}
/*
- We use the prepared statement interface but there is actually no
- '?' in the query. If unpreparable we fall back to use normal
- C API.
+ Prepare the query
*/
- if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT)
- return run_query_normal(mysql, q, flags);
-
- if (err != 0)
+ if (mysql_stmt_prepare(stmt, query, query_len))
{
- /*
- Preparing is part of normal execution and some errors may be expected
- */
- if (handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error= 1;
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
- /* We may have got warnings already, collect them if any */
- if (!disable_ps_warnings)
- run_query_stmt_handle_warnings(mysql, ds);
+ /*
+ Get the warnings from mysql_stmt_prepare and keep them in a
+ separate string
+ */
+ if (!disable_warnings)
+ append_warnings(&ds_prepare_warnings, mysql);
/*
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.
+#ifdef BUG14013_FIXED
+ /*
+ Use cursor when retrieving result
*/
+ if (cursor_protocol_enabled)
+ {
+ 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));
+ }
+#endif
- if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */
+ /*
+ Execute the query
+ */
+ if (mysql_stmt_execute(stmt))
{
- /* 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;
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
@@ -3518,313 +3694,387 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
*/
{
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 (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",
+ 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 ((err= mysql_stmt_store_result(stmt)) != 0)
+ if (mysql_stmt_store_result(stmt))
{
- /* 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;
+ 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 */
- if (handle_no_error(q))
+ handle_no_error(command);
+ if (!disable_result_log)
{
- error= 1;
- goto end;
- }
+ /*
+ 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 */
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
- num_rows= mysql_stmt_num_rows(stmt);
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
- /*
- 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);
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
- if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ append_stmt_result(ds, stmt, fields, num_fields);
- if (!display_result_vertically)
+ mysql_free_result(res); /* Free normal result set with meta data */
+
+ /* Clear prepare warnings */
+ dynstr_set(&ds_prepare_warnings, NULL);
+ }
+ else
{
- /* 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);
+ /*
+ This is a query without resultset
+ */
}
- /* Now we are to put the real result into the output buffer */
- /* FIXME when it works, create function append_stmt_result() */
+ if (!disable_warnings)
{
- 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);
+ /* Get the warnings from execute */
- /* Read result from each row */
- for (row_idx= 0; row_idx < num_rows; row_idx++)
+ /* Append warnings to ds - if there are any */
+ if (append_warnings(&ds_execute_warnings, mysql) ||
+ ds_prepare_warnings.length ||
+ ds_warnings->length)
{
- 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++)
- {
- const char *val;
- ulonglong len;
- if (col_idx < max_replace_column && replace_column[col_idx])
- {
- val= replace_column[col_idx];
- len= strlen(val);
- }
- else if (*bind[col_idx].is_null)
- {
- val= "NULL";
- len= 4;
- }
- else
- {
- /* FIXME is string terminated? */
- val= (const char *) bind[col_idx].buffer;
- len= *bind[col_idx].length;
- }
- 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);
+ 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);
+ if (ds_execute_warnings.length)
+ dynstr_append_mem(ds, ds_execute_warnings.str,
+ ds_execute_warnings.length);
}
-
- 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);
+ append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
- 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); /* 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);
+
+ 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
+ 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));
+#ifndef BUG15518_FIXED
mysql_stmt_close(stmt);
- DBUG_RETURN(error);
+ cur_con->stmt= NULL;
+#endif
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * 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\tType\tLength\tMax length\tIs_null\t"
- "Flags\tDecimals\tCharsetnr\n");
+/*
+ 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.
+*/
- for (field_end= field+num_fields ;
- field < field_end ;
- field++)
+static int util_query(MYSQL* org_mysql, const char* query){
+
+ MYSQL* mysql;
+ DBUG_ENTER("util_query");
+
+ if(!(mysql= cur_con->util_mysql))
{
- 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);
- longlong10_to_str((unsigned int) field->length, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- longlong10_to_str((unsigned 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);
+ DBUG_PRINT("info", ("Creating util_mysql"));
+ if (!(mysql= mysql_init(mysql)))
+ die("Failed in mysql_init()");
- 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);
+ 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);
}
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
+
+/*
+ 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)
{
- uint count;
- DBUG_ENTER("run_query_stmt_handle_warnings");
+ 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
+ */
+ 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_result, "", 16384, 65536);
+ ds= &ds_result;
+ }
+ else
+ ds= &ds_res;
+
+ /*
+ Log 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);
+ }
+
+ 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 (util_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)));
- if (!disable_warnings && (count= mysql_warning_count(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
+ {
+ /*
+ 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);
+
+ /*
+ Collect warnings from create of the view that should otherwise
+ have been produced when the SELECT was executed
+ */
+ append_warnings(&ds_warnings, cur_con->util_mysql);
+ }
+
+ dynstr_free(&query_str);
+
+ }
+
+ if (sp_protocol_enabled &&
+ complete_query &&
+ match_re(&sp_re, query))
{
/*
- 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...
+ Create the query as a stored procedure
+ Drop first since sp can exist from a failed mysqltest run
*/
- DBUG_ASSERT(!mysql_more_results(mysql));
+ DYNAMIC_STRING query_str;
+ init_dynamic_string(&query_str,
+ "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;",
+ query_len+64, 256);
+ 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 (util_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)));
+
+ /* Log error to create sp */
+ verbose_msg("Failed to create sp '%s' %d: %s", query_str.str,
+ mysql_errno(mysql), mysql_error(mysql));
- if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
+ }
+ else
{
- 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);
- }
+ sp_created= 1;
+
+ query= (char*)"CALL mysqltest_tmp_sp()";
+ query_len = strlen(query);
}
+ dynstr_free(&query_str);
}
- DBUG_VOID_RETURN;
+
+ /*
+ Find out how to run this query
+
+ 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
+ */
+ if (ps_protocol_enabled &&
+ complete_query &&
+ match_re(&ps_re, query))
+ run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings);
+ else
+ run_query_normal(mysql, command, flags, query, query_len,
+ ds, &ds_warnings);
+
+ if (sp_created)
+ {
+ 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 (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
+ die("Failed to drop view: %d: %s",
+ mysql_errno(mysql), mysql_error(mysql));
+ }
+
+ if (command->record_file[0])
+ {
+
+ /* 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);
+ 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:]]|"
@@ -3839,50 +4089,49 @@ 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);
+ my_regex_end();
}
/****************************************************************************/
@@ -3917,6 +4166,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] == ';')
{
/*
@@ -3956,7 +4206,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;
@@ -3965,12 +4215,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;
@@ -4004,7 +4252,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,
@@ -4012,8 +4260,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;
}
@@ -4021,7 +4268,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;
@@ -4034,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;
- lineno = lineno_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);
@@ -4065,17 +4316,21 @@ int main(int argc, char **argv)
{
cur_file->file= stdin;
cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
+ cur_file->lineno= 1;
}
- *lineno=1;
#ifndef EMBEDDED_LIBRARY
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)
@@ -4093,7 +4348,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);
@@ -4115,7 +4371,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:
@@ -4149,7 +4405,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);
@@ -4176,15 +4432,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;
@@ -4195,7 +4442,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;
@@ -4222,7 +4469,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;
@@ -4243,7 +4490,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;
@@ -4365,49 +4612,67 @@ int main(int argc, char **argv)
parser.current_line += current_line_inc;
}
- if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
- {
- /*
- my_stat() successful on result file. Check if we have not run a
- single query, but we do have a result file that contains data.
- Note that we don't care, if my_stat() fails. For example for
- non-existing or non-readable file we assume it's fine to have
- no query output from the test file, e.g. regarded as no error.
- */
- if (res_info.st_size)
- error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH);
- }
- if (ds_res.length && !error)
+ start_lineno= 0;
+
+ /*
+ 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 (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
+ - detect missing result file
+ - detect zero size result file
+ */
+ check_result(&ds_res, result_file, 0);
+ }
}
else
{
- /* Print the result to stdout */
+ /* No result_file specified to compare with, print to stdout */
printf("%s", ds_res.str);
}
}
- dynstr_free(&ds_res);
+ else
+ {
+ die("The test didn't produce any output");
+ }
- if (!silent)
+ if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
{
- if (error)
- printf("not ok\n");
- else
- printf("ok\n");
+ /*
+ 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)
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 */
}
@@ -5204,12 +5469,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
*****************************************************************************/
@@ -5351,7 +5610,7 @@ static char *subst_env_var(const char *str)
*/
#undef popen /* Remove wrapper */
-#ifdef __WIN__
+#ifdef __WIN__
#define popen _popen /* redefine for windows */
#endif
@@ -5367,3 +5626,5 @@ FILE *my_popen(const char *cmd, const char *mode __attribute__((unused)))
}
#endif /* __NETWARE__ or __WIN__*/
+
+
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..07c32e3127b 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -30,10 +30,11 @@ 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
+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 +42,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/include/config-netware.h b/include/config-netware.h
index f517e3c34d3..5a8b926a669 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -95,6 +95,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/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
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 <my_global.h>
+
+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/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/innobase/os/os0thread.c b/innobase/os/os0thread.c
index 847d0ee1cc7..1d1cb77b336 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -148,6 +148,15 @@ os_thread_create(
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++;
os_mutex_exit(os_sync_mutex);
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
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/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/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/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/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 2c53b94a248..fdee6d96d3a 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -152,6 +152,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
@@ -193,6 +194,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;
@@ -268,6 +272,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;
@@ -509,6 +514,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,
@@ -762,6 +770,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;
@@ -911,6 +920,7 @@ sub command_line_setup () {
}
$path_timefile= "$opt_vardir/log/mysqltest-time";
+ $path_mysqltest_log= "$opt_vardir/log/mysqltest.log";
}
@@ -955,7 +965,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");
@@ -1886,6 +1908,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);
}
# ----------------------------------------------------------------------
@@ -2046,7 +2073,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);
@@ -2272,7 +2299,7 @@ sub mysqld_start ($$$$) {
mtr_init_args(\$args);
- if ( defined $opt_valgrind )
+ if ( defined $opt_valgrind_mysqld )
{
valgrind_arguments($args, \$exe);
}
@@ -2603,6 +2630,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, ....
@@ -2711,6 +2753,7 @@ sub valgrind_arguments {
mtr_add_arg($args, split(' ', $opt_valgrind_options));
}
+
mtr_add_arg($args, $$exe);
$$exe= $opt_valgrind || "valgrind";
@@ -2734,6 +2777,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
@@ -2786,9 +2833,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
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 982aed9c633..5ab735dc2cb 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,10 +770,6 @@ then
SLAVE_MYSQLD=$MYSQLD
fi
-if [ x$DO_VALGRIND_MYSQL_TEST = x1 ] ; then
- MYSQL_TEST="$VALGRIND $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" ]
@@ -819,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
@@ -829,6 +839,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
@@ -991,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
}
@@ -1770,13 +1793,17 @@ 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
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"
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/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index c57b06f4895..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;
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/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/grant.result b/mysql-test/r/grant.result
index 448847bc919..eea29161de8 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -615,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/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/r/having.result b/mysql-test/r/having.result
index 35a1358dd0c..379c2f83c78 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -128,6 +128,19 @@ 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;
create table t1 (col1 int, col2 varchar(5), col_t1 int);
create table t2 (col1 int, col2 varchar(5), col_t2 int);
create table t3 (col1 int, col2 varchar(5), col_t3 int);
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/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/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/mysqldump.result b/mysql-test/r/mysqldump.result
index 62d2b46e617..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 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;
@@ -1995,13 +1992,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
-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 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
@@ -2376,7 +2368,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 +2524,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/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result
index 5ff931dafb5..067054510c2 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
;;;;;;;;
@@ -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: At line 1: End of line junk detected: "sleep 7
+# Another comment
+"
mysqltest: At line 1: Extra delimiter ";" found
mysqltest: At line 1: Extra delimiter ";" found
MySQL
@@ -301,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
@@ -328,6 +332,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;
@@ -350,9 +355,10 @@ 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
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
@@ -391,20 +397,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;
-drop table t1;
-create table t1 (a int primary key);
+mysqltest: At line 3: query '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
+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';
@@ -413,3 +419,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;
+drop table t1;
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/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/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/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/r/select.result b/mysql-test/r/select.result
index e2c4609d902..df68cdfff53 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -3337,6 +3337,30 @@ 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;
+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;
create table t1(f1 char, f2 char not null);
insert into t1 values(null,'a');
create table t2 (f2 char not null);
@@ -3345,3 +3369,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/r/sp.result b/mysql-test/r/sp.result
index ded9754f172..d56cf086cdf 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|
@@ -1097,6 +1102,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|
@@ -1106,11 +1167,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/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/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index deb60a95f21..442435b0459 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/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/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/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/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index a96564f4e76..c9b2b9fc18f 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -868,6 +868,16 @@ 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/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
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/mysql-test/t/grant.test b/mysql-test/t/grant.test
index e806df5e91c..9a8b7a19c59 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -499,4 +499,16 @@ revoke all privileges on ÂÄ.* from root@localhost;
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 ''
+#
+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@;
+
# End of 4.1 tests
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/having.test b/mysql-test/t/having.test
index fb223d2a9af..1cc894697f9 100644
--- a/mysql-test/t/having.test
+++ b/mysql-test/t/having.test
@@ -123,6 +123,18 @@ 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/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/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 440a7787985..5cf49185c30 100644
--- a/mysql-test/t/mysqltest.test
+++ b/mysql-test/t/mysqltest.test
@@ -365,6 +365,15 @@ select 3 from t1 ;
--exec $MYSQL_TEST < var/tmp/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/tmp/mysqltest.sql
+--system echo "# Another comment" >> var/tmp/mysqltest.sql
+--error 1
+--exec $MYSQL_TEST < var/tmp/mysqltest.sql 2>&1
+
+#
# Extra delimiter
#
--error 1
@@ -531,6 +540,42 @@ echo $novar1;
--exec echo "let hi;" | $MYSQL_TEST 2>&1
# ----------------------------------------------------------------------------
+# Test to assign let from query
+# let $<var_name>=`<query>`;
+# ----------------------------------------------------------------------------
+--disable_parsing
+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
+--enable_parsing
+# ----------------------------------------------------------------------------
# Test source command
# ----------------------------------------------------------------------------
@@ -680,7 +725,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
@@ -728,20 +773,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
@@ -769,7 +814,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
@@ -839,7 +884,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
@@ -946,13 +991,36 @@ select "this will not be executed";
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
#
# Bug #11731 mysqltest in multi-statement queries ignores errors in
# 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
@@ -967,14 +1035,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
---error 1
---exec test -s $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 ! -s $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
@@ -986,12 +1053,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;
-
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/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
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index a85b82a7767..01d5f2eb4d1 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -2807,6 +2807,33 @@ EXPLAIN SELECT t2.key_a,foo
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;
+
+#
+# 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;
+
+#
# Bug#15268 Unchecked null value caused server crash
#
create table t1(f1 char, f2 char not null);
@@ -2815,3 +2842,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/mysql-test/t/sp.test b/mysql-test/t/sp.test
index f73288f04ba..a1eba73635e 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -1157,6 +1157,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|
@@ -1234,8 +1239,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
#
@@ -1316,6 +1319,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|
@@ -1327,11 +1397,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/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
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index 6de90dd446d..ce6153d2b78 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;
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/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/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/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;
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
diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt
index 0be5e91cd71..eab4a8eb623 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 6007
Next DBDIH 7174
Next DBTC 8037
@@ -314,6 +314,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 803377f9dd1..b7c137d539f 100644
--- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
+++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
@@ -9264,6 +9264,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
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.",
diff --git a/ndb/test/ndbapi/testDataBuffers.cpp b/ndb/test/ndbapi/testDataBuffers.cpp
index aaecb6ee61e..83a063d60d3 100644
--- a/ndb/test/ndbapi/testDataBuffers.cpp
+++ b/ndb/test/ndbapi/testDataBuffers.cpp
@@ -254,12 +254,6 @@ testcase(Ndb_cluster_connection&cc, int flag)
ndbout << "tab=" << tab << " cols=" << attrcnt
<< " size max=" << smax << " tot=" << stot << endl;
- ndb = new Ndb(&cc, "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(Ndb_cluster_connection&cc, int flag)
return ndberror("key %d not found", k);
ndbout << "scanned " << key << endl;
- ndb = 0;
ndbout << "done" << endl;
return 0;
}
@@ -605,6 +598,7 @@ NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuff
return NDBT_ProgramExit(NDBT_WRONGARGS);
}
}
+
unsigned ok = true;
Ndb_cluster_connection con;
@@ -613,6 +607,20 @@ NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuff
return NDBT_ProgramExit(NDBT_FAILED);
}
+ ndb = new Ndb(&con, "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<<testbits); flag++) {
@@ -621,9 +629,13 @@ NDB_COMMAND(testDataBuffers, "testDataBuffers", "testDataBuffers", "testDataBuff
if (! kontinue)
goto out;
}
+ NdbDictionary::Dictionary * dict = ndb->getDictionary();
+ dict->dropTable(tab);
}
}
+
out:
+ delete ndb;
return NDBT_ProgramExit(ok ? NDBT_OK : NDBT_FAILED);
}
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 (i == getcol("pk2").no) {
- sprintf(d[0].pk2, "%-*u", g_charlen, d[0].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 (t == Op::DEL) {
- d[0].ind[i] = -1;
- continue;
- }
- if (i == getcol("seq").no) {
- d[0].seq = g_seq++;
- d[0].ind[i] = 0;
+ }
+ 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;
}
- uint u;
- u = urandom(100);
- if (c.nullable && u < 20) {
- d[0].ind[i] = 1;
- continue;
+ 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:
+ {
+ 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:
{
- u = urandom(0);
- Uint32* p = (Uint32*)d[0].ptr[i];
+ 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);
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
diff --git a/netware/mysqld_safe.c b/netware/mysqld_safe.c
index 3a1672fdf61..9db8a441ca3 100644
--- a/netware/mysqld_safe.c
+++ b/netware/mysqld_safe.c
@@ -258,11 +258,11 @@ void finish_defaults()
void read_defaults(arg_list_t *pal)
{
arg_list_t al;
- char defaults_file[PATH_MAX];
+ char defaults_file[PATH_MAX];
char mydefaults[PATH_MAX];
char line[PATH_MAX];
FILE *fp;
-
+
// defaults output file
snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir);
remove(defaults_file);
@@ -270,7 +270,7 @@ void read_defaults(arg_list_t *pal)
// mysqladmin file
snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir);
- // args
+ // args
init_args(&al);
add_arg(&al, mydefaults);
if (default_option[0])
@@ -279,11 +279,11 @@ void read_defaults(arg_list_t *pal)
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);
-
+
// gather defaults
if ((fp= fopen(defaults_file, "r")) != NULL)
{
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 <my_user.h>
+#include <m_string.h>
+
+
+/*
+ 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/field.cc b/sql/field.cc
index 1f3649e1b88..d72c4913d99 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8981,11 +8981,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:
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<Item_field> 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 b4064fb45b8..98ccefd08ab 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
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 8056e00e0cf..fe02e7c5b49 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -153,11 +153,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/mysqld.cc b/sql/mysqld.cc
index 1f32a8285d1..80b22f726ae 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3322,6 +3322,11 @@ int main(int argc, char **argv)
}
}
#endif
+#ifdef __NETWARE__
+ /* Increasing stacksize of threads on NetWare */
+
+ pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE);
+#endif
(void) thr_setconcurrency(concurrency); // 10 by default
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<Item> &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<Item> &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;
/*
diff --git a/sql/password.c b/sql/password.c
index 562df3ae226..506e1aa36a2 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -395,15 +395,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, (uint) strlen(password));
- sha1_result(&sha1_context, (uint8 *) to);
+ mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) 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);
@@ -434,20 +434,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, (uint) strlen(password));
- sha1_result(&sha1_context, hash_stage1);
+ mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) 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);
}
@@ -480,17 +480,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);
}
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..96bf2c51b02 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -31,6 +31,8 @@
#define SP_STMT_PRINT_MAXLEN 40
+#include <my_user.h>
+
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;
}
@@ -3137,7 +3131,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 */
@@ -3207,10 +3208,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
@@ -3222,14 +3227,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;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 061020e1952..130674b47f9 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1543,7 +1543,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);
@@ -2489,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;
@@ -2607,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;
@@ -4638,7 +4639,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;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index be3b64a5ef6..9d1720cc527 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1388,10 +1388,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)
@@ -1464,8 +1474,10 @@ bool reopen_table(TABLE *table,bool locked)
(*field)->table_name= &table->alias;
}
for (key=0 ; key < table->s->keys ; key++)
+ {
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
table->key_info[key].key_part[part].field->table= table;
+ }
if (table->triggers)
table->triggers->set_table(table);
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_handler.cc b/sql/sql_handler.cc
index fae48c7d164..e9e1e79daaf 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -423,7 +423,11 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (cond && ((!cond->fixed &&
cond->fix_fields(thd, &cond)) || cond->check_cols(1)))
+ {
+ if (table->query_id != thd->query_id)
+ cond->cleanup(); // File was reopened
goto err0;
+ }
if (keyname)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9cdb288c045..a7346c9fbed 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);
@@ -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);
@@ -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);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1c7293fd89d..be255d1f790 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_func(thd, ref_pointer_array, all_fields);
+ 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)
@@ -3518,13 +3519,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;
/*
@@ -4507,13 +4527,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;
/*
@@ -8640,6 +8662,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
have null
*/
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);
null_count= 0;
}
}
@@ -8859,7 +8886,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
}
- if (distinct)
+ if (distinct && field_count != param->hidden_field_count)
{
/*
Create an unique key or an unique constraint over all columns
@@ -9917,6 +9944,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)
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 089314078a6..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();
}
@@ -2887,7 +2890,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 +3032,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 +3216,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_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)
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;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 25e10362ece..49f2182e12a 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);
@@ -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
{
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index 97fea517c1b..5e357e0b65c 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 */
@@ -8657,7 +8692,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 f5d9b2627cd..f3938cc27ba 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 */
@@ -5708,7 +5743,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 */