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/BUILD/Makefile.am b/BUILD/Makefile.am
index 45c1aaa1a76..a5f3623c25e 100644
--- a/BUILD/Makefile.am
+++ b/BUILD/Makefile.am
@@ -21,27 +21,46 @@ EXTRA_DIST = FINISH.sh \
SETUP.sh \
autorun.sh \
check-cpu \
+ cleanup \
compile-alpha \
compile-alpha-ccc \
compile-alpha-cxx \
compile-alpha-debug \
+ compile-amd64-debug-max \
+ compile-amd64-max \
+ compile-darwin-mwcc \
+ compile-dist \
+ compile-hpux11-parisc2-aCC \
compile-ia64-debug-max \
+ compile-irix-mips64-mipspro \
compile-pentium \
compile-pentium-debug \
compile-pentium-debug-max \
+ compile-pentium-debug-max-no-embedded \
+ compile-pentium-debug-max-no-ndb \
compile-pentium-debug-no-bdb \
compile-pentium-debug-openssl \
compile-pentium-debug-yassl \
compile-pentium-gcov \
compile-pentium-gprof \
+ compile-pentium-icc \
+ compile-pentium-icc-valgrind-max \
+ compile-pentium-icc-yassl \
compile-pentium-max \
compile-pentium-myodbc \
compile-pentium-mysqlfs-debug \
compile-pentium-pgcc \
+ compile-pentium-valgrind-max \
+ compile-pentium64-debug \
+ compile-pentium64-debug-max \
+ compile-pentium64-valgrind-max \
+ compile-ppc \
+ compile-ppc-debug \
+ compile-ppc-debug-max \
+ compile-ppc-debug-max-no-ndb \
+ compile-ppc-max \
compile-solaris-sparc \
compile-solaris-sparc-debug \
- compile-irix-mips64-mipspro \
- compile-hpux11-parisc2-aCC \
compile-solaris-sparc-forte \
compile-solaris-sparc-purify
diff --git a/Docs/Makefile.am b/Docs/Makefile.am
index 542c82d8f58..f512aa9e29e 100644
--- a/Docs/Makefile.am
+++ b/Docs/Makefile.am
@@ -45,22 +45,22 @@ CLEAN_FILES: $(TXT_FILES)
GT = $(srcdir)/Support/generate-text-files.pl
../INSTALL-SOURCE: mysql.info $(GT)
- perl -w $(GT) $< "installing-source" "windows-source-build" > $@
+ perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@
../INSTALL-WIN-SOURCE: mysql.info $(GT)
- perl -w $(GT) $< "windows-source-build" "post-installation" > $@
+ perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@
# We put the description for the binary installation here so that
# people who download source wont have to see it. It is moved up to
# the toplevel by the script that makes the binary tar files.
INSTALL-BINARY: mysql.info $(GT)
- perl -w $(GT) $< "installing-binary" "installing-source" > $@
+ perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@
../EXCEPTIONS-CLIENT: mysql.info $(GT)
- perl -w $(GT) $< "mysql-floss-license-exception" "function-index" > $@
+ perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@
../support-files/MacOSX/ReadMe.txt: mysql.info $(GT)
- perl -w $(GT) $< "mac-os-x-installation" "netware-installation" > $@
+ perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/VC++Files/client/mysqldump.vcproj b/VC++Files/client/mysqldump.vcproj
index b6a33596083..39b83fd46f3 100644
--- a/VC++Files/client/mysqldump.vcproj
+++ b/VC++Files/client/mysqldump.vcproj
@@ -226,6 +226,33 @@
PreprocessorDefinitions=""/>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/VC++Files/sql/mysqld.vcproj b/VC++Files/sql/mysqld.vcproj
index 49bf74ae5a2..d5a10db380a 100644
--- a/VC++Files/sql/mysqld.vcproj
+++ b/VC++Files/sql/mysqld.vcproj
@@ -3744,6 +3744,81 @@
PreprocessorDefinitions=""/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#include
+#include
#include
#include
#include
@@ -1306,7 +1307,7 @@ static uint dump_routines_for_db(char *db)
fprintf(sql_file, "DELIMITER ;\n");
if (lock_tables)
- mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"));
DBUG_RETURN(0);
}
@@ -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 */
@@ -2095,7 +2124,10 @@ static void dump_table(char *table, char *db)
else
res=mysql_store_result(sock);
if (!res)
+ {
DB_error(sock, "when retrieving data from server");
+ goto err;
+ }
if (verbose)
fprintf(stderr, "-- Retrieving rows...\n");
if (mysql_num_fields(res) != num_fields)
@@ -2625,7 +2657,7 @@ static int dump_all_tables_in_db(char *database)
check_io(md_result_file);
}
if (lock_tables)
- mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"));
return 0;
} /* dump_all_tables_in_db */
@@ -2680,23 +2712,23 @@ static my_bool dump_all_views_in_db(char *database)
check_io(md_result_file);
}
if (lock_tables)
- mysql_query(sock,"UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"));
return 0;
} /* dump_all_tables_in_db */
/*
- get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
- table name from the server for the table name given on the command line.
- we do this because the table name given on the command line may be a
+ get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
+ table name from the server for the table name given on the command line.
+ we do this because the table name given on the command line may be a
different case (e.g. T1 vs t1)
-
+
RETURN
int - 0 if a tablename was retrieved. 1 if not
*/
-static int get_actual_table_name(const char *old_table_name,
- char *new_table_name,
+static int get_actual_table_name(const char *old_table_name,
+ char *new_table_name,
int buf_size)
{
int retval;
@@ -2708,7 +2740,7 @@ static int get_actual_table_name(const char *old_table_name,
/* Check memory for quote_for_like() */
DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
- my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
+ my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
quote_for_like(old_table_name, show_name_buff));
if (mysql_query_with_error_report(sock, 0, query))
@@ -2717,7 +2749,7 @@ static int get_actual_table_name(const char *old_table_name,
}
retval = 1;
-
+
if ((table_res= mysql_store_result(sock)))
{
my_ulonglong num_rows= mysql_num_rows(table_res);
@@ -2839,7 +2871,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
check_io(md_result_file);
}
if (lock_tables)
- mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
+ VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"));
DBUG_RETURN(0);
} /* dump_selected_tables */
diff --git a/client/mysqltest.c b/client/mysqltest.c
index ba1b92b31a3..ca28419fa4f 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -42,7 +42,7 @@
**********************************************************************/
-#define MTEST_VERSION "2.5"
+#define MTEST_VERSION "2.6"
#include
#include
@@ -108,7 +108,8 @@
enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC,
OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH,
- OPT_SSL_CIPHER,OPT_PS_PROTOCOL};
+ OPT_SSL_CIPHER,OPT_PS_PROTOCOL,OPT_SP_PROTOCOL,OPT_CURSOR_PROTOCOL,
+ OPT_VIEW_PROTOCOL};
/* ************************************************************************ */
/*
@@ -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
-int var_query_set(VAR* v, const char *p, const char** p_end)
+ SYNOPSIS
+ var_query_set()
+ var variable to set from query
+ query start of query string to execute
+ query_end end of the query string to execute
+
+
+ DESCRIPTION
+ let @ = ``
+
+ Execute the query and assign the first row of result to var as
+ a tab separated strings
+
+ Also assign each column of the result set to
+ variable "$_"
+ Thus the tab separated output can be read from $ and
+ and each individual column can be read as $_
+
+*/
+
+int var_query_set(VAR* var, const char *query, const char** query_end)
{
- char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p));
+ char* end = (char*)((query_end && *query_end) ?
+ *query_end : query + strlen(query));
MYSQL_RES *res;
MYSQL_ROW row;
MYSQL* mysql = &cur_con->mysql;
LINT_INIT(res);
- while (end > p && *end != '`')
+ while (end > query && *end != '`')
--end;
- if (p == end)
+ if (query == end)
die("Syntax error in query, missing '`'");
- ++p;
+ ++query;
- if (mysql_real_query(mysql, p, (int)(end - p)) ||
+ if (mysql_real_query(mysql, query, (int)(end - query)) ||
!(res = mysql_store_result(mysql)))
{
*end = 0;
- die("Error running query '%s': %s", p, mysql_error(mysql));
+ die("Error running query '%s': %d: %s", query,
+ mysql_errno(mysql) ,mysql_error(mysql));
}
if ((row = mysql_fetch_row(res)) && row[0])
@@ -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 _ */
+ 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,22 +2138,13 @@ 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))
- {
- /*
- Fail if there was no error but we expected it.
- We also don't want to have connection in this case.
- */
- mysql_close(con);
- *create_conn= 0;
- error= 1;
- goto err;
- }
+
+ handle_no_error(q);
/*
TODO: change this to 0 in future versions, but the 'kill' test relies on
@@ -2126,20 +2152,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 +2283,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 +2301,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 +2486,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 +2501,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 +2548,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 +2658,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 @ 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 +2683,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 +2714,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);
@@ -2731,10 +2737,8 @@ end:
static struct my_option my_long_options[] =
{
- {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
- 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir,
(gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test,
@@ -2742,13 +2746,17 @@ static struct my_option my_long_options[] =
{"compress", 'C', "Use the compressed server/client protocol.",
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
- {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- 0, 0, 0, 0, 0, 0},
+ {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef DBUG_OFF
+ {"debug", '#', "This is a non-debug version. Catch this and exit",
+ 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+ {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.",
- (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0,
- 0, 0, 0, 0, 0},
{"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.",
(gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
@@ -2757,6 +2765,9 @@ static struct my_option my_long_options[] =
{"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.",
(gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG,
MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0},
+ {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.",
+ (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0,
+ 0, 0, 0, 0, 0},
{"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT,
"Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout,
(gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0},
@@ -2767,6 +2778,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.",
@@ -2828,8 +2848,6 @@ void usage()
#include
-#include
-
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -2863,6 +2881,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':
@@ -2947,27 +2966,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)))
@@ -2975,7 +2996,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);
@@ -2997,6 +3019,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)
@@ -3015,7 +3038,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;
@@ -3057,678 +3080,121 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
/*
-* flags control the phased/stages of query execution to be performed
-* if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on
-* the result will be read - for regular query, both bits must be on
+ Append all results from ps execution to the dynamic string separated
+ with '\t'. Values may be converted with 'replace_column'
*/
-static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags);
-static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags);
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds);
-static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds);
-
-static int run_query(MYSQL *mysql, struct st_query *q, int flags)
+static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
+ MYSQL_FIELD *field, uint num_fields)
{
-
- /*
- Try to find out if we can run this statement using the prepared
- statement protocol.
-
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP.
-
- If it is a '?' in the query it may be a SQL level prepared
- statement already and we can't do it twice
- */
-
- if (ps_protocol_enabled && disable_info &&
- (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query))
- return run_query_stmt(mysql, q, flags);
- return run_query_normal(mysql, q, flags);
-}
-
-
-static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
-{
- MYSQL_RES* res= 0;
- uint i;
- int error= 0, err= 0, counter= 0;
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
- DYNAMIC_STRING eval_query;
- char* query;
- int query_len, got_error_on_send= 0;
- DBUG_ENTER("run_query_normal");
- DBUG_PRINT("enter",("flags: %d", flags));
-
- if (q->type != Q_EVAL)
- {
- query = q->query;
- query_len = strlen(query);
- }
- else
- {
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
- }
- DBUG_PRINT("enter", ("query: '%-.60s'", query));
-
- if (q->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds = &ds_tmp;
- }
- else
- ds= &ds_res;
-
- if (flags & QUERY_SEND)
- {
- got_error_on_send= mysql_send_query(mysql, query, query_len);
- if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY)
- die("unable to send query '%s' (mysql_errno=%d , errno=%d)",
- query, mysql_errno(mysql), errno);
- }
-
- do
- {
- if ((flags & QUERY_SEND) && !disable_query_log && !counter)
- {
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
- }
- if (!(flags & QUERY_REAP))
- DBUG_RETURN(0);
-
- if (got_error_on_send ||
- (!counter && (*mysql->methods->read_query_result)(mysql)) ||
- (!(last_result= res= mysql_store_result(mysql)) &&
- mysql_field_count(mysql)))
- {
- if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), ds))
- error= 1;
- goto end;
- }
-
- if (!disable_result_log)
- {
- ulong affected_rows; /* Ok to be undef if 'disable_info' is set */
- LINT_INIT(affected_rows);
-
- if (res)
- {
- MYSQL_FIELD *field= mysql_fetch_fields(res);
- uint num_fields= mysql_num_fields(res);
-
- if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
-
- if (!display_result_vertically)
- {
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append(ds, field[i].name);
- }
- dynstr_append_mem(ds, "\n", 1);
- }
- append_result(ds, res);
- }
-
- /*
- Need to call mysql_affected_rows() before the new
- query to find the warnings
- */
- if (!disable_info)
- affected_rows= (ulong)mysql_affected_rows(mysql);
-
- /*
- Add all warnings to the result. We can't do this if we are in
- the middle of processing results from multi-statement, because
- this will break protocol.
- */
- if (!disable_warnings && !mysql_more_results(mysql) &&
- mysql_warning_count(mysql))
- {
- MYSQL_RES *warn_res=0;
- uint count= mysql_warning_count(mysql);
- if (!mysql_real_query(mysql, "SHOW WARNINGS", 13))
- warn_res= mysql_store_result(mysql);
- if (!warn_res)
- die("Warning count is %u but didn't get any warnings", count);
- else
- {
- dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
- }
- if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lu\n", affected_rows);
- dynstr_append(ds, buf);
- if (mysql_info(mysql))
- {
- dynstr_append(ds, "info: ");
- dynstr_append(ds, mysql_info(mysql));
- dynstr_append_mem(ds, "\n", 1);
- }
- }
- }
-
- if (record)
- {
- if (!q->record_file[0] && !result_file)
- die("Missing result file");
- if (!result_file)
- str_to_file(q->record_file, ds->str, ds->length);
- }
- else if (q->record_file[0])
- {
- error= check_result(ds, q->record_file, q->require_file);
- }
- if (res)
- mysql_free_result(res);
- last_result= 0;
- counter++;
- } while (!(err= mysql_next_result(mysql)));
- if (err > 0)
- {
- /* We got an error from mysql_next_result, maybe expected */
- if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), ds))
- error= 1;
- goto end;
- }
-
- /* If we come here the query is both executed and read successfully */
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
-
-end:
- free_replace();
- last_result=0;
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- if (q->type == Q_EVAL)
- dynstr_free(&eval_query);
-
- /*
- We save the return code (mysql_errno(mysql)) from the last call sent
- to the server into the mysqltest builtin variable $mysql_errno. This
- variable then can be used from the test case itself.
- */
- var_set_errno(mysql_errno(mysql));
- DBUG_RETURN(error);
-}
-
-
-/*
- Handle errors which occurred after execution
-
- SYNOPSIS
- handle_error()
- query - query string
- q - query context
- err_errno - error number
- err_error - error message
- err_sqlstate - sql state
- ds - dynamic string which is used for output buffer
-
- NOTE
- If there is an unexpected error this function will abort mysqltest
- immediately.
-
- RETURN VALUE
- 0 - OK
- 1 - Some other error was expected.
-*/
-
-static int handle_error(const char *query, struct st_query *q,
- unsigned int err_errno, const char *err_error,
- const char* err_sqlstate, DYNAMIC_STRING *ds)
-{
- uint i;
-
- DBUG_ENTER("handle_error");
-
- if (q->require_file)
- abort_not_supported_test();
-
- if (q->abort_on_error)
- die("query '%s' failed: %d: %s", query, err_errno, err_error);
-
- for (i= 0 ; (uint) i < q->expected_errors ; i++)
- {
- if (((q->expected_errno[i].type == ERR_ERRNO) &&
- (q->expected_errno[i].code.errnum == err_errno)) ||
- ((q->expected_errno[i].type == ERR_SQLSTATE) &&
- (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0)))
- {
- if (!disable_result_log)
- {
- if (q->expected_errors == 1)
- {
- /* Only log error if there is one possible error */
- dynstr_append_mem(ds, "ERROR ", 6);
- replace_dynstr_append(ds, err_sqlstate);
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append(ds, err_error);
- dynstr_append_mem(ds,"\n",1);
- }
- /* Don't log error if we may not get an error */
- else if (q->expected_errno[0].type == ERR_SQLSTATE ||
- (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0))
- dynstr_append(ds,"Got one of the listed errors\n");
- }
- /* OK */
- DBUG_RETURN(0);
- }
- }
-
- DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors));
-
- if (!disable_result_log)
- {
- dynstr_append_mem(ds, "ERROR ",6);
- replace_dynstr_append(ds, err_sqlstate);
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append(ds, err_error);
- dynstr_append_mem(ds, "\n", 1);
- }
-
- if (i)
- {
- if (q->expected_errno[0].type == ERR_ERRNO)
- die("query '%s' failed with wrong errno %d instead of %d...",
- q->query, err_errno, q->expected_errno[0].code.errnum);
- else
- die("query '%s' failed with wrong sqlstate %s instead of %s...",
- q->query, err_sqlstate, q->expected_errno[0].code.sqlstate);
- DBUG_RETURN(1);
- }
-
- /*
- If we do not abort on error, failure to run the query does not fail the
- whole test case.
- */
- verbose_msg("query '%s' failed: %d: %s", q->query, err_errno,
- err_error);
- DBUG_RETURN(0);
-}
-
-
-/*
- Handle absence of errors after execution
-
- SYNOPSIS
- handle_no_error()
- q - context of query
-
- RETURN VALUE
- 0 - OK
- 1 - Some error was expected from this query.
-*/
-
-static int handle_no_error(struct st_query *q)
-{
- DBUG_ENTER("handle_no_error");
-
- if (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0)
- {
- /* Error code we wanted was != 0, i.e. not an expected success */
- die("query '%s' succeeded - should have failed with errno %d...",
- q->query, q->expected_errno[0].code.errnum);
- DBUG_RETURN(1);
- }
- else if (q->expected_errno[0].type == ERR_SQLSTATE &&
- strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
- {
- /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
- die("query '%s' succeeded - should have failed with sqlstate %s...",
- q->query, q->expected_errno[0].code.sqlstate);
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN(0);
-}
-
-/****************************************************************************\
- * If --ps-protocol run ordinary statements using prepared statemnt C API
-\****************************************************************************/
-
-/*
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP
-*/
-
-static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
-{
- int error= 0; /* Function return code if "goto end;" */
- int err; /* Temporary storage of return code from calls */
- int query_len;
+ MYSQL_BIND *bind;
+ my_bool *is_null;
+ ulong *length;
ulonglong num_rows;
- char *query;
- MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
- DYNAMIC_STRING eval_query;
- MYSQL_STMT *stmt;
- DBUG_ENTER("run_query_stmt");
+ uint col_idx, row_idx;
- /*
- We must allocate a new stmt for each query in this program becasue this
- may be a new connection.
- */
- if (!(stmt= mysql_stmt_init(mysql)))
- die("unable init stmt structure");
+ /* 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));
- if (q->type != Q_EVAL)
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
{
- query= q->query;
- query_len= strlen(query);
- }
- else
- {
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query= eval_query.str;
- query_len= eval_query.length;
- }
- DBUG_PRINT("query", ("'%-.60s'", query));
+ /* 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));
- if (q->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds= &ds_tmp;
- }
- else
- ds= &ds_res;
+ 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];
- /* Store the query into the output buffer if not disabled */
- if (!disable_query_log)
- {
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %d",
+ col_idx,
+ bind[col_idx].buffer_type,
+ bind[col_idx].buffer_length));
}
- /*
- We use the prepared statement interface but there is actually no
- '?' in the query. If unpreparable we fall back to use normal
- C API.
- */
- if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT)
- return run_query_normal(mysql, q, flags);
-
- if (err != 0)
- {
- /*
- 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;
- goto end;
- }
-
- /* We may have got warnings already, collect them if any */
- if (!disable_ps_warnings)
- run_query_stmt_handle_warnings(mysql, ds);
-
- /*
- No need to call mysql_stmt_bind_param() because we have no
- parameter markers.
-
- To optimize performance we use a global 'stmt' that is initiated
- once. A new prepare will implicitely close the old one. When we
- terminate we will lose the connection, this also closes the last
- prepared statement.
- */
-
- if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */
- {
- /* We got an error, maybe expected */
- if (handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error= 1;
- goto end;
- }
-
- /*
- We instruct that we want to update the "max_length" field in
- mysql_stmt_store_result(), this is our only way to know how much
- buffer to allocate for result data
- */
- {
- my_bool one= 1;
- if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
- (void*) &one)) != 0)
- die("unable to set stmt attribute "
- "'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err);
- }
-
- /*
- If we got here the statement succeeded and was expected to do so,
- get data. Note that this can still give errors found during execution!
- */
- if ((err= mysql_stmt_store_result(stmt)) != 0)
- {
- /* We got an error, maybe expected */
- if(handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error = 1;
- goto end;
- }
-
- /* If we got here the statement was both executed and read succeesfully */
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
+ /* Fill in the data into the structures created above */
+ if (mysql_stmt_bind_result(stmt, bind))
+ die("mysql_stmt_bind_result failed: %d: %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ /* Read result from each row */
num_rows= mysql_stmt_num_rows(stmt);
-
- /*
- Not all statements creates a result set. If there is one we can
- now create another normal result set that contains the meta
- data. This set can be handled almost like any other non prepared
- statement result set.
- */
- if (!disable_result_log && ((res= mysql_stmt_result_metadata(stmt)) != NULL))
+ for (row_idx= 0; row_idx < num_rows; row_idx++)
{
- /* Take the column count from meta info */
- MYSQL_FIELD *field= mysql_fetch_fields(res);
- uint num_fields= mysql_num_fields(res);
-
- if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ if (mysql_stmt_fetch(stmt))
+ die("mysql_stmt_fetch failed: %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ /* Read result from each column */
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
+ {
+ 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)
- {
- /* Display the table heading with the names tab separated */
- uint col_idx;
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- if (col_idx)
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append(ds, field[col_idx].name);
- }
dynstr_append_mem(ds, "\n", 1);
- }
-
- /* Now we are to put the real result into the output buffer */
- /* FIXME when it works, create function append_stmt_result() */
- {
- MYSQL_BIND *bind;
- my_bool *is_null;
- unsigned long *length;
- /* FIXME we don't handle vertical display ..... */
- uint col_idx, row_idx;
-
- /* Allocate array with bind structs, lengths and NULL flags */
- bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
- MYF(MY_WME | MY_FAE | MY_ZEROFILL));
- length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
- MYF(MY_WME | MY_FAE));
- is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
- MYF(MY_WME | MY_FAE));
-
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- /* Allocate data for output */
- /*
- FIXME it may be a bug that for non string/blob types
- 'max_length' is 0, should try out 'length' in that case
- */
- uint max_length= max(field[col_idx].max_length + 1, 1024);
- char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE));
-
- bind[col_idx].buffer_type= MYSQL_TYPE_STRING;
- bind[col_idx].buffer= (char *)str_data;
- bind[col_idx].buffer_length= max_length;
- bind[col_idx].is_null= &is_null[col_idx];
- bind[col_idx].length= &length[col_idx];
- }
-
- /* Fill in the data into the structures created above */
- if ((err= mysql_stmt_bind_result(stmt, bind)) != 0)
- die("unable to bind result to statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- /* Read result from each row */
- for (row_idx= 0; row_idx < num_rows; row_idx++)
- {
- if ((err= mysql_stmt_fetch(stmt)) != 0)
- die("unable to fetch all rows from statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- /* Read result from each column */
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- 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);
- }
-
- if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA)
- die("fetch didn't end with MYSQL_NO_DATA from statement "
- "'%s': %s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- free_replace_column();
-
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- /* Free data for output */
- my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE));
- }
- /* Free array with bind structs, lengths and NULL flags */
- my_free((gptr)bind , MYF(MY_WME | MY_FAE));
- my_free((gptr)length , MYF(MY_WME | MY_FAE));
- my_free((gptr)is_null , MYF(MY_WME | MY_FAE));
- }
-
- /* Add all warnings to the result */
- run_query_stmt_handle_warnings(mysql, ds);
-
- if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql));
- dynstr_append(ds, buf);
- if (mysql_info(mysql))
- {
- dynstr_append(ds, "info: ");
- dynstr_append(ds, mysql_info(mysql));
- dynstr_append_mem(ds, "\n", 1);
- }
- }
}
- run_query_stmt_handle_warnings(mysql, ds);
- if (record)
+ if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+ die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
+ mysql_stmt_error(stmt), mysql_stmt_errno(stmt));
+
+ free_replace_column();
+
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
{
- if (!q->record_file[0] && !result_file)
- die("Missing result file");
- if (!result_file)
- str_to_file(q->record_file, ds->str, ds->length);
+ /* Free data for output */
+ my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE));
}
- else if (q->record_file[0])
- {
- error= check_result(ds, q->record_file, q->require_file);
- }
- if (res)
- mysql_free_result(res); /* Free normal result set with meta data */
- last_result= 0; /* FIXME have no idea what this is about... */
-
-end:
- free_replace();
- last_result=0;
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- if (q->type == Q_EVAL)
- dynstr_free(&eval_query);
- var_set_errno(mysql_stmt_errno(stmt));
- mysql_stmt_close(stmt);
- DBUG_RETURN(error);
+ /* Free array with bind structs, lengths and NULL flags */
+ my_free((gptr)bind , MYF(MY_WME | MY_FAE));
+ my_free((gptr)length , MYF(MY_WME | MY_FAE));
+ my_free((gptr)is_null , MYF(MY_WME | MY_FAE));
}
-/****************************************************************************\
- * Broken out sub functions to run_query_stmt()
-\****************************************************************************/
+/*
+ Append metadata for fields to output
+*/
-static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds)
+static void append_metadata(DYNAMIC_STRING *ds,
+ MYSQL_FIELD *field,
+ uint num_fields)
{
MYSQL_FIELD *field_end;
dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
@@ -3782,44 +3248,822 @@ static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
}
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
+/*
+ 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)
+ {
+ dynstr_append(ds, "info: ");
+ dynstr_append(ds, info);
+ dynstr_append_mem(ds, "\n", 1);
+ }
+}
+
+
+/*
+ Display the table headings with the names tab separated
+*/
+
+static void append_table_headings(DYNAMIC_STRING *ds,
+ MYSQL_FIELD *field,
+ uint num_fields)
+{
+ uint col_idx;
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
+ {
+ if (col_idx)
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append(ds, field[col_idx].name);
+ }
+ dynstr_append_mem(ds, "\n", 1);
+}
+
+/*
+ Fetch warnings from server and append to ds
+
+ RETURN VALUE
+ Number of warnings appended to ds
+*/
+
+static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
{
uint count;
- DBUG_ENTER("run_query_stmt_handle_warnings");
+ MYSQL_RES *warn_res;
+ DBUG_ENTER("append_warnings");
- if (!disable_warnings && (count= mysql_warning_count(mysql)))
+ 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)
{
/*
- If one day we will support execution of multi-statements
- through PS API we should not issue SHOW WARNINGS until
- we have not read all results...
- */
- DBUG_ASSERT(!mysql_more_results(mysql));
-
- if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
+ Send the query
+ */
+ if (mysql_send_query(mysql, query, query_len))
{
- MYSQL_RES *warn_res= mysql_store_result(mysql);
- if (!warn_res)
- die("Warning count is %u but didn't get any warnings",
- count);
- else
- {
- dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
}
}
+
+ if (!(flags & QUERY_REAP))
+ DBUG_VOID_RETURN;
+
+ do
+ {
+ /*
+ When on first result set, call mysql_read_query_result to retrieve
+ answer to the query sent earlier
+ */
+ if ((counter==0) && mysql_read_query_result(mysql))
+ {
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+
+ }
+
+ /*
+ Store the result. If res is NULL, use mysql_field_count to
+ determine if that was expected
+ */
+ if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql))
+ {
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+ }
+
+ if (!disable_result_log)
+ {
+ ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */
+ LINT_INIT(affected_rows);
+
+ if (res)
+ {
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
+
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
+
+ append_result(ds, res);
+ }
+
+ /*
+ Need to call mysql_affected_rows() before the "new"
+ query to find the warnings
+ */
+ if (!disable_info)
+ affected_rows= 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))
+ {
+ if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
+ {
+ dynstr_append_mem(ds, "Warnings:\n", 10);
+ dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
+ }
+ }
+
+ if (!disable_info)
+ append_info(ds, affected_rows, mysql_info(mysql));
+ }
+
+ if (res)
+ mysql_free_result(res);
+ counter++;
+ } while (!(err= mysql_next_result(mysql)));
+ if (err > 0)
+ {
+ /* We got an error from mysql_next_result, maybe expected */
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+ }
+ DBUG_ASSERT(err == -1); /* Successful and there are no more results */
+
+ /* If we come here the query is both executed and read successfully */
+ handle_no_error(command);
+
+end:
+ free_replace();
+
+ /*
+ We save the return code (mysql_errno(mysql)) from the last call sent
+ to the server into the mysqltest builtin variable $mysql_errno. This
+ variable then can be used from the test case itself.
+ */
+ var_set_errno(mysql_errno(mysql));
DBUG_VOID_RETURN;
}
+/*
+ Handle errors which occurred during execution
+
+ SYNOPSIS
+ handle_error()
+ query - query string
+ q - query context
+ err_errno - error number
+ err_error - error message
+ err_sqlstate - sql state
+ ds - dynamic string which is used for output buffer
+
+ NOTE
+ If there is an unexpected error this function will abort mysqltest
+ immediately.
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+static void handle_error(const char *query, struct st_query *q,
+ unsigned int err_errno, const char *err_error,
+ const char *err_sqlstate, DYNAMIC_STRING *ds)
+{
+ uint i;
+
+ DBUG_ENTER("handle_error");
+
+ if (q->require_file)
+ abort_not_supported_test();
+
+ if (q->abort_on_error)
+ die("query '%s' failed: %d: %s", query, err_errno, err_error);
+
+ for (i= 0 ; (uint) i < q->expected_errors ; i++)
+ {
+ if (((q->expected_errno[i].type == ERR_ERRNO) &&
+ (q->expected_errno[i].code.errnum == err_errno)) ||
+ ((q->expected_errno[i].type == ERR_SQLSTATE) &&
+ (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0)))
+ {
+ if (!disable_result_log)
+ {
+ if (q->expected_errors == 1)
+ {
+ /* Only log error if there is one possible error */
+ dynstr_append_mem(ds, "ERROR ", 6);
+ replace_dynstr_append(ds, err_sqlstate);
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, err_error);
+ dynstr_append_mem(ds,"\n",1);
+ }
+ /* Don't log error if we may not get an error */
+ else if (q->expected_errno[0].type == ERR_SQLSTATE ||
+ (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0))
+ dynstr_append(ds,"Got one of the listed errors\n");
+ }
+ /* OK */
+ DBUG_VOID_RETURN;
+ }
+ }
+
+ DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors));
+
+ if (!disable_result_log)
+ {
+ dynstr_append_mem(ds, "ERROR ",6);
+ replace_dynstr_append(ds, err_sqlstate);
+ dynstr_append_mem(ds, ": ", 2);
+ replace_dynstr_append(ds, err_error);
+ dynstr_append_mem(ds, "\n", 1);
+ }
+
+ if (i)
+ {
+ if (q->expected_errno[0].type == ERR_ERRNO)
+ die("query '%s' failed with wrong errno %d: '%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: '%s', instead of %s...",
+ q->query, err_sqlstate, err_error,
+ q->expected_errno[0].code.sqlstate);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Handle absence of errors after execution
+
+ SYNOPSIS
+ handle_no_error()
+ q - context of query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+static void handle_no_error(struct st_query *q)
+{
+ DBUG_ENTER("handle_no_error");
+
+ if (q->expected_errno[0].type == ERR_ERRNO &&
+ q->expected_errno[0].code.errnum != 0)
+ {
+ /* Error code we wanted was != 0, i.e. not an expected success */
+ die("query '%s' succeeded - should have failed with errno %d...",
+ q->query, q->expected_errno[0].code.errnum);
+ }
+ else if (q->expected_errno[0].type == ERR_SQLSTATE &&
+ strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+ {
+ /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
+ die("query '%s' succeeded - should have failed with sqlstate %s...",
+ q->query, q->expected_errno[0].code.sqlstate);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Run query using prepared statement C API
+
+ SYNPOSIS
+ run_query_stmt
+ mysql - mysql handle
+ command - currrent command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer wherte to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+static void run_query_stmt(MYSQL *mysql, struct st_query *command,
+ char *query, int query_len, DYNAMIC_STRING *ds,
+ DYNAMIC_STRING *ds_warnings)
+{
+ MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
+ MYSQL_STMT *stmt;
+ DYNAMIC_STRING ds_prepare_warnings;
+ DYNAMIC_STRING ds_execute_warnings;
+ DBUG_ENTER("run_query_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
+
+ /*
+ Init a new stmt if it's not alreday one created for this connectoon
+ */
+ if(!(stmt= cur_con->stmt))
+ {
+ if (!(stmt= mysql_stmt_init(mysql)))
+ die("unable to init stmt structure");
+ cur_con->stmt= stmt;
+ }
+
+ /* Init dynamic strings for warnings */
+ if (!disable_warnings)
+ {
+ init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
+ init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
+ }
+
+ /*
+ Prepare the query
+ */
+ if (mysql_stmt_prepare(stmt, query, query_len))
+ {
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /*
+ 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.
+ */
+
+#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
+
+ /*
+ Execute the query
+ */
+ if (mysql_stmt_execute(stmt))
+ {
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /*
+ We instruct that we want to update the "max_length" field in
+ mysql_stmt_store_result(), this is our only way to know how much
+ buffer to allocate for result data
+ */
+ {
+ my_bool one= 1;
+ if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
+ die("mysql_stmt_attr_set(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 (mysql_stmt_store_result(stmt))
+ {
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ goto end;
+ }
+
+ /* If we got here the statement was both executed and read succeesfully */
+ handle_no_error(command);
+ if (!disable_result_log)
+ {
+ /*
+ Not all statements creates a result set. If there is one we can
+ now create another normal result set that contains the meta
+ data. This set can be handled almost like any other non prepared
+ statement result set.
+ */
+ if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
+ {
+ /* Take the column count from meta info */
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
+
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
+
+ append_stmt_result(ds, stmt, fields, num_fields);
+
+ mysql_free_result(res); /* Free normal result set with meta data */
+
+ /* Clear prepare warnings */
+ dynstr_set(&ds_prepare_warnings, NULL);
+ }
+ else
+ {
+ /*
+ This is a query without resultset
+ */
+ }
+
+ if (!disable_warnings)
+ {
+ /* Get the warnings from execute */
+
+ /* Append warnings to ds - if there are any */
+ if (append_warnings(&ds_execute_warnings, mysql) ||
+ ds_prepare_warnings.length ||
+ ds_warnings->length)
+ {
+ dynstr_append_mem(ds, "Warnings:\n", 10);
+ if (ds_warnings->length)
+ dynstr_append_mem(ds, ds_warnings->str,
+ ds_warnings->length);
+ if (ds_prepare_warnings.length)
+ dynstr_append_mem(ds, ds_prepare_warnings.str,
+ ds_prepare_warnings.length);
+ if (ds_execute_warnings.length)
+ dynstr_append_mem(ds, ds_execute_warnings.str,
+ ds_execute_warnings.length);
+ }
+ }
+
+ if (!disable_info)
+ append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
+
+ }
+
+end:
+ free_replace();
+
+ if (!disable_warnings)
+ {
+ dynstr_free(&ds_prepare_warnings);
+ dynstr_free(&ds_execute_warnings);
+ }
+
+ /*
+ We save the return code (mysql_stmt_errno(stmt)) from the last call sent
+ 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);
+ cur_con->stmt= NULL;
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+
+/*
+ Create a util connection if one does not already exists
+ and use that to run the query
+ This is done to avoid implict commit when creating/dropping objects such
+ as view, sp etc.
+*/
+
+static int util_query(MYSQL* org_mysql, const char* query){
+
+ MYSQL* mysql;
+ DBUG_ENTER("util_query");
+
+ if(!(mysql= cur_con->util_mysql))
+ {
+ DBUG_PRINT("info", ("Creating util_mysql"));
+ if (!(mysql= mysql_init(mysql)))
+ die("Failed in mysql_init()");
+
+ if (safe_connect(mysql, org_mysql->host, org_mysql->user,
+ org_mysql->passwd, org_mysql->db, org_mysql->port,
+ org_mysql->unix_socket))
+ die("Could not open util connection: %d %s",
+ mysql_errno(mysql), mysql_error(mysql));
+
+ cur_con->util_mysql= mysql;
+ }
+
+ return mysql_query(mysql, query);
+}
+
+
+
+/*
+ Run query
+
+ flags control the phased/stages of query execution to be performed
+ if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on
+ the result will be read - for regular query, both bits must be on
+
+ SYNPOSIS
+ run_query
+ mysql - mysql handle
+ command - currrent command pointer
+
+*/
+
+static void run_query(MYSQL *mysql, struct st_query *command, int flags)
+{
+ DYNAMIC_STRING *ds;
+ DYNAMIC_STRING ds_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)));
+
+ /* 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))
+ {
+ /*
+ Create the query as a stored procedure
+ Drop first since sp can exist from a failed mysqltest run
+ */
+ DYNAMIC_STRING query_str;
+ init_dynamic_string(&query_str,
+ "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;",
+ 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));
+
+ }
+ else
+ {
+ sp_created= 1;
+
+ query= (char*)"CALL mysqltest_tmp_sp()";
+ query_len = strlen(query);
+ }
+ dynstr_free(&query_str);
+ }
+
+ /*
+ Find out how to run this query
+
+ 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:]]|"
@@ -3834,50 +4078,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();
}
/****************************************************************************/
@@ -3912,6 +4155,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] == ';')
{
/*
@@ -3951,7 +4195,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;
@@ -3960,12 +4204,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;
@@ -3999,7 +4241,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,
@@ -4007,8 +4249,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;
}
@@ -4016,7 +4257,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;
@@ -4029,25 +4269,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);
@@ -4060,17 +4305,21 @@ int main(int argc, char **argv)
{
cur_file->file= stdin;
cur_file->file_name= my_strdup("", MYF(MY_WME));
+ cur_file->lineno= 1;
}
- *lineno=1;
#ifndef EMBEDDED_LIBRARY
if (manager_host)
init_manager();
#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)
@@ -4088,7 +4337,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);
@@ -4110,7 +4360,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:
@@ -4144,7 +4394,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);
@@ -4171,15 +4421,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;
@@ -4190,7 +4431,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;
@@ -4217,7 +4458,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;
@@ -4238,7 +4479,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;
@@ -4360,6 +4601,42 @@ int main(int argc, char **argv)
parser.current_line += current_line_inc;
}
+ start_lineno= 0;
+
+ /*
+ The whole test has been executed _sucessfully_
+ Time to compare result or save it to record file
+ The entire output from test is now kept in ds_res
+ */
+ if (ds_res.length)
+ {
+ if (result_file)
+ {
+ if (record)
+ {
+ /* Dump the output from test to result file */
+ str_to_file(result_file, ds_res.str, ds_res.length);
+ }
+ else
+ {
+ /* Check that the output from test is equal to result file
+ - detect missing result file
+ - detect zero size result file
+ */
+ check_result(&ds_res, result_file, 0);
+ }
+ }
+ else
+ {
+ /* No result_file specified to compare with, print to stdout */
+ printf("%s", ds_res.str);
+ }
+ }
+ else
+ {
+ die("The test didn't produce any output");
+ }
+
if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
{
/*
@@ -4369,40 +4646,22 @@ int main(int argc, char **argv)
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);
+ die("No queries executed but result file found!");
}
- if (ds_res.length && !error)
- {
- if (result_file)
- {
- if (!record)
- error |= check_result(&ds_res, result_file, q->require_file);
- else
- str_to_file(result_file, ds_res.str, ds_res.length);
- }
- else
- {
- /* Print the result to stdout */
- printf("%s", ds_res.str);
- }
- }
- dynstr_free(&ds_res);
- if (!silent)
- {
- if (error)
- printf("not ok\n");
- else
- printf("ok\n");
- }
+
+ 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 */
}
@@ -5199,12 +5458,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
*****************************************************************************/
@@ -5346,7 +5599,7 @@ static char *subst_env_var(const char *str)
*/
#undef popen /* Remove wrapper */
-#ifdef __WIN__
+#ifdef __WIN__
#define popen _popen /* redefine for windows */
#endif
@@ -5362,3 +5615,5 @@ FILE *my_popen(const char *cmd, const char *mode __attribute__((unused)))
}
#endif /* __NETWARE__ or __WIN__*/
+
+
diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c
index 1da6a864181..c0fa7cc717d 100644
--- a/cmd-line-utils/libedit/history.c
+++ b/cmd-line-utils/libedit/history.c
@@ -676,8 +676,8 @@ history_load(History *h, const char *fname)
(void) strunvis(ptr, line);
line[sz] = c;
if (HENTER(h, &ev, ptr) == -1) {
- h_free((ptr_t)ptr);
- return -1;
+ i = -1;
+ goto oomem;
}
}
oomem:
diff --git a/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/configure.in b/configure.in
index b3d4a587bea..b5c31361b26 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 5.0.18)
+AM_INIT_AUTOMAKE(mysql, 5.0.19)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -18,7 +18,7 @@ SHARED_LIB_VERSION=15:0:0
# ndb version
NDB_VERSION_MAJOR=5
NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=18
+NDB_VERSION_BUILD=19
NDB_VERSION_STATUS=""
# Set all version vars based on $VERSION. How do we do this more elegant ?
diff --git a/extra/comp_err.c b/extra/comp_err.c
index d0e387dcd35..65fc131a5fc 100644
--- a/extra/comp_err.c
+++ b/extra/comp_err.c
@@ -876,9 +876,10 @@ static void usage(void)
{
DBUG_ENTER("usage");
print_version();
- printf("This software comes with ABSOLUTELY NO WARRANTY. This is free "
- "software,\nand you are welcome to modify and redistribute it under "
- "the GPL license\nUsage:\n");
+ printf("This software comes with ABSOLUTELY NO WARRANTY. "
+ "This is free software,\n"
+ "and you are welcome to modify and redistribute it under the GPL license.\n"
+ "Usage:\n");
my_print_help(my_long_options);
my_print_variables(my_long_options);
DBUG_VOID_RETURN;
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 45dfb6fa032..d7df438b8df 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -656,7 +656,11 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr buffered)
{
ssl.getSocket().wait(); // wait for input if blocking
uint ready = ssl.getSocket().get_ready();
- if (!ready) return buffered;
+ if (!ready) {
+ // Nothing to receive after blocking wait => error
+ ssl.SetError(receive_error);
+ return buffered= null_buffer;
+ }
// add buffered data if its there
uint buffSz = buffered.get() ? buffered.get()->get_size() : 0;
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 7def0053bf2..5a8b926a669 100644
--- a/include/config-netware.h
+++ b/include/config-netware.h
@@ -72,9 +72,10 @@ extern "C" {
#undef HAVE_CRYPT
#endif /* HAVE_OPENSSL */
-/* Configure can't detect this because it uses AC_TRY_RUN */
+/* Netware has an ancient zlib */
#undef HAVE_COMPRESS
#define HAVE_COMPRESS
+#undef HAVE_ARCHIVE_DB
/* include the old function apis */
#define USE_OLD_FUNCTIONS 1
@@ -94,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 528bc8a8cdd..b2bd63efc30 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -22,6 +22,11 @@ functions */
#define _WIN32_WINNT 0x0500
#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+/* Avoid endless warnings about sprintf() etc. being unsafe. */
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
#include
#include
#include /* Because of rint() */
@@ -61,6 +66,10 @@ functions */
#define __WIN__ /* To make it easier in VC++ */
#endif
+#ifndef MAX_INDEXES
+#define MAX_INDEXES 64
+#endif
+
/* File and lock constants */
#define O_SHARE 0x1000 /* Open file in sharing mode */
#ifdef __BORLANDC__
@@ -99,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 */
@@ -324,6 +339,7 @@ inline double ulonglong2double(ulonglong value)
#define SPRINTF_RETURNS_INT
#define HAVE_SETFILEPOINTER
#define HAVE_VIO_READ_BUFF
+#define HAVE_STRNLEN
#ifndef __NT__
#undef FILE_SHARE_DELETE
diff --git a/include/hash.h b/include/hash.h
index 9a6d91036e1..8f5ff21ae5e 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -33,7 +33,7 @@ typedef void (*hash_free_key)(void *);
typedef struct st_hash {
uint key_offset,key_length; /* Length of key if const length */
- uint records,blength,current_record;
+ uint records, blength;
uint flags;
DYNAMIC_ARRAY array; /* Place for hash_keys */
hash_get_key get_key;
@@ -41,6 +41,9 @@ typedef struct st_hash {
CHARSET_INFO *charset;
} HASH;
+/* A search iterator state */
+typedef uint HASH_SEARCH_STATE;
+
#define hash_init(A,B,C,D,E,F,G,H) _hash_init(A,B,C,D,E,F,G, H CALLER_INFO)
my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
uint default_array_elements, uint key_offset,
@@ -49,12 +52,15 @@ my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
void hash_free(HASH *tree);
void my_hash_reset(HASH *hash);
byte *hash_element(HASH *hash,uint idx);
-gptr hash_search(HASH *info,const byte *key,uint length);
-gptr hash_next(HASH *info,const byte *key,uint length);
+gptr hash_search(const HASH *info, const byte *key, uint length);
+gptr hash_first(const HASH *info, const byte *key, uint length,
+ HASH_SEARCH_STATE *state);
+gptr hash_next(const HASH *info, const byte *key, uint length,
+ HASH_SEARCH_STATE *state);
my_bool my_hash_insert(HASH *info,const byte *data);
my_bool hash_delete(HASH *hash,byte *record);
my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
-void hash_replace(HASH *hash, uint idx, byte *new_row);
+void hash_replace(HASH *hash, HASH_SEARCH_STATE *state, byte *new_row);
my_bool hash_check(HASH *hash); /* Only in debug library */
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
diff --git a/include/my_base.h b/include/my_base.h
index 8eab79a96fd..77cd60fda92 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -404,7 +404,8 @@ enum ha_base_keytype {
enum en_fieldtype {
FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE,
FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO,
- FIELD_VARCHAR,FIELD_CHECK
+ FIELD_VARCHAR,FIELD_CHECK,
+ FIELD_enum_val_count
};
enum data_file_type {
diff --git a/include/my_global.h b/include/my_global.h
index e62f6c269aa..0df9ac78eb2 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -862,6 +862,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN WSAEINPROGRESS
#define SOCKET_ETIMEDOUT WSAETIMEDOUT
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
+#define SOCKET_EADDRINUSE WSAEADDRINUSE
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#elif defined(OS2)
@@ -870,6 +871,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN SOCEINPROGRESS
#define SOCKET_ETIMEDOUT SOCKET_EINTR
#define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK
+#define SOCKET_EADDRINUSE SOCEADDRINUSE
#define SOCKET_ENFILE SOCENFILE
#define SOCKET_EMFILE SOCEMFILE
#define closesocket(A) soclose(A)
@@ -880,6 +882,7 @@ typedef off_t os_off_t;
#define SOCKET_EAGAIN EAGAIN
#define SOCKET_ETIMEDOUT SOCKET_EINTR
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
+#define SOCKET_EADDRINUSE EADDRINUSE
#define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE
#endif
diff --git a/include/my_user.h b/include/my_user.h
new file mode 100644
index 00000000000..2bd4208a34c
--- /dev/null
+++ b/include/my_user.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ This is a header for libraries containing functions used in both server and
+ only some of clients (but not in libmysql)...
+*/
+
+#ifndef _my_user_h_
+#define _my_user_h_
+
+#include
+
+C_MODE_START
+
+void parse_user(const char *user_id_str, uint user_id_len,
+ char *user_name_str, uint *user_name_len,
+ char *host_name_str, uint *host_name_len);
+
+C_MODE_END
+
+#endif /* _my_user_h_ */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 1e595cdbba3..ec1c133799f 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -27,6 +27,14 @@
#define SERVER_VERSION_LENGTH 60
#define SQLSTATE_LENGTH 5
+/*
+ USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain
+ username and hostname parts of the user identifier with trailing zero in
+ MySQL standard format:
+ user_name_part@host_name_part\0
+*/
+#define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2
+
#define LOCAL_HOST "localhost"
#define LOCAL_HOST_NAMEDPIPE "."
diff --git a/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/include/data0type.h b/innobase/include/data0type.h
index 7e9692eca5a..30c0f732c34 100644
--- a/innobase/include/data0type.h
+++ b/innobase/include/data0type.h
@@ -13,6 +13,7 @@ Created 1/16/1996 Heikki Tuuri
extern ulint data_mysql_default_charset_coll;
#define DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL 8
+#define DATA_MYSQL_BINARY_CHARSET_COLL 63
/* SQL data type struct */
typedef struct dtype_struct dtype_t;
@@ -311,7 +312,7 @@ dtype_get_pad_char(
/*===============*/
/* out: padding character code, or
ULINT_UNDEFINED if no padding specified */
- dtype_t* type); /* in: type */
+ const dtype_t* type); /* in: type */
/***************************************************************************
Returns the size of a fixed size data type, 0 if not a fixed size type. */
UNIV_INLINE
diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic
index d4a7b3c64b8..ad0f02fa63d 100644
--- a/innobase/include/data0type.ic
+++ b/innobase/include/data0type.ic
@@ -188,26 +188,35 @@ dtype_get_pad_char(
/*===============*/
/* out: padding character code, or
ULINT_UNDEFINED if no padding specified */
- dtype_t* type) /* in: type */
+ const dtype_t* type) /* in: type */
{
- if (type->mtype == DATA_CHAR
- || type->mtype == DATA_VARCHAR
- || type->mtype == DATA_BINARY
- || type->mtype == DATA_FIXBINARY
- || type->mtype == DATA_MYSQL
- || type->mtype == DATA_VARMYSQL
- || (type->mtype == DATA_BLOB
- && (type->prtype & DATA_BINARY_TYPE) == 0)) {
-
+ switch (type->mtype) {
+ case DATA_FIXBINARY:
+ case DATA_BINARY:
+ if (UNIV_UNLIKELY(dtype_get_charset_coll(type->prtype)
+ == DATA_MYSQL_BINARY_CHARSET_COLL)) {
+ /* Starting from 5.0.18, do not pad
+ VARBINARY or BINARY columns. */
+ return(ULINT_UNDEFINED);
+ }
+ /* Fall through */
+ case DATA_CHAR:
+ case DATA_VARCHAR:
+ case DATA_MYSQL:
+ case DATA_VARMYSQL:
/* Space is the padding character for all char and binary
strings, and starting from 5.0.3, also for TEXT strings. */
- return((ulint)' ');
+ return(0x20);
+ case DATA_BLOB:
+ if ((type->prtype & DATA_BINARY_TYPE) == 0) {
+ return(0x20);
+ }
+ /* Fall through */
+ default:
+ /* No padding specified */
+ return(ULINT_UNDEFINED);
}
-
- /* No padding specified */
-
- return(ULINT_UNDEFINED);
}
/**************************************************************************
diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h
index 20b1f1d7145..86e579bc007 100644
--- a/innobase/include/lock0lock.h
+++ b/innobase/include/lock0lock.h
@@ -64,14 +64,6 @@ lock_clust_rec_some_has_impl(
dict_index_t* index, /* in: clustered index */
const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*****************************************************************
-Resets the lock bits for a single record. Releases transactions
-waiting for lock requests here. */
-
-void
-lock_rec_reset_and_release_wait(
-/*============================*/
- rec_t* rec); /* in: record whose locks bits should be reset */
-/*****************************************************************
Makes a record to inherit the locks of another record as gap type
locks, but does not reset the lock bits of the other record. Also
waiting lock requests on rec are inherited as GRANTED gap locks. */
@@ -427,6 +419,18 @@ lock_is_on_table(
/*=============*/
/* out: TRUE if there are lock(s) */
dict_table_t* table); /* in: database table in dictionary cache */
+/*****************************************************************
+Removes a granted record lock of a transaction from the queue and grants
+locks to other transactions waiting in the queue if they now are entitled
+to a lock. */
+
+void
+lock_rec_unlock(
+/*============*/
+ trx_t* trx, /* in: transaction that has set a record
+ lock */
+ rec_t* rec, /* in: record */
+ ulint lock_mode); /* in: LOCK_S or LOCK_X */
/*************************************************************************
Releases a table lock.
Releases possible other transactions waiting for this lock. */
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index 02a38dd49ef..d5bc5a2b115 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -91,9 +91,10 @@ log. */
#define OS_FILE_NOT_FOUND 71
#define OS_FILE_DISK_FULL 72
#define OS_FILE_ALREADY_EXISTS 73
-#define OS_FILE_AIO_RESOURCES_RESERVED 74 /* wait for OS aio resources
+#define OS_FILE_PATH_ERROR 74
+#define OS_FILE_AIO_RESOURCES_RESERVED 75 /* wait for OS aio resources
to become available again */
-#define OS_FILE_ERROR_NOT_SPECIFIED 75
+#define OS_FILE_ERROR_NOT_SPECIFIED 76
/* Types for aio operations */
#define OS_FILE_READ 10
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index b5da4634d98..7d8740db044 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -250,8 +250,9 @@ trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,
and also under prebuilt->clust_pcur. Currently, this is only used and tested
in the case of an UPDATE or a DELETE statement, where the row lock is of the
-LOCK_X type.
-Thus, this implements a 'mini-rollback' that releases the latest record
+LOCK_X or LOCK_S type.
+
+Thus, this implements a 'mini-rollback' that releases the latest record
locks we set. */
int
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 7844991613f..06475c8ef7e 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -2392,7 +2392,7 @@ lock_rec_free_all_from_discard_page(
/*****************************************************************
Resets the lock bits for a single record. Releases transactions waiting for
lock requests here. */
-
+static
void
lock_rec_reset_and_release_wait(
/*============================*/
@@ -3760,6 +3760,75 @@ lock_table_dequeue(
/*=========================== LOCK RELEASE ==============================*/
+/*****************************************************************
+Removes a granted record lock of a transaction from the queue and grants
+locks to other transactions waiting in the queue if they now are entitled
+to a lock. */
+
+void
+lock_rec_unlock(
+/*============*/
+ trx_t* trx, /* in: transaction that has set a record
+ lock */
+ rec_t* rec, /* in: record */
+ ulint lock_mode) /* in: LOCK_S or LOCK_X */
+{
+ lock_t* lock;
+ lock_t* release_lock = NULL;
+ ulint heap_no;
+
+ ut_ad(trx && rec);
+
+ mutex_enter(&kernel_mutex);
+
+ heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec));
+
+ lock = lock_rec_get_first(rec);
+
+ /* Find the last lock with the same lock_mode and transaction
+ from the record. */
+
+ while (lock != NULL) {
+ if (lock->trx == trx && lock_get_mode(lock) == lock_mode) {
+ release_lock = lock;
+ ut_a(!lock_get_wait(lock));
+ }
+
+ lock = lock_rec_get_next(rec, lock);
+ }
+
+ /* If a record lock is found, release the record lock */
+
+ if (UNIV_LIKELY(release_lock != NULL)) {
+ lock_rec_reset_nth_bit(release_lock, heap_no);
+ } else {
+ mutex_exit(&kernel_mutex);
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: unlock row could not find a %lu mode lock on the record\n",
+ (ulong)lock_mode);
+
+ return;
+ }
+
+ /* Check if we can now grant waiting lock requests */
+
+ lock = lock_rec_get_first(rec);
+
+ while (lock != NULL) {
+ if (lock_get_wait(lock)
+ && !lock_rec_has_to_wait_in_queue(lock)) {
+
+ /* Grant the lock */
+ lock_grant(lock);
+ }
+
+ lock = lock_rec_get_next(rec, lock);
+ }
+
+ mutex_exit(&kernel_mutex);
+}
+
/*************************************************************************
Releases a table lock.
Releases possible other transactions waiting for this lock. */
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index 20a3303d12d..3b8f7576049 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -160,15 +160,12 @@ time_t os_last_printout;
ibool os_has_said_disk_full = FALSE;
-/* The mutex protecting the following counts of pending pread and pwrite
-operations */
+/* The mutex protecting the following counts of pending I/O operations */
static os_mutex_t os_file_count_mutex;
ulint os_file_n_pending_preads = 0;
ulint os_file_n_pending_pwrites = 0;
-
-/* These are not protected by any mutex */
-ulint os_n_pending_writes = 0;
-ulint os_n_pending_reads = 0;
+ulint os_n_pending_writes = 0;
+ulint os_n_pending_reads = 0;
/***************************************************************************
Gets the operating system version. Currently works only on Windows. */
@@ -314,6 +311,8 @@ os_file_get_last_error(
return(OS_FILE_NOT_FOUND);
} else if (err == EEXIST) {
return(OS_FILE_ALREADY_EXISTS);
+ } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) {
+ return(OS_FILE_PATH_ERROR);
} else {
return(100 + err);
}
@@ -363,7 +362,8 @@ os_file_handle_error(
return(TRUE);
- } else if (err == OS_FILE_ALREADY_EXISTS) {
+ } else if (err == OS_FILE_ALREADY_EXISTS
+ || err == OS_FILE_PATH_ERROR) {
return(FALSE);
} else {
@@ -467,7 +467,8 @@ os_file_handle_error_no_exit(
return(TRUE);
- } else if (err == OS_FILE_ALREADY_EXISTS) {
+ } else if (err == OS_FILE_ALREADY_EXISTS
+ || err == OS_FILE_PATH_ERROR) {
return(FALSE);
} else {
@@ -1905,12 +1906,14 @@ os_file_pread(
#if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD)
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_preads++;
+ os_n_pending_reads++;
os_mutex_exit(os_file_count_mutex);
n_bytes = pread(file, buf, (ssize_t)n, offs);
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_preads--;
+ os_n_pending_reads--;
os_mutex_exit(os_file_count_mutex);
return(n_bytes);
@@ -1920,6 +1923,10 @@ os_file_pread(
ssize_t ret;
ulint i;
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads++;
+ os_mutex_exit(os_file_count_mutex);
+
/* Protect the seek / read operation with a mutex */
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
@@ -1928,15 +1935,17 @@ os_file_pread(
ret_offset = lseek(file, offs, SEEK_SET);
if (ret_offset < 0) {
- os_mutex_exit(os_file_seek_mutexes[i]);
-
- return(-1);
+ ret = -1;
+ } else {
+ ret = read(file, buf, (ssize_t)n);
}
-
- ret = read(file, buf, (ssize_t)n);
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads--;
+ os_mutex_exit(os_file_count_mutex);
+
return(ret);
}
#endif
@@ -1981,12 +1990,14 @@ os_file_pwrite(
#if defined(HAVE_PWRITE) && !defined(HAVE_BROKEN_PREAD)
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_pwrites++;
+ os_n_pending_writes++;
os_mutex_exit(os_file_count_mutex);
ret = pwrite(file, buf, (ssize_t)n, offs);
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_pwrites--;
+ os_n_pending_writes--;
os_mutex_exit(os_file_count_mutex);
# ifdef UNIV_DO_FLUSH
@@ -2008,6 +2019,10 @@ os_file_pwrite(
off_t ret_offset;
ulint i;
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_writes++;
+ os_mutex_exit(os_file_count_mutex);
+
/* Protect the seek / write operation with a mutex */
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
@@ -2016,9 +2031,9 @@ os_file_pwrite(
ret_offset = lseek(file, offs, SEEK_SET);
if (ret_offset < 0) {
- os_mutex_exit(os_file_seek_mutexes[i]);
+ ret = -1;
- return(-1);
+ goto func_exit;
}
ret = write(file, buf, (ssize_t)n);
@@ -2036,8 +2051,13 @@ os_file_pwrite(
}
# endif /* UNIV_DO_FLUSH */
+func_exit:
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_writes--;
+ os_mutex_exit(os_file_count_mutex);
+
return(ret);
}
#endif
@@ -2082,9 +2102,13 @@ try_again:
low = (DWORD) offset;
high = (DWORD) offset_high;
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads++;
+ os_mutex_exit(os_file_count_mutex);
+
/* Protect the seek / read operation with a mutex */
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
-
+
os_mutex_enter(os_file_seek_mutexes[i]);
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
@@ -2093,17 +2117,21 @@ try_again:
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads--;
+ os_mutex_exit(os_file_count_mutex);
+
goto error_handling;
}
- os_n_pending_reads++;
-
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
- os_n_pending_reads--;
-
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads--;
+ os_mutex_exit(os_file_count_mutex);
+
if (ret && len == n) {
return(TRUE);
}
@@ -2114,12 +2142,8 @@ try_again:
os_bytes_read_since_printout += n;
try_again:
- os_n_pending_reads++;
-
ret = os_file_pread(file, buf, n, offset, offset_high);
- os_n_pending_reads--;
-
if ((ulint)ret == n) {
return(TRUE);
@@ -2193,6 +2217,10 @@ try_again:
low = (DWORD) offset;
high = (DWORD) offset_high;
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads++;
+ os_mutex_exit(os_file_count_mutex);
+
/* Protect the seek / read operation with a mutex */
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
@@ -2204,17 +2232,21 @@ try_again:
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads--;
+ os_mutex_exit(os_file_count_mutex);
+
goto error_handling;
}
- os_n_pending_reads++;
-
ret = ReadFile(file, buf, (DWORD) n, &len, NULL);
- os_n_pending_reads--;
-
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_reads--;
+ os_mutex_exit(os_file_count_mutex);
+
if (ret && len == n) {
return(TRUE);
}
@@ -2225,12 +2257,8 @@ try_again:
os_bytes_read_since_printout += n;
try_again:
- os_n_pending_reads++;
-
ret = os_file_pread(file, buf, n, offset, offset_high);
- os_n_pending_reads--;
-
if ((ulint)ret == n) {
return(TRUE);
@@ -2310,6 +2338,10 @@ retry:
low = (DWORD) offset;
high = (DWORD) offset_high;
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_writes++;
+ os_mutex_exit(os_file_count_mutex);
+
/* Protect the seek / write operation with a mutex */
i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES;
@@ -2321,6 +2353,10 @@ retry:
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_writes--;
+ os_mutex_exit(os_file_count_mutex);
+
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -2335,12 +2371,8 @@ retry:
return(FALSE);
}
- os_n_pending_writes++;
-
ret = WriteFile(file, buf, (DWORD) n, &len, NULL);
- os_n_pending_writes--;
-
/* Always do fsync to reduce the probability that when the OS crashes,
a database page is only partially physically written to disk. */
@@ -2352,6 +2384,10 @@ retry:
os_mutex_exit(os_file_seek_mutexes[i]);
+ os_mutex_enter(os_file_count_mutex);
+ os_n_pending_writes--;
+ os_mutex_exit(os_file_count_mutex);
+
if (ret && len == n) {
return(TRUE);
@@ -2402,11 +2438,7 @@ retry:
#else
ssize_t ret;
- os_n_pending_writes++;
-
ret = os_file_pwrite(file, buf, n, offset, offset_high);
-
- os_n_pending_writes--;
if ((ulint)ret == n) {
diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c
index 847d0ee1cc7..1d1cb77b336 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -147,6 +147,15 @@ os_thread_create(
"InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret);
exit(1);
}
+#endif
+#ifdef __NETWARE__
+ ret = pthread_attr_setstacksize(&attr,
+ (size_t) NW_THD_STACKSIZE);
+ if (ret) {
+ fprintf(stderr,
+ "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret);
+ exit(1);
+ }
#endif
os_mutex_enter(os_sync_mutex);
os_thread_count++;
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 32aa0385596..be1a48a4b46 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -549,6 +549,15 @@ row_ins_cascade_calc_update_vec(
default:
ut_error;
case 1:
+ if (UNIV_UNLIKELY(
+ dtype_get_charset_coll(
+ dtype_get_prtype(type))
+ == DATA_MYSQL_BINARY_CHARSET_COLL)) {
+ /* Do not pad BINARY
+ columns. */
+ return(ULINT_UNDEFINED);
+ }
+
/* space=0x20 */
memset(pad_start, 0x20,
pad_end - pad_start);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 723e305b2ab..937056c300e 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -1436,8 +1436,9 @@ trx_register_new_rec_lock() to store the information which new record locks
really were set. This function removes a newly set lock under prebuilt->pcur,
and also under prebuilt->clust_pcur. Currently, this is only used and tested
in the case of an UPDATE or a DELETE statement, where the row lock is of the
-LOCK_X type.
-Thus, this implements a 'mini-rollback' that releases the latest record
+LOCK_X or LOCK_S type.
+
+Thus, this implements a 'mini-rollback' that releases the latest record
locks we set. */
int
@@ -1474,7 +1475,14 @@ row_unlock_for_mysql(
index = btr_pcur_get_btr_cur(pcur)->index;
- if (index != NULL && trx_new_rec_locks_contain(trx, index)) {
+ if (UNIV_UNLIKELY(index == NULL)) {
+ fprintf(stderr,
+"InnoDB: Error: Index is not set for persistent cursor.\n");
+ ut_print_buf(stderr, (const byte*)pcur, sizeof(btr_pcur_t));
+ ut_error;
+ }
+
+ if (trx_new_rec_locks_contain(trx, index)) {
mtr_start(&mtr);
@@ -1486,11 +1494,7 @@ row_unlock_for_mysql(
rec = btr_pcur_get_rec(pcur);
- mutex_enter(&kernel_mutex);
-
- lock_rec_reset_and_release_wait(rec);
-
- mutex_exit(&kernel_mutex);
+ lock_rec_unlock(trx, rec, prebuilt->select_lock_type);
mtr_commit(&mtr);
@@ -1520,11 +1524,7 @@ row_unlock_for_mysql(
rec = btr_pcur_get_rec(clust_pcur);
- mutex_enter(&kernel_mutex);
-
- lock_rec_reset_and_release_wait(rec);
-
- mutex_exit(&kernel_mutex);
+ lock_rec_unlock(trx, rec, prebuilt->select_lock_type);
mtr_commit(&mtr);
}
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index 1b66f14f5d7..d25023dc6be 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -2771,8 +2771,8 @@ row_sel_get_clust_rec_for_mysql(
func_exit:
*out_rec = clust_rec;
- if (prebuilt->select_lock_type == LOCK_X) {
- /* We may use the cursor in update: store its position */
+ if (prebuilt->select_lock_type != LOCK_NONE) {
+ /* We may use the cursor in unlock: store its position */
btr_pcur_store_position(prebuilt->clust_pcur, mtr);
}
@@ -3972,12 +3972,12 @@ got_row:
/* We have an optimization to save CPU time: if this is a consistent
read on a unique condition on the clustered index, then we do not
store the pcur position, because any fetch next or prev will anyway
- return 'end of file'. An exception is the MySQL HANDLER command
- where the user can move the cursor with PREV or NEXT even after
- a unique search. */
+ return 'end of file'. Exceptions are locking reads and the MySQL
+ HANDLER command where the user can move the cursor with PREV or NEXT
+ even after a unique search. */
if (!unique_search_from_clust_index
- || prebuilt->select_lock_type == LOCK_X
+ || prebuilt->select_lock_type != LOCK_NONE
|| prebuilt->used_in_HANDLER) {
/* Inside an update always store the cursor position */
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 090057f5d46..2637b28ef90 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -794,7 +794,8 @@ trx_commit_off_kernel(
in trx sys header if MySQL binlogging is on or the database
server is a MySQL replication slave */
- if (trx->mysql_log_file_name) {
+ if (trx->mysql_log_file_name
+ && trx->mysql_log_file_name[0] != '\0') {
trx_sys_update_mysql_binlog_offset(
trx->mysql_log_file_name,
trx->mysql_log_offset,
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 11ee7284cbf..0c74dc9121c 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -818,7 +818,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
if ((*options->local_infile_init)(&li_ptr, net_filename,
options->local_infile_userdata))
{
- my_net_write(net,"",0); /* Server needs one packet */
+ VOID(my_net_write(net,"",0)); /* Server needs one packet */
net_flush(net);
strmov(net->sqlstate, unknown_sqlstate);
net->last_errno= (*options->local_infile_error)(li_ptr,
diff --git a/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/myisam/mi_create.c b/myisam/mi_create.c
index 6d4106afda5..1a17febe94a 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -72,7 +72,6 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
LINT_INIT(dfile);
LINT_INIT(file);
- pthread_mutex_lock(&THR_LOCK_myisam);
errpos=0;
options=0;
bzero((byte*) &share,sizeof(share));
@@ -135,7 +134,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pack_reclength++;
min_pack_length++;
/* We must test for 257 as length includes pack-length */
- if (test(rec->length >= 257))
+ if (test(rec->length >= 257))
{
long_varchar_count++;
pack_reclength+= 2; /* May be packed on 3 bytes */
@@ -542,6 +541,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (! (flags & HA_DONT_TOUCH_DATA))
share.state.create_time= (long) time((time_t*) 0);
+ pthread_mutex_lock(&THR_LOCK_myisam);
+
if (ci->index_file_name)
{
fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4);
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index bf99830b37f..2010b684300 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -170,7 +170,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo,
goto err;
}
if ((error=d_search(info,keyinfo,
- (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND
+ (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND | SEARCH_UPDATE
: SEARCH_SAME),
key,key_length,old_root,root_buff)) >0)
{
@@ -276,7 +276,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (subkeys == -1)
{
/* the last entry in sub-tree */
- _mi_dispose(info, keyinfo, root,DFLT_INIT_HITS);
+ if (_mi_dispose(info, keyinfo, root,DFLT_INIT_HITS))
+ DBUG_RETURN(-1);
/* fall through to normal delete */
}
else
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index d691c24e890..e80a3ffacd9 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -1159,7 +1159,7 @@ static int compare_huff_elements(void *not_used __attribute__((unused)),
static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
my_off_t records)
{
- uint space_fields,fill_zero_fields,field_count[(int) FIELD_VARCHAR+1];
+ uint space_fields,fill_zero_fields,field_count[(int) FIELD_enum_val_count];
my_off_t old_length,new_length,length;
DBUG_ENTER("check_counts");
diff --git a/myisam/sort.c b/myisam/sort.c
index c3eaddb3e92..c9562461f56 100644
--- a/myisam/sort.c
+++ b/myisam/sort.c
@@ -376,7 +376,10 @@ pthread_handler_t thr_find_all_keys(void *arg)
{
if (my_init_dynamic_array(&info->buffpek, sizeof(BUFFPEK),
maxbuffer, maxbuffer/2))
+ {
my_free((gptr) sort_keys,MYF(0));
+ sort_keys= (uchar **) NULL; /* for err: label */
+ }
else
break;
}
diff --git a/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/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index b3a243444c1..4d88c9b3322 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -890,7 +890,14 @@ sub mtr_exit ($) {
# cluck("Called mtr_exit()");
mtr_timer_stop_all($::glob_timers);
local $SIG{HUP} = 'IGNORE';
- kill('HUP', -$$);
+ # ToDo: Signalling -$$ will only work if we are the process group
+ # leader (in fact on QNX it will signal our session group leader,
+ # which might be Do-compile or Pushbuild, causing tests to be
+ # aborted). So we only do it if we are the group leader. We might
+ # set ourselves as the group leader at startup (with
+ # POSIX::setpgrp(0,0)), but then care must be needed to always do
+ # proper child process cleanup.
+ kill('HUP', -$$) if $$ == getpgrp();
sleep 2;
exit($code);
}
diff --git a/mysql-test/lib/mtr_stress.pl b/mysql-test/lib/mtr_stress.pl
index a57d94e8043..d3ed24db545 100644
--- a/mysql-test/lib/mtr_stress.pl
+++ b/mysql-test/lib/mtr_stress.pl
@@ -145,6 +145,14 @@ sub run_stress_test ()
mtr_add_arg($args, "--stress-init-file=%", $::opt_stress_init_file);
}
+ if ( !$::opt_stress_loop_count && !$::opt_stress_test_count &&
+ !$::opt_stress_test_duration )
+ {
+ #Limit stress testing with 20 loops in case when any limit parameter
+ #was specified
+ $::opt_stress_test_count=20;
+ }
+
if ( $::opt_stress_loop_count )
{
mtr_add_arg($args, "--loop-count=%s", $::opt_stress_loop_count);
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 8ccd87fc7a8..bdcacf3a2ee 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;
@@ -276,9 +281,9 @@ our $opt_stress= "";
our $opt_stress_suite= "main";
our $opt_stress_mode= "random";
our $opt_stress_threads= 5;
-our $opt_stress_test_count= 20;
-our $opt_stress_loop_count= "";
-our $opt_stress_test_duration= "";
+our $opt_stress_test_count= 0;
+our $opt_stress_loop_count= 0;
+our $opt_stress_test_duration= 0;
our $opt_stress_init_file= "";
our $opt_stress_test_file= "";
@@ -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;
@@ -804,6 +813,12 @@ sub command_line_setup () {
}
}
+ # On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be
+ # considered different, so avoid the extra slash (/) in the socket
+ # paths.
+ my $sockdir = $opt_tmpdir;
+ $sockdir =~ s|/+$||;
+
# Put this into a hash, will be a C struct
$master->[0]=
@@ -812,7 +827,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/master.err",
path_mylog => "$opt_vardir/log/master.log",
path_mypid => "$opt_vardir/run/master.pid",
- path_mysock => "$opt_tmpdir/master.sock",
+ path_mysock => "$sockdir/master.sock",
path_myport => $opt_master_myport,
start_timeout => 400, # enough time create innodb tables
@@ -825,7 +840,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/master1.err",
path_mylog => "$opt_vardir/log/master1.log",
path_mypid => "$opt_vardir/run/master1.pid",
- path_mysock => "$opt_tmpdir/master1.sock",
+ path_mysock => "$sockdir/master1.sock",
path_myport => $opt_master_myport + 1,
start_timeout => 400, # enough time create innodb tables
};
@@ -836,7 +851,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave.err",
path_mylog => "$opt_vardir/log/slave.log",
path_mypid => "$opt_vardir/run/slave.pid",
- path_mysock => "$opt_tmpdir/slave.sock",
+ path_mysock => "$sockdir/slave.sock",
path_myport => $opt_slave_myport,
start_timeout => 400,
};
@@ -847,7 +862,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave1.err",
path_mylog => "$opt_vardir/log/slave1.log",
path_mypid => "$opt_vardir/run/slave1.pid",
- path_mysock => "$opt_tmpdir/slave1.sock",
+ path_mysock => "$sockdir/slave1.sock",
path_myport => $opt_slave_myport + 1,
start_timeout => 300,
};
@@ -858,7 +873,7 @@ sub command_line_setup () {
path_myerr => "$opt_vardir/log/slave2.err",
path_mylog => "$opt_vardir/log/slave2.log",
path_mypid => "$opt_vardir/run/slave2.pid",
- path_mysock => "$opt_tmpdir/slave2.sock",
+ path_mysock => "$sockdir/slave2.sock",
path_myport => $opt_slave_myport + 2,
start_timeout => 300,
};
@@ -868,7 +883,7 @@ sub command_line_setup () {
path_err => "$opt_vardir/log/im.err",
path_log => "$opt_vardir/log/im.log",
path_pid => "$opt_vardir/run/im.pid",
- path_sock => "$opt_tmpdir/im.sock",
+ path_sock => "$sockdir/im.sock",
port => $im_port,
start_timeout => $master->[0]->{'start_timeout'},
admin_login => 'im_admin',
@@ -883,7 +898,7 @@ sub command_line_setup () {
server_id => 1,
port => $im_mysqld1_port,
path_datadir => "$opt_vardir/im_mysqld_1.data",
- path_sock => "$opt_tmpdir/mysqld_1.sock",
+ path_sock => "$sockdir/mysqld_1.sock",
path_pid => "$opt_vardir/run/mysqld_1.pid",
};
@@ -892,7 +907,7 @@ sub command_line_setup () {
server_id => 2,
port => $im_mysqld2_port,
path_datadir => "$opt_vardir/im_mysqld_2.data",
- path_sock => "$opt_tmpdir/mysqld_2.sock",
+ path_sock => "$sockdir/mysqld_2.sock",
path_pid => "$opt_vardir/run/mysqld_2.pid",
nonguarded => 1,
};
@@ -905,6 +920,7 @@ sub command_line_setup () {
}
$path_timefile= "$opt_vardir/log/mysqltest-time";
+ $path_mysqltest_log= "$opt_vardir/log/mysqltest.log";
}
@@ -922,11 +938,14 @@ sub executable_setup () {
{
$path_client_bindir= mtr_path_exists("$glob_basedir/client_release",
"$glob_basedir/bin");
- $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-nt",
+ $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-max",
+ "$path_client_bindir/mysqld-nt",
"$path_client_bindir/mysqld",
"$path_client_bindir/mysqld-debug",);
$path_language= mtr_path_exists("$glob_basedir/share/english/");
$path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets");
+ $exe_my_print_defaults=
+ mtr_exe_exists("$path_client_bindir/my_print_defaults");
}
else
{
@@ -937,6 +956,8 @@ sub executable_setup () {
$exe_im= mtr_exe_exists(
"$glob_basedir/server-tools/instance-manager/mysqlmanager");
+ $exe_my_print_defaults=
+ mtr_exe_exists("$glob_basedir/extra/my_print_defaults");
}
if ( $glob_use_embedded_server )
@@ -949,7 +970,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");
@@ -963,8 +996,6 @@ sub executable_setup () {
$exe_mysql= mtr_exe_exists("$path_client_bindir/mysql");
$exe_mysql_fix_system_tables=
mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables");
- $exe_my_print_defaults=
- mtr_script_exists("$glob_basedir/extra/my_print_defaults");
$path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools");
$exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm";
}
@@ -982,7 +1013,7 @@ sub executable_setup () {
mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables",
"$glob_basedir/scripts/mysql_fix_privilege_tables");
$exe_my_print_defaults=
- mtr_script_exists("$path_client_bindir/my_print_defaults");
+ mtr_exe_exists("$path_client_bindir/my_print_defaults");
$path_language= mtr_path_exists("$glob_basedir/share/mysql/english/",
"$glob_basedir/share/english/");
@@ -1880,6 +1911,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);
}
# ----------------------------------------------------------------------
@@ -2040,7 +2076,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);
@@ -2266,7 +2302,7 @@ sub mysqld_start ($$$$) {
mtr_init_args(\$args);
- if ( defined $opt_valgrind )
+ if ( defined $opt_valgrind_mysqld )
{
valgrind_arguments($args, \$exe);
}
@@ -2597,6 +2633,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, ....
@@ -2705,6 +2756,7 @@ sub valgrind_arguments {
mtr_add_arg($args, split(' ', $opt_valgrind_options));
}
+
mtr_add_arg($args, $$exe);
$$exe= $opt_valgrind || "valgrind";
@@ -2728,6 +2780,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
@@ -2780,9 +2836,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 c84763713e1..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
@@ -279,7 +292,7 @@ DO_STRESS=""
STRESS_SUITE="main"
STRESS_MODE="random"
STRESS_THREADS=5
-STRESS_TEST_COUNT=20
+STRESS_TEST_COUNT=""
STRESS_LOOP_COUNT=""
STRESS_TEST_DURATION=""
STRESS_INIT_FILE=""
@@ -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
}
@@ -1261,6 +1284,7 @@ start_master()
--server-id=$id \
--basedir=$MY_BASEDIR \
--port=$this_master_myport \
+ --port-open-timeout=380 \
--local-infile \
--exit-info=256 \
--core \
@@ -1285,6 +1309,7 @@ start_master()
--server-id=$id --rpl-recovery-rank=1 \
--basedir=$MY_BASEDIR --init-rpl-role=master \
--port=$this_master_myport \
+ --port-open-timeout=380 \
--local-infile \
--datadir=$MASTER_MYDDIR$1 \
--pid-file=$MASTER_MYPID$1 \
@@ -1417,6 +1442,7 @@ start_slave()
--datadir=$slave_datadir \
--pid-file=$slave_pid \
--port=$slave_port \
+ --port-open-timeout=380 \
--socket=$slave_sock \
--character-sets-dir=$CHARSETSDIR \
--default-character-set=$CHARACTER_SET \
@@ -1767,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"
@@ -1906,7 +1936,7 @@ run_stress_test()
--stress-basedir=$STRESS_BASEDIR \
--server-logs-dir=$STRESS_BASEDIR \
--stress-mode=$STRESS_MODE \
- --mysqltest=$BASEDIR/client/mysqltest \
+ --mysqltest=$CLIENT_BINDIR/mysqltest \
--threads=$STRESS_THREADS \
--verbose \
--cleanup \
@@ -1917,6 +1947,14 @@ run_stress_test()
STRESS_TEST_ARGS="$STRESS_TEST_ARGS --stress-init-file=$STRESS_INIT_FILE"
fi
+ if [ -z "$STRESS_LOOP_COUNT" -a -z "$STRESS_TEST_COUNT" -a
+ -z "$STRESS_TEST_DURATION" ] ; then
+
+ #Limit stress testing with 20 loops in case when any limit parameter
+ #was specified
+ STRESS_TEST_COUNT=20
+ fi
+
if [ -n "$STRESS_LOOP_COUNT" ] ; then
STRESS_TEST_ARGS="$STRESS_TEST_ARGS --loop-count=$STRESS_LOOP_COUNT"
fi
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index f224a10c9bd..5c50b3cd79d 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -562,3 +562,7 @@ desc t1;
Field Type Null Key Default Extra
mycol int(10) NO 0
drop table t1;
+create table t1 (t varchar(255) default null, key t (t(80)))
+engine=myisam default charset=latin1;
+alter table t1 change t t text;
+drop table t1;
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index a564fd1045c..af6319afe99 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -1923,4 +1923,9 @@ d varchar(255) character set utf8,
e varchar(255) character set utf8,
key (a,b,c,d,e)) engine=bdb;
ERROR 42000: Specified key was too long; max key length is 3072 bytes
+set autocommit=0;
+create table t1 (a int) engine=bdb;
+commit;
+alter table t1 add primary key(a);
+drop table t1;
End of 5.0 tests
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index c981d3092a7..848b84e2b8c 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -259,21 +259,6 @@ select * from t1;
0 1 2
0 0 1
drop table t1;
-create table t1 select 1,2,3;
-create table if not exists t1 select 1,2;
-Warnings:
-Note 1050 Table 't1' already exists
-create table if not exists t1 select 1,2,3,4;
-ERROR 21S01: Column count doesn't match value count at row 1
-create table if not exists t1 select 1;
-Warnings:
-Note 1050 Table 't1' already exists
-select * from t1;
-1 2 3
-1 2 3
-0 1 2
-0 0 1
-drop table t1;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
@@ -287,7 +272,6 @@ a b
create table if not exists t1 select 3 as 'a',4 as 'b';
Warnings:
Note 1050 Table 't1' already exists
-Warning 1364 Field 'a' doesn't have a default value
create table if not exists t1 select 3 as 'a',3 as 'b';
ERROR 23000: Duplicate entry '3' for key 1
select * from t1;
@@ -614,6 +598,11 @@ DESC t2;
Field Type Null Key Default Extra
f2 varchar(171) YES NULL
DROP TABLE t1,t2;
+CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1;
+SELECT * FROM t12913;
+f1
+a
+DROP TABLE t12913;
create database mysqltest;
use mysqltest;
drop database mysqltest;
@@ -645,8 +634,6 @@ create table t1 (
a varchar(112) charset utf8 collate utf8_bin not null,
primary key (a)
) select 'test' as a ;
-Warnings:
-Warning 1364 Field 'a' doesn't have a default value
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -662,9 +649,6 @@ create table t1 (
a varchar(12) charset utf8 collate utf8_bin not null,
b int not null, primary key (a)
) select a, 1 as b from t2 ;
-Warnings:
-Warning 1364 Field 'a' doesn't have a default value
-Warning 1364 Field 'b' doesn't have a default value
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -674,12 +658,37 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (
+a varchar(12) charset utf8 collate utf8_bin not null,
+b int not null, primary key (a)
+) select a, 1 as c from t2 ;
+Warnings:
+Warning 1364 Field 'b' doesn't have a default value
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `b` int(11) NOT NULL,
+ `a` varchar(12) character set utf8 collate utf8_bin NOT NULL,
+ `c` bigint(1) NOT NULL default '0',
+ PRIMARY KEY (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (
+a varchar(12) charset utf8 collate utf8_bin not null,
+b int null, primary key (a)
+) select a, 1 as c from t2 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `b` int(11) default NULL,
+ `a` varchar(12) character set utf8 collate utf8_bin NOT NULL,
+ `c` bigint(1) NOT NULL default '0',
+ PRIMARY KEY (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+create table t1 (
a varchar(12) charset utf8 collate utf8_bin not null,
b int not null, primary key (a)
) select 'a' as a , 1 as b from t2 ;
-Warnings:
-Warning 1364 Field 'a' doesn't have a default value
-Warning 1364 Field 'b' doesn't have a default value
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -692,8 +701,6 @@ create table t1 (
a varchar(12) charset utf8 collate utf8_bin,
b int not null, primary key (a)
) select 'a' as a , 1 as b from t2 ;
-Warnings:
-Warning 1364 Field 'b' doesn't have a default value
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
@@ -712,8 +719,6 @@ a1 varchar(12) charset utf8 collate utf8_bin not null,
a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int,
primary key (a1)
) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ;
-Warnings:
-Warning 1364 Field 'a1' doesn't have a default value
drop table t2;
create table t2 (
a1 varchar(12) charset utf8 collate utf8_bin,
@@ -729,8 +734,6 @@ a1 varchar(12) charset utf8 collate utf8_bin not null,
a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int,
primary key (a1)
) select a1,a2,a3,a4,a5,a6,a7,a8,a9 from t1 ;
-Warnings:
-Warning 1364 Field 'a1' doesn't have a default value
drop table t2;
create table t2 ( a int default 3, b int default 3)
select a1,a2 from t1;
diff --git a/mysql-test/r/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_uca.result b/mysql-test/r/ctype_uca.result
index 4b245c69d2a..3e286c77c00 100644
--- a/mysql-test/r/ctype_uca.result
+++ b/mysql-test/r/ctype_uca.result
@@ -2015,6 +2015,112 @@ Z,z,Ź,ź,Ż,ż,Ž,ž
Ç
Ç‚
ǃ
+select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci;
+group_concat(c1 order by c1)
+÷
+×
+A,a,À,Ã,Â,Ã,Ä,Ã…,à ,á,â,ã,ä,Ã¥,Ä€,Ä,Ä‚,ă,Ä„,Ä…,Ç,ÇŽ,Çž,ÇŸ,Ç ,Ç¡,Ǻ,Ç»
+AA,Aa,aA,aa
+Æ,æ,Ǣ,ǣ,Ǽ,ǽ
+B,b
+Æ€
+Æ
+Ƃ,ƃ
+C,c,Ç,ç,Ć,ć,Ĉ,ĉ,ÄŠ,Ä‹,ÄŒ,Ä
+CH,Ch,cH,ch
+Ƈ,ƈ
+D,d,ÄŽ,Ä
+DZ,Dz,dZ,dz,DŽ,Dž,dž,DZ,Dz,dz
+Ä,Ä‘
+Ɖ
+ÆŠ
+Ƌ,ƌ
+Ã,ð
+E,e,È,É,Ê,Ë,è,é,ê,ë,Ē,ē,Ĕ,ĕ,Ė,ė,Ę,ę,Ě,ě
+ÆŽ,Ç
+Æ
+Æ
+F,f
+Æ‘,Æ’
+G,g,Äœ,Ä,Äž,ÄŸ,Ä ,Ä¡,Ä¢,Ä£,Ǧ,ǧ,Ç´,ǵ
+Ǥ,ǥ
+Æ“
+Æ”
+Æ¢,Æ£
+H,h,Ĥ,ĥ
+ƕ,Ƕ
+Ħ,ħ
+I,i,ÃŒ,Ã,ÃŽ,Ã,ì,Ã,î,ï,Ĩ,Ä©,Ī,Ä«,Ĭ,Ä,Ä®,į,İ,Ç,Ç
+IJ,Ij,iJ,ij,IJ,ij
+ı
+Æ—
+Æ–
+J,j,Ĵ,ĵ,ǰ
+K,k,Ķ,ķ,Ǩ,ǩ
+Ƙ,ƙ
+L,l,Ĺ,ĺ,Ļ,ļ,Ľ,ľ
+Ä¿,Å€
+LJ,Lj,lJ,lj,LJ,Lj,lj
+LL,Ll,lL,ll
+Å,Å‚
+Æš
+Æ›
+M,m
+N,n,Ñ,ñ,Ń,ń,Ņ,ņ,Ň,ň,Ǹ,ǹ
+NJ,Nj,nJ,nj,NJ,Nj,nj
+Æ
+Æž
+ÅŠ,Å‹
+O,o,Ã’,Ó,Ô,Õ,ò,ó,ô,õ,ÅŒ,Å,ÅŽ,Å,Æ ,Æ¡,Ç‘,Ç’,Ǫ,Ç«,Ǭ,Ç
+OE,Oe,oE,oe,Å’,Å“
+Ö,ö,Å,Å‘
+Ø,ø,Ǿ,ǿ
+Ɔ
+ÆŸ
+P,p
+Ƥ,ƥ
+Q,q
+ĸ
+R,r,Ŕ,ŕ,Ŗ,ŗ,Ř,ř
+RR,Rr,rR,rr
+Ʀ
+S,s,Åš,Å›,Åœ,Å,Åž,ÅŸ,Å ,Å¡,Å¿
+SS,Ss,sS,ss,ß
+Æ©
+ƪ
+T,t,Ţ,ţ,Ť,ť
+ƾ
+Ŧ,ŧ
+Æ«
+Ƭ,Æ
+Æ®
+U,u,Ù,Ú,Û,ù,ú,û,Ũ,Å©,Ū,Å«,Ŭ,Å,Å®,ů,Ų,ų,Ư,ư,Ç“,Ç”,Ç•,Ç–,Ç—,ǘ,Ç™,Çš,Ç›,Çœ
+Ü,ü,Ű,ű
+Ɯ
+Ʊ
+V,v
+Ʋ
+W,w,Ŵ,ŵ
+X,x
+Y,y,Ã,ý,ÿ,Ŷ,Å·,Ÿ
+Ƴ,ƴ
+Z,z,Ź,ź,Ż,ż,Ž,ž
+Æ
+Ƶ,ƶ
+Ʒ,Ǯ,ǯ
+Ƹ,ƹ
+ƺ
+Þ,þ
+Æ¿,Ç·
+Æ»
+Ƨ,ƨ
+Ƽ,ƽ
+Æ„,Æ…
+ʼn
+Ç€
+Ç
+Ç‚
+ǃ
drop table t1;
SET NAMES utf8;
CREATE TABLE t1 (c varchar(255) NOT NULL COLLATE utf8_general_ci, INDEX (c));
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 65b5a1cbba8..d11d25f9b35 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -685,6 +685,13 @@ hex(a)
005B
803D
drop table t1;
+create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB;
+insert into t1 values('a');
+create index t1f1 on t1(f1);
+select f1 from t1 where f1 like 'a%';
+f1
+a
+drop table t1;
CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3));
INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0);
update t1 set b=a;
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/fulltext2.result b/mysql-test/r/fulltext2.result
index 0b1d8eb9a15..72c6b2d22ed 100644
--- a/mysql-test/r/fulltext2.result
+++ b/mysql-test/r/fulltext2.result
@@ -215,3 +215,24 @@ select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
262
drop table t1;
+set names utf8;
+create table t1(a text,fulltext(a)) collate=utf8_swedish_ci;
+insert into t1 values('test test '),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test');
+delete from t1 limit 1;
+drop table t1;
+set names latin1;
diff --git a/mysql-test/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/grant2.result b/mysql-test/r/grant2.result
index 9c744396403..246aaa3a93e 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -107,6 +107,17 @@ delete from mysql.columns_priv where user like 'mysqltest\_%';
flush privileges;
drop database mysqltest;
use test;
+create user mysqltest_1@host1;
+create user mysqltest_2@host2;
+create user mysqltest_3@host3;
+create user mysqltest_4@host4;
+create user mysqltest_5@host5;
+create user mysqltest_6@host6;
+create user mysqltest_7@host7;
+flush privileges;
+drop user mysqltest_3@host3;
+drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4,
+mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7;
set sql_mode='maxdb';
drop table if exists t1, t2;
create table t1(c1 int);
diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result
index 133683fb273..104025e83eb 100644
--- a/mysql-test/r/handler.result
+++ b/mysql-test/r/handler.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1,t3,t4,t5;
create table t1 (a int, b char(10), key a(a), key b(a,b));
insert into t1 values
(17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"),
diff --git a/mysql-test/r/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 6224b30b70e..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;
@@ -1056,3 +1050,37 @@ where table_name="v1";
table_type
VIEW
drop view v1;
+create temporary table t1(f1 int, index(f1));
+show columns from t1;
+Field Type Null Key Default Extra
+f1 int(11) YES MUL NULL
+describe t1;
+Field Type Null Key Default Extra
+f1 int(11) YES MUL NULL
+show indexes from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 f1 1 f1 A NULL NULL NULL YES BTREE
+drop table t1;
+create table t1(f1 binary(32), f2 varbinary(64));
+select character_maximum_length, character_octet_length
+from information_schema.columns where table_name='t1';
+character_maximum_length character_octet_length
+32 32
+64 64
+drop table t1;
+CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT);
+INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1;
+CREATE FUNCTION func2() RETURNS BIGINT RETURN 1;
+CREATE FUNCTION func1() RETURNS BIGINT
+BEGIN
+RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS);
+END//
+CREATE VIEW v1 AS SELECT 1 FROM t1
+WHERE f3 = (SELECT func2 ());
+SELECT func1();
+func1()
+1
+DROP TABLE t1;
+DROP VIEW v1;
+DROP FUNCTION func1;
+DROP FUNCTION func2;
diff --git a/mysql-test/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/innodb.result b/mysql-test/r/innodb.result
index dcff72ba7c0..973ad72042e 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -2718,6 +2718,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+a hex(b) hex(c) filler
+1 61626364656667 61626364656667 boo
+4 D0B1 D0B1 eight
+4 5B 5B five
+4 E880BD E880BD four
+4 E880BDD0B1E880BD E880BDD0B1E880BD seven
+4 E880BDE880BD E880BDE880BD six
+3 71727374757677 71727374757677 three
+2 696A6B696C6D6E 696A6B696C6D6E two
+select a,hex(b),hex(c),filler from t2 order by filler;
+a hex(b) hex(c) filler
+4 05630563 05630563 email
+4 0563 0563 email
+4 05612020 05612020 email
+4 01FC 01FC email
+4 0120 0120 email
+4 00640065 00640065 email
+4 00E400E50068 00E400E50068 email
+4 0000E400 0000E400 email
+4 0000563001FC0563 0000563001FC0563 email
+1 0061006200630064006500660067 0061006200630064006500660067 one
+3 0071007200730074007500760077 0071007200730074007500760077 three
+2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two
drop table t1;
drop table t2;
create table t1 (
@@ -2746,6 +2772,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+a hex(b) hex(c) filler
+1 61626364656667 61626364656667 boo
+4 D0B1 D0B1 eight
+4 5B 5B five
+4 E880BD E880BD four
+4 E880BDD0B1E880BD E880BDD0B1E880BD seven
+4 E880BDE880BD E880BDE880BD six
+3 71727374757677 71727374757677 three
+2 696A6B696C6D6E 696A6B696C6D6E two
+select a,hex(b),hex(c),filler from t2 order by filler;
+a hex(b) hex(c) filler
+4 05630563 05630563 email
+4 0563 0563 email
+4 05612020 05612020 email
+4 01FC 01FC email
+4 0120 0120 email
+4 00640065 00640065 email
+4 00E400E50068 00E400E50068 email
+4 0000E400 0000E400 email
+4 0000563001FC0563 0000563001FC0563 email
+1 0061006200630064006500660067 0061006200630064006500660067 one
+3 0071007200730074007500760077 0071007200730074007500760077 three
+2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two
drop table t1;
drop table t2;
create table t1 (
@@ -2774,6 +2826,32 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+a hex(b) hex(c) filler
+1 61626364656667 61626364656667 boo
+4 D0B1 D0B1 eight
+4 5B 5B five
+4 E880BD E880BD four
+4 E880BDD0B1E880BD E880BDD0B1E880BD seven
+4 E880BDE880BD E880BDE880BD six
+3 71727374757677 71727374757677 three
+2 696A6B696C6D6E 696A6B696C6D6E two
+select a,hex(b),hex(c),filler from t2 order by filler;
+a hex(b) hex(c) filler
+4 0120 0120 email
+4 01FC 01FC email
+4 0563 0563 email
+4 0000563001FC0563 0000563001FC0563 email
+4 0000E400 0000E400 email
+4 00640065 00640065 email
+4 00E400E50068 00E400E50068 email
+4 05612020 05612020 email
+4 05630563 05630563 email
+1 0061006200630064006500660067 0061006200630064006500660067 one
+3 0071007200730074007500760077 0071007200730074007500760077 three
+2 0069006A006B0069006C006D006E 0069006A006B0069006C006D006E two
drop table t1;
drop table t2;
create table t1 (
@@ -2798,6 +2876,28 @@ insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven');
insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight');
insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+a hex(b) hex(c) filler
+1 61626364656667 61626364656667 boo
+4 D0B1 D0B1 eight
+4 5B 5B five
+4 E880BD E880BD four
+3 71727374757677 71727374757677 three
+2 696A6B696C6D6E 696A6B696C6D6E two
+select a,hex(b),hex(c),filler from t2 order by filler;
+a hex(b) hex(c) filler
+4 0000E400 0000E400 email
+4 00640065 00640065 email
+4 00E400E50068 00E400E50068 email
+4 0120 0120 email
+4 01FC 01FC email
+4 05612020 05612020 email
+4 0563 0563 email
+1 61626364656667 61626364656667 one
+3 71727374757677 71727374757677 three
+2 696A6B696C6D6E 696A6B696C6D6E two
drop table t1;
drop table t2;
commit;
@@ -2833,19 +2933,6 @@ rename table t3 to t1;
ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150)
set foreign_key_checks=1;
drop table t2,t3;
-create table t1 (a varchar(255) character set utf8,
-b varchar(255) character set utf8,
-c varchar(255) character set utf8,
-d varchar(255) character set utf8,
-key (a,b,c,d)) engine=innodb;
-drop table t1;
-create table t1 (a varchar(255) character set utf8,
-b varchar(255) character set utf8,
-c varchar(255) character set utf8,
-d varchar(255) character set utf8,
-e varchar(255) character set utf8,
-key (a,b,c,d,e)) engine=innodb;
-ERROR 42000: Specified key was too long; max key length is 3072 bytes
create table t1(a int primary key) row_format=redundant engine=innodb;
create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb;
create table t3(a int primary key) row_format=compact engine=innodb;
@@ -2875,4 +2962,221 @@ truncate t4;
truncate t1;
truncate t3;
drop table t4,t3,t2,t1;
-End of 5.0 tests
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+key (a,b,c,d)) engine=innodb;
+drop table t1;
+create table t1 (a varchar(255) character set utf8,
+b varchar(255) character set utf8,
+c varchar(255) character set utf8,
+d varchar(255) character set utf8,
+e varchar(255) character set utf8,
+key (a,b,c,d,e)) engine=innodb;
+ERROR 42000: Specified key was too long; max key length is 3072 bytes
+create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb;
+create table t2 (s1 binary(2),primary key (s1)) engine=innodb;
+create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb;
+create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb;
+insert into t1 values (0x41),(0x4120),(0x4100);
+insert into t2 values (0x41),(0x4120),(0x4100);
+ERROR 23000: Duplicate entry 'A' for key 1
+insert into t2 values (0x41),(0x4120);
+insert into t3 values (0x41),(0x4120),(0x4100);
+ERROR 23000: Duplicate entry 'A ' for key 1
+insert into t3 values (0x41),(0x4100);
+insert into t4 values (0x41),(0x4120),(0x4100);
+ERROR 23000: Duplicate entry 'A' for key 1
+insert into t4 values (0x41),(0x4100);
+select hex(s1) from t1;
+hex(s1)
+41
+4100
+4120
+select hex(s1) from t2;
+hex(s1)
+4100
+4120
+select hex(s1) from t3;
+hex(s1)
+4100
+41
+select hex(s1) from t4;
+hex(s1)
+4100
+41
+drop table t1,t2,t3,t4;
+create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb;
+create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
+insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42);
+insert into t2 values(0x42);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+insert into t2 values(0x41);
+select hex(s1) from t2;
+hex(s1)
+4100
+update t1 set s1=0x123456 where a=2;
+select hex(s1) from t2;
+hex(s1)
+4100
+update t1 set s1=0x12 where a=1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+update t1 set s1=0x12345678 where a=1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+update t1 set s1=0x123457 where a=1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+update t1 set s1=0x1220 where a=1;
+select hex(s1) from t2;
+hex(s1)
+1220
+update t1 set s1=0x1200 where a=1;
+select hex(s1) from t2;
+hex(s1)
+1200
+update t1 set s1=0x4200 where a=1;
+select hex(s1) from t2;
+hex(s1)
+4200
+delete from t1 where a=1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+delete from t1 where a=2;
+update t2 set s1=0x4120;
+delete from t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+delete from t1 where a!=3;
+select a,hex(s1) from t1;
+a hex(s1)
+3 4120
+select hex(s1) from t2;
+hex(s1)
+4120
+drop table t2,t1;
+create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb;
+create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
+insert into t1 values(1,0x4100),(2,0x41);
+insert into t2 values(0x41);
+select hex(s1) from t2;
+hex(s1)
+41
+update t1 set s1=0x1234 where a=1;
+select hex(s1) from t2;
+hex(s1)
+41
+update t1 set s1=0x12 where a=2;
+select hex(s1) from t2;
+hex(s1)
+12
+delete from t1 where a=1;
+delete from t1 where a=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
+select a,hex(s1) from t1;
+a hex(s1)
+2 12
+select hex(s1) from t2;
+hex(s1)
+12
+drop table t2,t1;
+CREATE TABLE t1 (
+ind enum('0','1','2') NOT NULL default '0',
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ind enum('0','1','2') NOT NULL default '0',
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+INSERT INTO t1 VALUES ('1', ''),('2', '');
+INSERT INTO t2 VALUES ('1', ''),('2', '');
+SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1;
+hex(ind) hex(string1)
+31
+32
+SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1;
+hex(ind) hex(string1)
+0031
+0032
+drop table t1,t2;
+CREATE TABLE t1 (
+ind set('0','1','2') NOT NULL default '0',
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ind set('0','1','2') NOT NULL default '0',
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+INSERT INTO t1 VALUES ('1', ''),('2', '');
+INSERT INTO t2 VALUES ('1', ''),('2', '');
+SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1;
+hex(ind) hex(string1)
+31
+32
+SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1;
+hex(ind) hex(string1)
+0031
+0032
+drop table t1,t2;
+CREATE TABLE t1 (
+ind bit not null,
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ind bit not null,
+string1 varchar(250) NOT NULL,
+PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+insert into t1 values(0,''),(1,'');
+insert into t2 values(0,''),(1,'');
+select hex(ind),hex(string1) from t1 order by string1;
+hex(ind) hex(string1)
+0
+1
+select hex(ind),hex(string1) from t2 order by string1;
+hex(ind) hex(string1)
+0
+1
+drop table t1,t2;
+create table t2 (
+a int, b char(10), filler char(10), primary key(a, b(2))
+) character set utf8 engine = innodb;
+insert into t2 values (1,'abcdefg','one');
+insert into t2 values (2,'ijkilmn','two');
+insert into t2 values (3, 'qrstuvw','three');
+update t2 set a=5, filler='booo' where a=1;
+drop table t2;
+create table t2 (
+a int, b char(10), filler char(10), primary key(a, b(2))
+) character set ucs2 engine = innodb;
+insert into t2 values (1,'abcdefg','one');
+insert into t2 values (2,'ijkilmn','two');
+insert into t2 values (3, 'qrstuvw','three');
+update t2 set a=5, filler='booo' where a=1;
+drop table t2;
+create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8;
+insert into t1 values(1,'abcdefg'),(2,'defghijk');
+insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1);
+insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2);
+select a,hex(b) from t1 order by b;
+a hex(b)
+1 61626364656667
+2 6465666768696A6B
+6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1
+7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2
+update t1 set b = 'three' where a = 6;
+drop table t1;
+create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8;
+insert into t1 values(1,'abcdefg'),(2,'defghijk');
+insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1);
+insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2);
+select a,hex(b) from t1 order by b;
+a hex(b)
+1 61626364656667
+2 6465666768696A6B
+6 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1
+7 D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2
+update t1 set b = 'three' where a = 6;
+drop table t1;
diff --git a/mysql-test/r/innodb_unsafe_binlog.result b/mysql-test/r/innodb_unsafe_binlog.result
new file mode 100644
index 00000000000..4a4f0e0fae5
--- /dev/null
+++ b/mysql-test/r/innodb_unsafe_binlog.result
@@ -0,0 +1,48 @@
+drop table if exists t1,t2;
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(f_id, id)) engine=innodb;
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id)) engine=innodb;
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+commit;
+DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
+WHERE mm.id IS NULL;
+select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
+where mm.id is null lock in share mode;
+id f_id f
+drop table t1,t2;
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(id),key(f_id)) engine=innodb;
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id),key(s_id)) engine=innodb;
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+commit;
+delete ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null;
+select ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null lock in share mode;
+id f_id f
+drop table t1,t2;
+create table t1(a int not null, b int, primary key(a)) engine=innodb;
+insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
+commit;
+set autocommit = 0;
+select * from t1 lock in share mode;
+a b
+1 1
+2 2
+3 1
+4 2
+5 1
+6 2
+update t1 set b = 5 where b = 1;
+set autocommit = 0;
+select * from t1 where a = 2 and b = 2 for update;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+commit;
+drop table t1;
diff --git a/mysql-test/r/join_nested.result b/mysql-test/r/join_nested.result
index 6b7293d46bc..faad969fcd1 100644
--- a/mysql-test/r/join_nested.result
+++ b/mysql-test/r/join_nested.result
@@ -960,7 +960,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
-1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
@@ -1009,7 +1009,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
-1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where
@@ -1059,7 +1059,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
-1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t5 ALL idx_b NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ref idx_b idx_b 5 test.t5.b 2 Using where
@@ -1467,3 +1467,17 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t6 ref a a 5 test.t4.b X
1 SIMPLE t5 ref a a 5 test.t3.b X
drop table t0, t1, t2, t3, t4, t5, t6, t7;
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, filler char(100), key(a));
+insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B;
+create table t3 like t2;
+insert into t3 select * from t2;
+explain select * from t1 left join
+(t2 left join t3 on (t2.a = t3.a))
+on (t1.a = t2.a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10
+1 SIMPLE t2 ref a a 5 test.t1.a 1
+1 SIMPLE t3 ref a a 5 test.t2.a 1
+drop table t1, t2, t3;
diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result
index 754568093ff..2413834be4f 100644
--- a/mysql-test/r/kill.result
+++ b/mysql-test/r/kill.result
@@ -5,8 +5,6 @@ select ((@id := kill_id) - kill_id) from t1;
((@id := kill_id) - kill_id)
0
kill @id;
-select 1;
-Got one of the listed errors
select ((@id := kill_id) - kill_id) from t1;
((@id := kill_id) - kill_id)
0
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index e028e58acf5..7e3ccc83d73 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -719,3 +719,52 @@ SELECT b FROM t2;
b
3
DROP TABLE t1, t2;
+create table t1(a int);
+create table t2(a int);
+insert into t1 values (1);
+insert into t2 values (2);
+create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
+select * from t3;
+a
+1
+2
+insert t2 select * from t2;
+select * from t2;
+a
+2
+2
+insert t3 select * from t1;
+select * from t3;
+a
+1
+1
+2
+2
+insert t1 select * from t3;
+select * from t1;
+a
+1
+1
+1
+1
+2
+2
+select * from t2;
+a
+2
+2
+select * from t3;
+a
+1
+1
+1
+1
+2
+2
+2
+2
+check table t1, t2;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+test.t2 check status OK
+drop table t1, t2, t3;
diff --git a/mysql-test/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/mysqlshow.result b/mysql-test/r/mysqlshow.result
index 355c20fdad3..942cde83f21 100644
--- a/mysql-test/r/mysqlshow.result
+++ b/mysql-test/r/mysqlshow.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1,t2;
+DROP TABLE IF EXISTS t1,t2,test1,test2;
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (1),(2),(3);
CREATE TABLE t2 (a int, b int);
diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result
index 5ff931dafb5..df530eda285 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,12 +355,14 @@ 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
+connect(localhost,root,,test,MASTER_PORT,MASTER_SOCKET);
Output from mysqltest-x.inc
Output from mysqltest-x.inc
Output from mysqltest-x.inc
@@ -391,12 +398,20 @@ root@localhost
--------------------------------------------------------------------------------
this will be executed
this will be executed
+mysqltest: Result length mismatch
+mysqltest: The test didn't produce any output
+Failing multi statement query
mysqltest: At line 3: query 'create table t1 (a int primary key);
insert into t1 values (1);
select 'select-me';
insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1
drop table t1;
+mysqltest: At line 3: query 'create table t1 (a int primary key);
+insert into t1 values (1);
+select 'select-me';
+insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1
drop table t1;
+Multi statement using expected error
create table t1 (a int primary key);
insert into t1 values (1);
select 'select-me';
@@ -405,11 +420,4 @@ select-me
select-me
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz error query' at line 1
drop table t1;
-create table t1 (a int primary key);
-insert into t1 values (1);
-select 'select-me';
-insertz error query||||
-select-me
-select-me
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz error query' at line 1
drop table t1;
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.result b/mysql-test/r/ps.result
index bc3d2a6108c..a7c05e9acad 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -825,6 +825,40 @@ execute stmt;
drop table t1;
set names default;
deallocate prepare stmt;
+create table t1 (
+word_id mediumint(8) unsigned not null default '0',
+formatted varchar(20) not null default ''
+);
+insert into t1 values
+(80,'pendant'), (475,'pretendants'), (989,'tendances'),
+(1019,'cependant'),(1022,'abondance'),(1205,'independants'),
+(13,'lessiver'),(25,'lambiner'),(46,'situer'),(71,'terminer'),
+(82,'decrocher');
+select count(*) from t1 where formatted like '%NDAN%';
+count(*)
+6
+select count(*) from t1 where formatted like '%ER';
+count(*)
+5
+prepare stmt from "select count(*) from t1 where formatted like ?";
+set @like="%NDAN%";
+execute stmt using @like;
+count(*)
+6
+set @like="%ER";
+execute stmt using @like;
+count(*)
+5
+set @like="%NDAN%";
+execute stmt using @like;
+count(*)
+6
+set @like="%ER";
+execute stmt using @like;
+count(*)
+5
+deallocate prepare stmt;
+drop table t1;
create table t1 (id int);
prepare ins_call from "insert into t1 (id) values (1)";
execute ins_call;
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/rpl000001.result b/mysql-test/r/rpl000001.result
index 450e728090e..de9f6f16b2a 100644
--- a/mysql-test/r/rpl000001.result
+++ b/mysql-test/r/rpl000001.result
@@ -50,7 +50,7 @@ select (@id := id) - id from t2;
0
kill @id;
drop table t2;
-ERROR 08S01: Server shutdown in progress
+Got one of the listed errors
set global sql_slave_skip_counter=1;
start slave;
select count(*) from t1;
diff --git a/mysql-test/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/rpl_sp.result b/mysql-test/r/rpl_sp.result
index 41bcfc7d72c..c9a9e162fa6 100644
--- a/mysql-test/r/rpl_sp.result
+++ b/mysql-test/r/rpl_sp.result
@@ -57,6 +57,9 @@ insert into t1 values (15);
grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1;
grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1;
grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1;
+SELECT 1;
+1
+1
create procedure foo4()
deterministic
begin
diff --git a/mysql-test/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-code.result b/mysql-test/r/sp-code.result
index e6c4ffe1731..943471c2261 100644
--- a/mysql-test/r/sp-code.result
+++ b/mysql-test/r/sp-code.result
@@ -49,7 +49,7 @@ Pos Instruction
9 set err@1 1
10 hreturn 5
11 cfetch c@0 n@4
-12 jump_if_not 15 isnull(n@4)
+12 jump_if_not 15(17) isnull(n@4)
13 set nulls@2 (nulls@2 + 1)
14 jump 17
15 set count@3 (count@3 + 1)
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index d7bed7e88a7..9a148c3516e 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -535,7 +535,7 @@ fetch c into v;
end|
delete from t1|
call bug7299()|
-ERROR 02000: No data to FETCH
+ERROR 02000: No data - zero rows fetched, selected, or processed
drop procedure bug7299|
create procedure bug9073()
begin
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index ded9754f172..19f3d033f53 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -522,7 +522,7 @@ delete from t1|
create table t3 ( s char(16), d int)|
call into_test4()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from t3|
s d
into4 NULL
@@ -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|
@@ -1720,10 +1787,10 @@ end|
call bug1863(10)|
Warnings:
Note 1051 Unknown table 'temp_t1'
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug1863(10)|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from t4|
f1 rc t3
2 0 NULL
@@ -2017,10 +2084,10 @@ end|
call bug4579_1()|
call bug4579_1()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug4579_1()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop procedure bug4579_1|
drop procedure bug4579_2|
drop table t3|
@@ -2499,7 +2566,7 @@ call bug7743("OneWord")|
var
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug7743("anotherword")|
var
2
@@ -2507,7 +2574,7 @@ call bug7743("AnotherWord")|
var
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop procedure bug7743|
drop table t4|
delete from t3|
@@ -3557,8 +3624,6 @@ drop procedure if exists bug7049_1|
drop procedure if exists bug7049_2|
drop procedure if exists bug7049_3|
drop procedure if exists bug7049_4|
-drop procedure if exists bug7049_5|
-drop procedure if exists bug7049_6|
drop function if exists bug7049_1|
drop function if exists bug7049_2|
create table t3 ( x int unique )|
@@ -3583,18 +3648,6 @@ select 'Caught it' as 'Result';
call bug7049_3();
select 'Missed it' as 'Result';
end|
-create procedure bug7049_5()
-begin
-declare x decimal(2,1);
-set x = 'zap';
-end|
-create procedure bug7049_6()
-begin
-declare exit handler for sqlwarning
-select 'Caught it' as 'Result';
-call bug7049_5();
-select 'Missed it' as 'Result';
-end|
create function bug7049_1()
returns int
begin
@@ -3624,9 +3677,6 @@ Caught it
select * from t3|
x
42
-call bug7049_6()|
-Result
-Caught it
select bug7049_2()|
bug7049_2()
1
@@ -3635,8 +3685,6 @@ drop procedure bug7049_1|
drop procedure bug7049_2|
drop procedure bug7049_3|
drop procedure bug7049_4|
-drop procedure bug7049_5|
-drop procedure bug7049_6|
drop function bug7049_1|
drop function bug7049_2|
drop function if exists bug13941|
@@ -4320,4 +4368,143 @@ id county
2 NULL
drop table t3|
drop procedure bug15441|
+drop procedure if exists bug14498_1|
+drop procedure if exists bug14498_2|
+drop procedure if exists bug14498_3|
+drop procedure if exists bug14498_4|
+drop procedure if exists bug14498_5|
+create procedure bug14498_1()
+begin
+declare continue handler for sqlexception select 'error' as 'Handler';
+if v then
+select 'yes' as 'v';
+else
+select 'no' as 'v';
+end if;
+select 'done' as 'End';
+end|
+create procedure bug14498_2()
+begin
+declare continue handler for sqlexception select 'error' as 'Handler';
+while v do
+select 'yes' as 'v';
+end while;
+select 'done' as 'End';
+end|
+create procedure bug14498_3()
+begin
+declare continue handler for sqlexception select 'error' as 'Handler';
+repeat
+select 'maybe' as 'v';
+until v end repeat;
+select 'done' as 'End';
+end|
+create procedure bug14498_4()
+begin
+declare continue handler for sqlexception select 'error' as 'Handler';
+case v
+when 1 then
+select '1' as 'v';
+when 2 then
+select '2' as 'v';
+else
+select '?' as 'v';
+end case;
+select 'done' as 'End';
+end|
+create procedure bug14498_5()
+begin
+declare continue handler for sqlexception select 'error' as 'Handler';
+case
+when v = 1 then
+select '1' as 'v';
+when v = 2 then
+select '2' as 'v';
+else
+select '?' as 'v';
+end case;
+select 'done' as 'End';
+end|
+call bug14498_1()|
+Handler
+error
+End
+done
+call bug14498_2()|
+Handler
+error
+End
+done
+call bug14498_3()|
+v
+maybe
+Handler
+error
+End
+done
+call bug14498_5()|
+Handler
+error
+End
+done
+drop procedure bug14498_1|
+drop procedure bug14498_2|
+drop procedure bug14498_3|
+drop procedure bug14498_4|
+drop procedure bug14498_5|
+drop table if exists t3|
+drop procedure if exists bug15231_1|
+drop procedure if exists bug15231_2|
+drop procedure if exists bug15231_3|
+drop procedure if exists bug15231_4|
+create table t3 (id int not null)|
+create procedure bug15231_1()
+begin
+declare xid integer;
+declare xdone integer default 0;
+declare continue handler for not found set xdone = 1;
+set xid=null;
+call bug15231_2(xid);
+select xid, xdone;
+end|
+create procedure bug15231_2(inout ioid integer)
+begin
+select "Before NOT FOUND condition is triggered" as '1';
+select id into ioid from t3 where id=ioid;
+select "After NOT FOUND condtition is triggered" as '2';
+if ioid is null then
+set ioid=1;
+end if;
+end|
+create procedure bug15231_3()
+begin
+declare exit handler for sqlwarning
+select 'Caught it (wrong)' as 'Result';
+call bug15231_4();
+end|
+create procedure bug15231_4()
+begin
+declare x decimal(2,1);
+set x = 'zap';
+select 'Missed it (correct)' as 'Result';
+end|
+call bug15231_1()|
+1
+Before NOT FOUND condition is triggered
+2
+After NOT FOUND condtition is triggered
+xid xdone
+1 0
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+call bug15231_3()|
+Result
+Missed it (correct)
+Warnings:
+Warning 1366 Incorrect decimal value: 'zap' for column 'x' at row 1
+drop table if exists t3|
+drop procedure if exists bug15231_1|
+drop procedure if exists bug15231_2|
+drop procedure if exists bug15231_3|
+drop procedure if exists bug15231_4|
drop table t1,t2;
diff --git a/mysql-test/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 ff92fc543d4..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;
@@ -767,8 +767,7 @@ deallocate prepare stmt1;
drop procedure p1;
drop table t1, t2, t3;
create table t1 (a int);
-drop procedure if exists p2;
-CREATE PROCEDURE `p2`()
+CREATE PROCEDURE `p1`()
begin
insert into t1 values (1);
end//
@@ -777,6 +776,12 @@ begin
declare done int default 0;
set done= not done;
end//
-CALL p2();
-drop procedure p2;
+CALL p1();
+drop procedure p1;
drop table t1;
+create trigger t1_bi before insert on test.t1 for each row set @a:=0;
+ERROR 3D000: No database selected
+create trigger test.t1_bi before insert on t1 for each row set @a:=0;
+ERROR 3D000: No database selected
+drop trigger t1_bi;
+ERROR 3D000: No database selected
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index df180218a09..4f6a6569443 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -537,10 +537,10 @@ select @@query_prealloc_size = @test;
create table t1 (a int);
select a into @x from t1;
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
show warnings;
Level Code Message
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop table t1;
set @@warning_count=1;
ERROR HY000: Variable 'warning_count' is a read only variable
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index e4f2671eb34..8b6d0787ada 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -2423,6 +2423,9 @@ drop view v1;
drop table t1;
create table t1(f1 int, f2 int);
insert into t1 values (null, 10), (null,2);
+select f1, sum(f2) from t1 group by f1;
+f1 sum(f2)
+NULL 12
create view v1 as select * from t1;
select f1, sum(f2) from v1 group by f1;
f1 sum(f2)
@@ -2456,3 +2459,48 @@ f1()
42
drop view v2,v1;
drop function f1;
+create table t1 (id numeric, warehouse_id numeric);
+create view v1 as select id from t1;
+create view v2 as
+select t1.warehouse_id, v1.id as receipt_id
+from t1, v1 where t1.id = v1.id;
+insert into t1 (id, warehouse_id) values(3, 2);
+insert into t1 (id, warehouse_id) values(4, 2);
+insert into t1 (id, warehouse_id) values(5, 1);
+select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2
+order by v2.receipt_id;
+alias1 alias2
+3 3
+4 4
+5 5
+drop view v2, v1;
+drop table t1;
+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/r/view_grant.result b/mysql-test/r/view_grant.result
index e2ee02351d7..ede69343a29 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -348,12 +348,12 @@ select * from v1;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v2;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v3;
ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
select * from v4;
@@ -394,12 +394,12 @@ select * from v3;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v4;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v5;
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
drop view v1, v2, v3, v4, v5;
diff --git a/mysql-test/t/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/alter_table.test b/mysql-test/t/alter_table.test
index f4245abfe86..cfa6182543b 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -412,3 +412,13 @@ create table t1 (mycol int(10) not null);
alter table t1 alter column mycol set default 0;
desc t1;
drop table t1;
+
+#
+# Bug#6073 "ALTER table minor glich": ALTER TABLE complains that an index
+# without # prefix is not allowed for TEXT columns, while index
+# is defined with prefix.
+#
+create table t1 (t varchar(255) default null, key t (t(80)))
+engine=myisam default charset=latin1;
+alter table t1 change t t text;
+drop table t1;
diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test
index d3068b29e28..d017d91bfb1 100644
--- a/mysql-test/t/bdb.test
+++ b/mysql-test/t/bdb.test
@@ -1010,4 +1010,13 @@ create table t1 (a varchar(255) character set utf8,
e varchar(255) character set utf8,
key (a,b,c,d,e)) engine=bdb;
+#
+# Bug #14212: Server crash after COMMIT + ALTER TABLE
+#
+set autocommit=0;
+create table t1 (a int) engine=bdb;
+commit;
+alter table t1 add primary key(a);
+drop table t1;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 6f3bc67cb30..f7b9002faa0 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -211,13 +211,6 @@ drop table t1;
# bug #1434
#
-create table t1 select 1,2,3;
-create table if not exists t1 select 1,2;
---error 1136
-create table if not exists t1 select 1,2,3,4;
-create table if not exists t1 select 1;
-select * from t1;
-drop table t1;
create table t1 select 1,2,3;
create table if not exists t1 select 1,2;
--error 1136
@@ -511,6 +504,13 @@ CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) A
DESC t2;
DROP TABLE t1,t2;
+#
+# Bug#12913 Simple SQL can crash server or connection
+#
+CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1;
+SELECT * FROM t12913;
+DROP TABLE t12913;
+
#
# Bug#11028: Crash on create table like
#
@@ -571,6 +571,22 @@ create table t1 (
show create table t1;
drop table t1;
+--warning 1364
+create table t1 (
+ a varchar(12) charset utf8 collate utf8_bin not null,
+ b int not null, primary key (a)
+) select a, 1 as c from t2 ;
+show create table t1;
+drop table t1;
+
+--warning 1364
+create table t1 (
+ a varchar(12) charset utf8 collate utf8_bin not null,
+ b int null, primary key (a)
+) select a, 1 as c from t2 ;
+show create table t1;
+drop table t1;
+
--warning 1364
create table t1 (
a varchar(12) charset utf8 collate utf8_bin not null,
diff --git a/mysql-test/t/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_uca.test b/mysql-test/t/ctype_uca.test
index 6d8713f4910..3e49b9de883 100644
--- a/mysql-test/t/ctype_uca.test
+++ b/mysql-test/t/ctype_uca.test
@@ -212,6 +212,7 @@ select group_concat(c1 order by c1) from t1 group by c1 collate utf8_slovak_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_spanish2_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_roman_ci;
select group_concat(c1 order by c1) from t1 group by c1 collate utf8_esperanto_ci;
+select group_concat(c1 order by c1) from t1 group by c1 collate utf8_hungarian_ci;
drop table t1;
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 626c7e0e1b6..04de13f8228 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -421,6 +421,14 @@ insert into t1 values (0x005b);
select hex(a) from t1;
drop table t1;
+#
+# Bug #14583 Bug on query using a LIKE on indexed field with ucs2_bin collation
+#
+create table t1(f1 varchar(5) CHARACTER SET ucs2 COLLATE ucs2_bin NOT NULL) engine=InnoDB;
+insert into t1 values('a');
+create index t1f1 on t1(f1);
+select f1 from t1 where f1 like 'a%';
+drop table t1;
# End of 4.1 tests
#
diff --git a/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 4722fac435c..46f15983dc3 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -11,5 +11,4 @@
##############################################################################
sp-goto : GOTO is currently is disabled - will be fixed in the future
-kill : Unstable test case, bug#9712
subselect : Bug#15706
diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test
index de2576300dc..19a47b2893a 100644
--- a/mysql-test/t/flush_read_lock_kill.test
+++ b/mysql-test/t/flush_read_lock_kill.test
@@ -42,7 +42,7 @@ connection con1;
# debug build running without our --debug=make_global..., will be
# error 0 (no error). The only important thing to test is that on
# debug builds with our --debug=make_global... we don't hang forever.
---error 0,1053
+--error 0,1053,2013
reap;
connection con2;
diff --git a/mysql-test/t/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/fulltext2.test b/mysql-test/t/fulltext2.test
index bcd39b9ea04..7a7b572d58f 100644
--- a/mysql-test/t/fulltext2.test
+++ b/mysql-test/t/fulltext2.test
@@ -179,7 +179,37 @@ update t1 set a='aaaxxx' where a = 'aaayyy';
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
-
drop table t1;
+#
+# BUG#11336
+#
+# for uca collation isalnum and strnncollsp don't agree on whether
+# 0xC2A0 is a space (strnncollsp is right, isalnum is wrong).
+#
+# they still don't, the bug was fixed by avoiding strnncollsp
+#
+
+set names utf8;
+create table t1(a text,fulltext(a)) collate=utf8_swedish_ci;
+insert into t1 values('test test '),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test'),
+('test'),('test'),('test'),('test'),('test'),('test'),('test'),('test');
+delete from t1 limit 1;
+drop table t1;
+set names latin1;
+
# End of 4.1 tests
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
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/grant2.test b/mysql-test/t/grant2.test
index 2fa82ce5dce..c19bb1482d6 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -155,6 +155,38 @@ flush privileges;
drop database mysqltest;
use test;
+
+#
+# Bug #15775: "drop user" command does not refresh acl_check_hosts
+#
+
+# Create some test users
+create user mysqltest_1@host1;
+create user mysqltest_2@host2;
+create user mysqltest_3@host3;
+create user mysqltest_4@host4;
+create user mysqltest_5@host5;
+create user mysqltest_6@host6;
+create user mysqltest_7@host7;
+flush privileges;
+
+# Drop one user
+drop user mysqltest_3@host3;
+
+# This connect failed before fix since the acl_check_hosts list was corrupted by the "drop user"
+connect (con8,127.0.0.1,root,,test,$MASTER_MYPORT,);
+disconnect con8;
+connection default;
+
+# Clean up - Drop all of the remaining users at once
+drop user mysqltest_1@host1, mysqltest_2@host2, mysqltest_4@host4,
+ mysqltest_5@host5, mysqltest_6@host6, mysqltest_7@host7;
+
+# Check that it's still possible to connect
+connect (con9,127.0.0.1,root,,test,$MASTER_MYPORT,);
+disconnect con9;
+connection default;
+
#
# Create and drop user
#
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/handler.test b/mysql-test/t/handler.test
index f3e14c3cd2b..3fb09df5f2f 100644
--- a/mysql-test/t/handler.test
+++ b/mysql-test/t/handler.test
@@ -3,7 +3,7 @@
#
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t3,t4,t5;
--enable_warnings
create table t1 (a int, b char(10), key a(a), key b(a,b));
diff --git a/mysql-test/t/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/information_schema.test b/mysql-test/t/information_schema.test
index acbc62f1364..f835a7148a2 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -748,3 +748,45 @@ drop table t1;
select table_type from information_schema.tables
where table_name="v1";
drop view v1;
+
+#
+# Bug #14387 SHOW COLUMNS doesn't work on temporary tables
+# Bug #15224 SHOW INDEX from temporary table doesn't work
+# Bug #12770 DESC cannot display the info. about temporary table
+#
+create temporary table t1(f1 int, index(f1));
+show columns from t1;
+describe t1;
+show indexes from t1;
+drop table t1;
+
+#
+# Bug#14271 I_S: columns has no size for (var)binary columns
+#
+create table t1(f1 binary(32), f2 varbinary(64));
+select character_maximum_length, character_octet_length
+from information_schema.columns where table_name='t1';
+drop table t1;
+
+#
+# Bug#15533 crash, information_schema, function, view
+#
+CREATE TABLE t1 (f1 BIGINT, f2 VARCHAR(20), f3 BIGINT);
+INSERT INTO t1 SET f1 = 1, f2 = 'Schoenenbourg', f3 = 1;
+
+CREATE FUNCTION func2() RETURNS BIGINT RETURN 1;
+
+delimiter //;
+CREATE FUNCTION func1() RETURNS BIGINT
+BEGIN
+ RETURN ( SELECT COUNT(*) FROM INFORMATION_SCHEMA.VIEWS);
+END//
+delimiter ;//
+
+CREATE VIEW v1 AS SELECT 1 FROM t1
+ WHERE f3 = (SELECT func2 ());
+SELECT func1();
+DROP TABLE t1;
+DROP VIEW v1;
+DROP FUNCTION func1;
+DROP FUNCTION func2;
diff --git a/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/innodb.test b/mysql-test/t/innodb.test
index 887d8193157..7ae2b6d4ac2 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1679,6 +1679,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+select a,hex(b),hex(c),filler from t2 order by filler;
drop table t1;
drop table t2;
@@ -1708,6 +1712,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+select a,hex(b),hex(c),filler from t2 order by filler;
drop table t1;
drop table t2;
@@ -1737,6 +1745,10 @@ insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05630563,_ucs2 0x05630563,'eleven');
insert into t2 values (4,_ucs2 0x0563001fc0563,_ucs2 0x0563001fc0563,'point');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+select a,hex(b),hex(c),filler from t2 order by filler;
drop table t1;
drop table t2;
@@ -1762,6 +1774,10 @@ insert into t2 values (4,_ucs2 0x01fc,_ucs2 0x01fc,'seven');
insert into t2 values (4,_ucs2 0x0120,_ucs2 0x0120,'eight');
insert into t2 values (4,_ucs2 0x0563,_ucs2 0x0563,'ten');
insert into t2 values (4,_ucs2 0x05612020,_ucs2 0x05612020,'taken');
+update t1 set filler = 'boo' where a = 1;
+update t2 set filler ='email' where a = 4;
+select a,hex(b),hex(c),filler from t1 order by filler;
+select a,hex(b),hex(c),filler from t2 order by filler;
drop table t1;
drop table t2;
commit;
@@ -1816,23 +1832,6 @@ rename table t3 to t1;
set foreign_key_checks=1;
drop table t2,t3;
-#
-# Test that we can create a large (>1K) key
-#
-create table t1 (a varchar(255) character set utf8,
- b varchar(255) character set utf8,
- c varchar(255) character set utf8,
- d varchar(255) character set utf8,
- key (a,b,c,d)) engine=innodb;
-drop table t1;
---error ER_TOO_LONG_KEY
-create table t1 (a varchar(255) character set utf8,
- b varchar(255) character set utf8,
- c varchar(255) character set utf8,
- d varchar(255) character set utf8,
- e varchar(255) character set utf8,
- key (a,b,c,d,e)) engine=innodb;
-
# test that foreign key errors are reported correctly (Bug #15550)
create table t1(a int primary key) row_format=redundant engine=innodb;
@@ -1867,4 +1866,184 @@ truncate t3;
drop table t4,t3,t2,t1;
---echo End of 5.0 tests
+
+#
+# Test that we can create a large (>1K) key
+#
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ key (a,b,c,d)) engine=innodb;
+drop table t1;
+--error ER_TOO_LONG_KEY
+create table t1 (a varchar(255) character set utf8,
+ b varchar(255) character set utf8,
+ c varchar(255) character set utf8,
+ d varchar(255) character set utf8,
+ e varchar(255) character set utf8,
+ key (a,b,c,d,e)) engine=innodb;
+
+
+# test the padding of BINARY types and collations (Bug #14189)
+
+create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb;
+create table t2 (s1 binary(2),primary key (s1)) engine=innodb;
+create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb;
+create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb;
+
+insert into t1 values (0x41),(0x4120),(0x4100);
+-- error 1062
+insert into t2 values (0x41),(0x4120),(0x4100);
+insert into t2 values (0x41),(0x4120);
+-- error 1062
+insert into t3 values (0x41),(0x4120),(0x4100);
+insert into t3 values (0x41),(0x4100);
+-- error 1062
+insert into t4 values (0x41),(0x4120),(0x4100);
+insert into t4 values (0x41),(0x4100);
+select hex(s1) from t1;
+select hex(s1) from t2;
+select hex(s1) from t3;
+select hex(s1) from t4;
+drop table t1,t2,t3,t4;
+
+create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb;
+create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
+
+insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42);
+-- error 1452
+insert into t2 values(0x42);
+insert into t2 values(0x41);
+select hex(s1) from t2;
+update t1 set s1=0x123456 where a=2;
+select hex(s1) from t2;
+-- error 1451
+update t1 set s1=0x12 where a=1;
+-- error 1451
+update t1 set s1=0x12345678 where a=1;
+-- error 1451
+update t1 set s1=0x123457 where a=1;
+update t1 set s1=0x1220 where a=1;
+select hex(s1) from t2;
+update t1 set s1=0x1200 where a=1;
+select hex(s1) from t2;
+update t1 set s1=0x4200 where a=1;
+select hex(s1) from t2;
+-- error 1451
+delete from t1 where a=1;
+delete from t1 where a=2;
+update t2 set s1=0x4120;
+-- error 1451
+delete from t1;
+delete from t1 where a!=3;
+select a,hex(s1) from t1;
+select hex(s1) from t2;
+
+drop table t2,t1;
+
+create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb;
+create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
+
+insert into t1 values(1,0x4100),(2,0x41);
+insert into t2 values(0x41);
+select hex(s1) from t2;
+update t1 set s1=0x1234 where a=1;
+select hex(s1) from t2;
+update t1 set s1=0x12 where a=2;
+select hex(s1) from t2;
+delete from t1 where a=1;
+-- error 1451
+delete from t1 where a=2;
+select a,hex(s1) from t1;
+select hex(s1) from t2;
+
+drop table t2,t1;
+#
+# Test cases for bug #15308 Problem of Order with Enum Column in Primary Key
+#
+CREATE TABLE t1 (
+ ind enum('0','1','2') NOT NULL default '0',
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ ind enum('0','1','2') NOT NULL default '0',
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+
+INSERT INTO t1 VALUES ('1', ''),('2', '');
+INSERT INTO t2 VALUES ('1', ''),('2', '');
+SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1;
+SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1;
+drop table t1,t2;
+
+CREATE TABLE t1 (
+ ind set('0','1','2') NOT NULL default '0',
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ ind set('0','1','2') NOT NULL default '0',
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+
+INSERT INTO t1 VALUES ('1', ''),('2', '');
+INSERT INTO t2 VALUES ('1', ''),('2', '');
+SELECT hex(ind),hex(string1) FROM t1 ORDER BY string1;
+SELECT hex(ind),hex(string1) FROM t2 ORDER BY string1;
+drop table t1,t2;
+
+CREATE TABLE t1 (
+ ind bit not null,
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE t2 (
+ ind bit not null,
+ string1 varchar(250) NOT NULL,
+ PRIMARY KEY (ind)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2;
+insert into t1 values(0,''),(1,'');
+insert into t2 values(0,''),(1,'');
+select hex(ind),hex(string1) from t1 order by string1;
+select hex(ind),hex(string1) from t2 order by string1;
+drop table t1,t2;
+
+# tests for bug #14056 Column prefix index on UTF-8 primary key column causes 'Can't find record..'
+
+create table t2 (
+ a int, b char(10), filler char(10), primary key(a, b(2))
+) character set utf8 engine = innodb;
+
+insert into t2 values (1,'abcdefg','one');
+insert into t2 values (2,'ijkilmn','two');
+insert into t2 values (3, 'qrstuvw','three');
+update t2 set a=5, filler='booo' where a=1;
+drop table t2;
+create table t2 (
+ a int, b char(10), filler char(10), primary key(a, b(2))
+) character set ucs2 engine = innodb;
+
+insert into t2 values (1,'abcdefg','one');
+insert into t2 values (2,'ijkilmn','two');
+insert into t2 values (3, 'qrstuvw','three');
+update t2 set a=5, filler='booo' where a=1;
+drop table t2;
+
+create table t1(a int not null, b char(110),primary key(a,b(100))) engine=innodb default charset=utf8;
+insert into t1 values(1,'abcdefg'),(2,'defghijk');
+insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1);
+insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2);
+select a,hex(b) from t1 order by b;
+update t1 set b = 'three' where a = 6;
+drop table t1;
+create table t1(a int not null, b text(110),primary key(a,b(100))) engine=innodb default charset=utf8;
+insert into t1 values(1,'abcdefg'),(2,'defghijk');
+insert into t1 values(6,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1);
+insert into t1 values(7,_utf8 0xD0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B1D0B2);
+select a,hex(b) from t1 order by b;
+update t1 set b = 'three' where a = 6;
+drop table t1;
diff --git a/mysql-test/t/innodb_unsafe_binlog-master.opt b/mysql-test/t/innodb_unsafe_binlog-master.opt
new file mode 100644
index 00000000000..503c8457b2c
--- /dev/null
+++ b/mysql-test/t/innodb_unsafe_binlog-master.opt
@@ -0,0 +1 @@
+--innodb_locks_unsafe_for_binlog=true
diff --git a/mysql-test/t/innodb_unsafe_binlog.test b/mysql-test/t/innodb_unsafe_binlog.test
new file mode 100644
index 00000000000..fa240eb7608
--- /dev/null
+++ b/mysql-test/t/innodb_unsafe_binlog.test
@@ -0,0 +1,67 @@
+-- source include/have_innodb.inc
+#
+# Note that these tests uses a innodb_locks_unsafe_for_binlog option.
+#
+# Test cases for a bug #15650 DELETE with LEFT JOIN crashes server
+#
+
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(f_id, id)) engine=innodb;
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id)) engine=innodb;
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+commit;
+DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
+WHERE mm.id IS NULL;
+select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id)
+where mm.id is null lock in share mode;
+drop table t1,t2;
+
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(id),key(f_id)) engine=innodb;
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id),key(s_id)) engine=innodb;
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+commit;
+delete ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null;
+select ml.* from t1 as ml left join t2 as mm on (mm.s_id=ml.f_id) where mm.s is null lock in share mode;
+drop table t1,t2;
+
+#
+# Test case for unlock row bug where unlock releases all locks granted for
+# a row. Only the latest lock should be released.
+#
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+connection a;
+create table t1(a int not null, b int, primary key(a)) engine=innodb;
+insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2);
+commit;
+set autocommit = 0;
+select * from t1 lock in share mode;
+update t1 set b = 5 where b = 1;
+connection b;
+set autocommit = 0;
+#
+# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update
+#
+--error 1205
+select * from t1 where a = 2 and b = 2 for update;
+connection a;
+commit;
+connection b;
+commit;
+drop table t1;
+disconnect a;
+disconnect b;
+
diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test
index 9f23e2d0e2f..145edded486 100644
--- a/mysql-test/t/join_nested.test
+++ b/mysql-test/t/join_nested.test
@@ -900,3 +900,17 @@ explain select * from t2 left join
join t5 on t5.a=t3.b) on t3.a=t2.b;
drop table t0, t1, t2, t3, t4, t5, t6, t7;
+
+# BUG#16393
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 (a int, filler char(100), key(a));
+insert into t2 select A.a + 10*B.a, '' from t1 A, t1 B;
+create table t3 like t2;
+insert into t3 select * from t2;
+
+explain select * from t1 left join
+ (t2 left join t3 on (t2.a = t3.a))
+ on (t1.a = t2.a);
+drop table t1, t2, t3;
+
diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test
index 7f3a9932d31..c50c35825fc 100644
--- a/mysql-test/t/kill.test
+++ b/mysql-test/t/kill.test
@@ -25,11 +25,18 @@ select ((@id := kill_id) - kill_id) from t1;
kill @id;
connection con1;
---sleep 1
+--sleep 2
-# this statement should fail
---error 2006,2013
+--disable_query_log
+--disable_result_log
+# One of the following statements should fail
+--error 0,2006,2013
select 1;
+--error 0,2006,2013
+select 1;
+--enable_query_log
+--enable_result_log
+
--enable_reconnect
# this should work, and we should have a new connection_id()
select ((@id := kill_id) - kill_id) from t1;
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index ff05867b7c1..060f1ea167b 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -352,4 +352,30 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3;
SELECT b FROM t2;
DROP TABLE t1, t2;
+
+#
+# BUG#5390 - problems with merge tables
+# Problem #1: INSERT...SELECT
+#
+#drop table if exists t1, t2, t3;
+create table t1(a int);
+create table t2(a int);
+insert into t1 values (1);
+insert into t2 values (2);
+create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
+select * from t3;
+#
+insert t2 select * from t2;
+select * from t2;
+#
+insert t3 select * from t1;
+select * from t3;
+#
+insert t1 select * from t3;
+select * from t1;
+select * from t2;
+select * from t3;
+check table t1, t2;
+drop table t1, t2, t3;
+
# End of 4.1 tests
diff --git a/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/mysqlshow.test b/mysql-test/t/mysqlshow.test
index 1e2e97a4e07..78c4ae2b531 100644
--- a/mysql-test/t/mysqlshow.test
+++ b/mysql-test/t/mysqlshow.test
@@ -2,7 +2,7 @@
-- source include/not_embedded.inc
--disable_warnings
-DROP TABLE IF EXISTS t1,t2;
+DROP TABLE IF EXISTS t1,t2,test1,test2;
--enable_warnings
#
diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test
index 440a7787985..e6dc4d356c2 100644
--- a/mysql-test/t/mysqltest.test
+++ b/mysql-test/t/mysqltest.test
@@ -364,6 +364,15 @@ select 3 from t1 ;
--error 1
--exec $MYSQL_TEST < var/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
#
@@ -530,6 +539,42 @@ echo $novar1;
--error 1
--exec echo "let hi;" | $MYSQL_TEST 2>&1
+# ----------------------------------------------------------------------------
+# Test to assign let from query
+# let $=``;
+# ----------------------------------------------------------------------------
+--disable_parsing
+echo var1;
+let $var1= `select "hi" as "Col", 1 as "Column1", "hi there" as Col3`;
+echo $var1;
+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
@@ -865,7 +910,13 @@ select "a" as col1, "c" as col2;
--error 1
--exec echo "source var/tmp/con.sql;" | $MYSQL_TEST 2>&1
-
+# connect when "disable_abort_on_error" caused "connection not found"
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--disable_abort_on_error
+connect (con1,localhost,root,,);
+connection default;
+connection con1;
+--enable_abort_on_error
# ----------------------------------------------------------------------------
# Test mysqltest arguments
@@ -946,13 +997,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 +1041,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 +1059,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/ps.test b/mysql-test/t/ps.test
index 22d0abf645e..645538ee890 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -870,6 +870,36 @@ drop table t1;
set names default;
deallocate prepare stmt;
+#
+# A test case for Bug#12734 "prepared statement may return incorrect result
+# set for a select SQL request": test that canDoTurboBM is reset for each
+# execute of a prepared statement.
+#
+create table t1 (
+ word_id mediumint(8) unsigned not null default '0',
+ formatted varchar(20) not null default ''
+);
+
+insert into t1 values
+ (80,'pendant'), (475,'pretendants'), (989,'tendances'),
+ (1019,'cependant'),(1022,'abondance'),(1205,'independants'),
+ (13,'lessiver'),(25,'lambiner'),(46,'situer'),(71,'terminer'),
+ (82,'decrocher');
+
+select count(*) from t1 where formatted like '%NDAN%';
+select count(*) from t1 where formatted like '%ER';
+prepare stmt from "select count(*) from t1 where formatted like ?";
+set @like="%NDAN%";
+execute stmt using @like;
+set @like="%ER";
+execute stmt using @like;
+set @like="%NDAN%";
+execute stmt using @like;
+set @like="%ER";
+execute stmt using @like;
+deallocate prepare stmt;
+drop table t1;
+
# End of 4.1 tests
#
diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test
index 3d03823d474..45d621b730f 100644
--- a/mysql-test/t/rpl000001.test
+++ b/mysql-test/t/rpl000001.test
@@ -92,7 +92,7 @@ kill @id;
# We don't drop t3 as this is a temporary table
drop table t2;
connection master;
---error 1053
+--error 1053,2013
reap;
connection slave;
# The SQL slave thread should now have stopped because the query was killed on
diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test
index cb4137c49e0..339d966dbb3 100644
--- a/mysql-test/t/rpl_error_ignored_table.test
+++ b/mysql-test/t/rpl_error_ignored_table.test
@@ -45,7 +45,7 @@ select (@id := id) - id from t3;
kill @id;
drop table t2,t3;
connection master;
---error 0,1053
+--error 0,1053,2013
reap;
connection master1;
--replace_column 2 # 5 #
diff --git a/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/rpl_sp.test b/mysql-test/t/rpl_sp.test
index 386582f8f1b..8fa330584e2 100644
--- a/mysql-test/t/rpl_sp.test
+++ b/mysql-test/t/rpl_sp.test
@@ -87,6 +87,14 @@ grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1;
grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1;
grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1;
+# ToDo: BUG#14931: There is a race between the last grant binlogging, and
+# the binlogging in the new connection made below, causing sporadic test
+# failures due to switched statement order in binlog. To fix this we do
+# SELECT 1 in the first connection before starting the second, ensuring
+# that binlogging is done in the expected order.
+# Please remove this SELECT 1 when BUG#14931 is fixed.
+SELECT 1;
+
connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,);
connection con1;
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
@@ -2806,6 +2806,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
#
@@ -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..68ce9cdb118 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
@@ -3748,7 +3824,7 @@ drop procedure if exists bug7088_2|
--disable_parsing # temporarily disabled until Bar fixes BUG#11986
create procedure bug6063()
- lâbel: begin end|
+ lâbel: begin end|
call bug6063()|
# QQ Known bug: this will not show the label correctly.
show create procedure bug6063|
@@ -4288,8 +4364,6 @@ drop procedure if exists bug7049_1|
drop procedure if exists bug7049_2|
drop procedure if exists bug7049_3|
drop procedure if exists bug7049_4|
-drop procedure if exists bug7049_5|
-drop procedure if exists bug7049_6|
drop function if exists bug7049_1|
drop function if exists bug7049_2|
--enable_warnings
@@ -4323,22 +4397,6 @@ begin
select 'Missed it' as 'Result';
end|
-create procedure bug7049_5()
-begin
- declare x decimal(2,1);
-
- set x = 'zap';
-end|
-
-create procedure bug7049_6()
-begin
- declare exit handler for sqlwarning
- select 'Caught it' as 'Result';
-
- call bug7049_5();
- select 'Missed it' as 'Result';
-end|
-
create function bug7049_1()
returns int
begin
@@ -4363,7 +4421,6 @@ select * from t3|
delete from t3|
call bug7049_4()|
select * from t3|
-call bug7049_6()|
select bug7049_2()|
drop table t3|
@@ -4371,8 +4428,6 @@ drop procedure bug7049_1|
drop procedure bug7049_2|
drop procedure bug7049_3|
drop procedure bug7049_4|
-drop procedure bug7049_5|
-drop procedure bug7049_6|
drop function bug7049_1|
drop function bug7049_2|
@@ -5078,6 +5133,155 @@ call bug15441('Yale')|
drop table t3|
drop procedure bug15441|
+#
+# BUG#14498: Stored procedures: hang if undefined variable and exception
+#
+--disable_warnings
+drop procedure if exists bug14498_1|
+drop procedure if exists bug14498_2|
+drop procedure if exists bug14498_3|
+drop procedure if exists bug14498_4|
+drop procedure if exists bug14498_5|
+--enable_warnings
+
+create procedure bug14498_1()
+begin
+ declare continue handler for sqlexception select 'error' as 'Handler';
+
+ if v then
+ select 'yes' as 'v';
+ else
+ select 'no' as 'v';
+ end if;
+ select 'done' as 'End';
+end|
+
+create procedure bug14498_2()
+begin
+ declare continue handler for sqlexception select 'error' as 'Handler';
+
+ while v do
+ select 'yes' as 'v';
+ end while;
+ select 'done' as 'End';
+end|
+
+create procedure bug14498_3()
+begin
+ declare continue handler for sqlexception select 'error' as 'Handler';
+
+ repeat
+ select 'maybe' as 'v';
+ until v end repeat;
+ select 'done' as 'End';
+end|
+
+create procedure bug14498_4()
+begin
+ declare continue handler for sqlexception select 'error' as 'Handler';
+
+ case v
+ when 1 then
+ select '1' as 'v';
+ when 2 then
+ select '2' as 'v';
+ else
+ select '?' as 'v';
+ end case;
+ select 'done' as 'End';
+end|
+
+create procedure bug14498_5()
+begin
+ declare continue handler for sqlexception select 'error' as 'Handler';
+
+ case
+ when v = 1 then
+ select '1' as 'v';
+ when v = 2 then
+ select '2' as 'v';
+ else
+ select '?' as 'v';
+ end case;
+ select 'done' as 'End';
+end|
+
+call bug14498_1()|
+call bug14498_2()|
+call bug14498_3()|
+# We couldn't call this before, due to a known bug (BUG#14643)
+# QQ We still can't since the new set_case_expr instruction breaks
+# the semantics of case; it won't crash, but will get the wrong result.
+#call bug14498_4()|
+call bug14498_5()|
+
+drop procedure bug14498_1|
+drop procedure bug14498_2|
+drop procedure bug14498_3|
+drop procedure bug14498_4|
+drop procedure bug14498_5|
+
+#
+# BUG#15231: Stored procedure bug with not found condition handler
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug15231_1|
+drop procedure if exists bug15231_2|
+drop procedure if exists bug15231_3|
+drop procedure if exists bug15231_4|
+--enable_warnings
+
+create table t3 (id int not null)|
+
+create procedure bug15231_1()
+begin
+ declare xid integer;
+ declare xdone integer default 0;
+ declare continue handler for not found set xdone = 1;
+
+ set xid=null;
+ call bug15231_2(xid);
+ select xid, xdone;
+end|
+
+create procedure bug15231_2(inout ioid integer)
+begin
+ select "Before NOT FOUND condition is triggered" as '1';
+ select id into ioid from t3 where id=ioid;
+ select "After NOT FOUND condtition is triggered" as '2';
+
+ if ioid is null then
+ set ioid=1;
+ end if;
+end|
+
+create procedure bug15231_3()
+begin
+ declare exit handler for sqlwarning
+ select 'Caught it (wrong)' as 'Result';
+
+ call bug15231_4();
+end|
+
+create procedure bug15231_4()
+begin
+ declare x decimal(2,1);
+
+ set x = 'zap';
+ select 'Missed it (correct)' as 'Result';
+end|
+
+call bug15231_1()|
+call bug15231_3()|
+
+drop table if exists t3|
+drop procedure if exists bug15231_1|
+drop procedure if exists bug15231_2|
+drop procedure if exists bug15231_3|
+drop procedure if exists bug15231_4|
+
+
#
# BUG#NNNN: New bug synopsis
#
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index d4fa5268762..f2d9bb6c856 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -13,6 +13,8 @@ drop procedure if exists p1;
# Create additional connections used through test
connect (addconroot1, localhost, root,,);
connect (addconroot2, localhost, root,,);
+# Connection without current database set
+connect (addconwithoutdb, localhost, root,,*NO-ONE*);
connection default;
create table t1 (i int);
@@ -928,11 +930,8 @@ drop table t1, t2, t3;
# operator.
#
create table t1 (a int);
---disable_warnings
-drop procedure if exists p2;
---enable_warnings
DELIMITER //;
-CREATE PROCEDURE `p2`()
+CREATE PROCEDURE `p1`()
begin
insert into t1 values (1);
end//
@@ -942,7 +941,20 @@ begin
set done= not done;
end//
DELIMITER ;//
-CALL p2();
-drop procedure p2;
+CALL p1();
+drop procedure p1;
drop table t1;
+#
+# Test for bug #14863 "Triggers: crash if create and there is no current
+# database". We should not crash and give proper error when database for
+# trigger or its table is not specified and there is no current database.
+#
+connection addconwithoutdb;
+--error ER_NO_DB_ERROR
+create trigger t1_bi before insert on test.t1 for each row set @a:=0;
+--error ER_NO_DB_ERROR
+create trigger test.t1_bi before insert on t1 for each row set @a:=0;
+--error ER_NO_DB_ERROR
+drop trigger t1_bi;
+connection default;
diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test
index 1f6310cb819..07347322453 100644
--- a/mysql-test/t/type_decimal.test
+++ b/mysql-test/t/type_decimal.test
@@ -376,3 +376,4 @@ insert INTO t2 SELECT * FROM t1;
select * from t2;
drop table t1, t2;
+
diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test
index 7ae3f65f7cc..cb7e4f85ad1 100644
--- a/mysql-test/t/type_time.test
+++ b/mysql-test/t/type_time.test
@@ -21,4 +21,22 @@ select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1;
select sec_to_time(time_to_sec(t)) from t1;
drop table t1;
+#
+# BUG #12440: Incorrect processing of time values containing
+# long fraction part and/or large exponent part.
+#
+# These must return normal result:
+# ##########################################################
+# 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);
+# This must return NULL and produce warning:
+# 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 6d2afb908a4..5f3678215f2 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2275,6 +2275,7 @@ drop table t1;
#
create table t1(f1 int, f2 int);
insert into t1 values (null, 10), (null,2);
+select f1, sum(f2) from t1 group by f1;
create view v1 as select * from t1;
select f1, sum(f2) from v1 group by f1;
drop view v1;
@@ -2319,3 +2320,46 @@ CREATE VIEW v2 AS SELECT f1();
select * from v2;
drop view v2,v1;
drop function f1;
+
+#
+# Bug#14861: aliased column names are not preserved.
+#
+create table t1 (id numeric, warehouse_id numeric);
+create view v1 as select id from t1;
+create view v2 as
+select t1.warehouse_id, v1.id as receipt_id
+from t1, v1 where t1.id = v1.id;
+
+insert into t1 (id, warehouse_id) values(3, 2);
+insert into t1 (id, warehouse_id) values(4, 2);
+insert into t1 (id, warehouse_id) values(5, 1);
+
+select v2.receipt_id as alias1, v2.receipt_id as alias2 from v2
+order by v2.receipt_id;
+
+drop view v2, v1;
+drop table t1;
+
+#
+# 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/charset-def.c b/mysys/charset-def.c
index 5b30d1ee135..0559fe59d06 100644
--- a/mysys/charset-def.c
+++ b/mysys/charset-def.c
@@ -43,6 +43,7 @@ extern CHARSET_INFO my_charset_ucs2_spanish2_uca_ci;
extern CHARSET_INFO my_charset_ucs2_roman_uca_ci;
extern CHARSET_INFO my_charset_ucs2_persian_uca_ci;
extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci;
+extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci;
#endif
#ifdef HAVE_CHARSET_utf8
@@ -64,6 +65,7 @@ extern CHARSET_INFO my_charset_utf8_spanish2_uca_ci;
extern CHARSET_INFO my_charset_utf8_roman_uca_ci;
extern CHARSET_INFO my_charset_utf8_persian_uca_ci;
extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci;
+extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci;
#ifdef HAVE_UTF8_GENERAL_CS
extern CHARSET_INFO my_charset_utf8_general_cs;
#endif
@@ -151,6 +153,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_ucs2_roman_uca_ci);
add_compiled_collation(&my_charset_ucs2_persian_uca_ci);
add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci);
+ add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci);
#endif
#endif
@@ -184,6 +187,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf8_roman_uca_ci);
add_compiled_collation(&my_charset_utf8_persian_uca_ci);
add_compiled_collation(&my_charset_utf8_esperanto_uca_ci);
+ add_compiled_collation(&my_charset_utf8_hungarian_uca_ci);
#endif
#endif
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index de03d783c68..0f58b8a930c 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -197,7 +197,7 @@ int modify_defaults_file(const char *file_location, const char *option,
goto err;
}
if (my_fclose(cnf_file, MYF(MY_WME)))
- goto err;
+ DBUG_RETURN(1);
my_free(file_buffer, MYF(0));
DBUG_RETURN(0);
diff --git a/mysys/hash.c b/mysys/hash.c
index 45cf7d5ff1d..99479ef6769 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -36,9 +36,10 @@ typedef struct st_hash_info {
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
-static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
+ uint length);
-static uint calc_hash(HASH *hash,const byte *key,uint length)
+static uint calc_hash(const HASH *hash, const byte *key, uint length)
{
ulong nr1=1, nr2=4;
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
@@ -63,7 +64,6 @@ _hash_init(HASH *hash,CHARSET_INFO *charset,
hash->key_offset=key_offset;
hash->key_length=key_length;
hash->blength=1;
- hash->current_record= NO_RECORD; /* For the future */
hash->get_key=get_key;
hash->free=free_element;
hash->flags=flags;
@@ -135,7 +135,6 @@ void my_hash_reset(HASH *hash)
reset_dynamic(&hash->array);
/* Set row pointers so that the hash can be reused at once */
hash->blength= 1;
- hash->current_record= NO_RECORD;
DBUG_VOID_RETURN;
}
@@ -147,7 +146,8 @@ void my_hash_reset(HASH *hash)
*/
static inline char*
-hash_key(HASH *hash,const byte *record,uint *length,my_bool first)
+hash_key(const HASH *hash, const byte *record, uint *length,
+ my_bool first)
{
if (hash->get_key)
return (*hash->get_key)(record,length,first);
@@ -163,8 +163,8 @@ static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
return (hashnr & ((buffmax >> 1) -1));
}
-static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
- uint maxlength)
+static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos,
+ uint buffmax, uint maxlength)
{
uint length;
byte *key= (byte*) hash_key(hash,pos->data,&length,0);
@@ -186,14 +186,25 @@ unsigned int rec_hashnr(HASH *hash,const byte *record)
}
- /* Search after a record based on a key */
- /* Sets info->current_ptr to found record */
+gptr hash_search(const HASH *hash, const byte *key, uint length)
+{
+ HASH_SEARCH_STATE state;
+ return hash_first(hash, key, length, &state);
+}
-gptr hash_search(HASH *hash,const byte *key,uint length)
+/*
+ Search after a record based on a key
+
+ NOTE
+ Assigns the number of the found record to HASH_SEARCH_STATE state
+*/
+
+gptr hash_first(const HASH *hash, const byte *key, uint length,
+ HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
uint flag,idx;
- DBUG_ENTER("hash_search");
+ DBUG_ENTER("hash_first");
flag=1;
if (hash->records)
@@ -206,7 +217,7 @@ gptr hash_search(HASH *hash,const byte *key,uint length)
if (!hashcmp(hash,pos,key,length))
{
DBUG_PRINT("exit",("found key at %d",idx));
- hash->current_record= idx;
+ *current_record= idx;
DBUG_RETURN (pos->data);
}
if (flag)
@@ -218,31 +229,32 @@ gptr hash_search(HASH *hash,const byte *key,uint length)
}
while ((idx=pos->next) != NO_RECORD);
}
- hash->current_record= NO_RECORD;
+ *current_record= NO_RECORD;
DBUG_RETURN(0);
}
/* Get next record with identical key */
/* Can only be called if previous calls was hash_search */
-gptr hash_next(HASH *hash,const byte *key,uint length)
+gptr hash_next(const HASH *hash, const byte *key, uint length,
+ HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
uint idx;
- if (hash->current_record != NO_RECORD)
+ if (*current_record != NO_RECORD)
{
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
- for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
+ for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next)
{
pos=data+idx;
if (!hashcmp(hash,pos,key,length))
{
- hash->current_record= idx;
+ *current_record= idx;
return pos->data;
}
}
- hash->current_record=NO_RECORD;
+ *current_record= NO_RECORD;
}
return 0;
}
@@ -281,7 +293,8 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
!= 0 key of record != key
*/
-static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
+ uint length)
{
uint rec_keylength;
byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1);
@@ -307,7 +320,6 @@ my_bool my_hash_insert(HASH *info,const byte *record)
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
return(TRUE); /* No more memory */
- info->current_record= NO_RECORD;
data=dynamic_element(&info->array,0,HASH_LINK*);
halfbuff= info->blength >> 1;
@@ -450,7 +462,6 @@ my_bool hash_delete(HASH *hash,byte *record)
}
if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
- hash->current_record= NO_RECORD;
lastpos=data+hash->records;
/* Remove link to record */
@@ -543,7 +554,6 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
if ((idx=pos->next) == NO_RECORD)
DBUG_RETURN(1); /* Not found in links */
}
- hash->current_record= NO_RECORD;
org_link= *pos;
empty=idx;
@@ -593,10 +603,10 @@ byte *hash_element(HASH *hash,uint idx)
isn't changed
*/
-void hash_replace(HASH *hash, uint idx, byte *new_row)
+void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, byte *new_row)
{
- if (idx != NO_RECORD) /* Safety */
- dynamic_element(&hash->array,idx,HASH_LINK*)->data=new_row;
+ if (*current_record != NO_RECORD) /* Safety */
+ dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
}
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index 1f3db84304e..e181ccfb88d 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -79,7 +79,7 @@ my_off_t my_b_safe_tell(IO_CACHE *info)
void my_b_seek(IO_CACHE *info,my_off_t pos)
{
- my_off_t offset;
+ my_off_t offset;
DBUG_ENTER("my_b_seek");
DBUG_PRINT("enter",("pos: %lu", (ulong) pos));
@@ -91,10 +91,10 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
b) see if there is a better way to make it work
*/
if (info->type == SEQ_READ_APPEND)
- flush_io_cache(info);
-
+ VOID(flush_io_cache(info));
+
offset=(pos - info->pos_in_file);
-
+
if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND)
{
/* TODO: explain why this works if pos < info->pos_in_file */
@@ -119,7 +119,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
info->write_pos = info->write_buffer + offset;
DBUG_VOID_RETURN;
}
- flush_io_cache(info);
+ VOID(flush_io_cache(info));
/* Correct buffer end so that we write in increments of IO_SIZE */
info->write_end=(info->write_buffer+info->buffer_length-
(pos & (IO_SIZE-1)));
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index 4a917fc8287..e2875d9e53e 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -69,7 +69,7 @@ my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
(thread_safe ?
sizeof(pthread_mutex_t) : 0),
MYF(MY_WME | MY_ZEROFILL))))
- return 1;
+ DBUG_RETURN(1);
map->bitmap_size=bitmap_size;
#ifdef THREAD
if (thread_safe)
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index 072492172e3..2fb022a25f2 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -53,7 +53,7 @@ struct utimbuf {
int my_copy(const char *from, const char *to, myf MyFlags)
{
uint Count;
- my_bool new_file_stat; /* 1 if we could stat "to" */
+ my_bool new_file_stat= 0; /* 1 if we could stat "to" */
int create_flag;
File from_file,to_file;
char buff[IO_SIZE];
@@ -62,7 +62,6 @@ int my_copy(const char *from, const char *to, myf MyFlags)
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
from_file=to_file= -1;
- LINT_INIT(new_file_stat);
DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));
diff --git a/mysys/my_error.c b/mysys/my_error.c
index 0c18bbf6e8b..d7177e7a047 100644
--- a/mysys/my_error.c
+++ b/mysys/my_error.c
@@ -189,7 +189,10 @@ int my_error_register(const char **errmsgs, int first, int last)
/* Error numbers must be unique. No overlapping is allowed. */
if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
+ {
+ my_free((gptr)meh_p, MYF(0));
return 1;
+ }
/* Insert header into the chain. */
meh_p->meh_next= *search_meh_pp;
diff --git a/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/mysys/testhash.c b/mysys/testhash.c
index 72badffdbcd..d15016113cd 100644
--- a/mysys/testhash.c
+++ b/mysys/testhash.c
@@ -74,7 +74,7 @@ static int do_test()
bzero((char*) key1,sizeof(key1[0])*1000);
printf("- Creating hash\n");
- if (hash_init(&hash,recant/2,0,6,0,free_record,0))
+ if (hash_init(&hash, default_charset_info, recant/2, 0, 6, 0, free_record, 0))
goto err;
printf("- Writing records:\n");
@@ -172,15 +172,16 @@ static int do_test()
break;
if (key1[j] > 1)
{
+ HASH_SEARCH_STATE state;
printf("- Testing identical read\n");
sprintf(key,"%6d",j);
pos=1;
- if (!(recpos=hash_search(&hash,key,0)))
+ if (!(recpos= hash_first(&hash, key, 0, &state)))
{
printf("can't find key1: \"%s\"\n",key);
goto err;
}
- while (hash_next(&hash,key,0) && pos < (ulong) (key1[j]+10))
+ while (hash_next(&hash, key, 0, &state) && pos < (ulong) (key1[j]+10))
pos++;
if (pos != (ulong) key1[j])
{
@@ -189,7 +190,7 @@ static int do_test()
}
}
printf("- Creating output heap-file 2\n");
- if (hash_init(&hash2,hash.records,0,0,hash2_key,free_record,0))
+ if (hash_init(&hash2, default_charset_info, hash.records, 0, 0, hash2_key, free_record,0))
goto err;
printf("- Copying and removing records\n");
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
index e5b77de5e38..41914080a9d 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -401,7 +401,7 @@ void end_thr_alarm(my_bool free_structures)
{
DBUG_ENTER("end_thr_alarm");
if (alarm_aborted != 1) /* If memory not freed */
- {
+ {
pthread_mutex_lock(&LOCK_alarm);
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
alarm_aborted= -1; /* mark aborted */
@@ -415,13 +415,10 @@ void end_thr_alarm(my_bool free_structures)
if (free_structures)
{
struct timespec abstime;
- /*
- The following test is just for safety, the caller should not
- depend on this
- */
- DBUG_ASSERT(!alarm_queue.elements);
- /* Wait until alarm thread dies */
+ DBUG_ASSERT(!alarm_queue.elements);
+
+ /* Wait until alarm thread dies */
set_timespec(abstime, 10); /* Wait up to 10 seconds */
while (alarm_thread_running)
{
@@ -429,16 +426,13 @@ void end_thr_alarm(my_bool free_structures)
if (error == ETIME || error == ETIMEDOUT)
break; /* Don't wait forever */
}
- if (!alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ alarm_aborted= 1;
+ pthread_mutex_unlock(&LOCK_alarm);
+ if (!alarm_thread_running) /* Safety */
{
- delete_queue(&alarm_queue);
- alarm_aborted= 1;
- pthread_mutex_unlock(&LOCK_alarm);
- if (!alarm_thread_running) /* Safety */
- {
- pthread_mutex_destroy(&LOCK_alarm);
- pthread_cond_destroy(&COND_alarm);
- }
+ pthread_mutex_destroy(&LOCK_alarm);
+ pthread_cond_destroy(&COND_alarm);
}
}
else
diff --git a/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/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp
index 05ae8f3cbf3..2d50890e962 100644
--- a/ndb/src/kernel/blocks/backup/Backup.cpp
+++ b/ndb/src/kernel/blocks/backup/Backup.cpp
@@ -3871,7 +3871,7 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr)
req->userReference = reference();
req->varIndex = 0;
req->offset = tmp - c_startOfPages;
- req->size = sz; // Avrunda uppot
+ req->size = sz; // Round up
sendSignal(NDBFS_REF, GSN_FSAPPENDREQ, signal,
FsAppendReq::SignalLength, JBA);
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index 1ab606758e6..2a28c4db770 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -11135,7 +11135,11 @@ void Dbdih::initCommonData()
cnoReplicas = 1;
ndb_mgm_get_int_parameter(p, CFG_DB_NO_REPLICAS, &cnoReplicas);
- cnoReplicas = cnoReplicas > 4 ? 4 : cnoReplicas;
+ if (cnoReplicas > 4)
+ {
+ progError(__LINE__, NDBD_EXIT_INVALID_CONFIG,
+ "Only up to four replicas are supported. Check NoOfReplicas.");
+ }
cgcpDelay = 2000;
ndb_mgm_get_int_parameter(p, CFG_DB_GCP_INTERVAL, &cgcpDelay);
@@ -11723,14 +11727,14 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal)
break;
case CheckNodeGroups::GetNodeGroupMembers: {
ok = true;
- Uint32 ownNodeGoup =
+ Uint32 ownNodeGroup =
Sysfile::getNodeGroup(sd->nodeId, SYSFILE->nodeGroups);
- sd->output = ownNodeGoup;
+ sd->output = ownNodeGroup;
sd->mask.clear();
NodeGroupRecordPtr ngPtr;
- ngPtr.i = ownNodeGoup;
+ ngPtr.i = ownNodeGroup;
ptrAss(ngPtr, nodeGroupRecord);
for (Uint32 j = 0; j < ngPtr.p->nodeCount; j++) {
jam();
@@ -11738,7 +11742,7 @@ void Dbdih::execCHECKNODEGROUPSREQ(Signal* signal)
}
#if 0
for (int i = 0; i < MAX_NDB_NODES; i++) {
- if (ownNodeGoup ==
+ if (ownNodeGroup ==
Sysfile::getNodeGroup(i, SYSFILE->nodeGroups)) {
sd->mask.set(i);
}
diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
index 2e50c0f8f73..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
@@ -18578,60 +18587,54 @@ void
Dblqh::execCREATE_TRIG_REQ(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference tupref = calcTupBlockRef(myNodeId);
- sendSignal(tupref, GSN_CREATE_TRIG_REQ, signal, CreateTrigReq::SignalLength, JBB);
+ sendSignal(DBTUP_REF, GSN_CREATE_TRIG_REQ, signal,
+ CreateTrigReq::SignalLength, JBB);
}
void
Dblqh::execCREATE_TRIG_CONF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_CREATE_TRIG_CONF, signal, CreateTrigConf::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_CREATE_TRIG_CONF, signal,
+ CreateTrigConf::SignalLength, JBB);
}
void
Dblqh::execCREATE_TRIG_REF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_CREATE_TRIG_REF, signal, CreateTrigRef::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_CREATE_TRIG_REF, signal,
+ CreateTrigRef::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_REQ(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference tupref = calcTupBlockRef(myNodeId);
- sendSignal(tupref, GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB);
+ sendSignal(DBTUP_REF, GSN_DROP_TRIG_REQ, signal,
+ DropTrigReq::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_CONF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_DROP_TRIG_CONF, signal, DropTrigConf::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_DROP_TRIG_CONF, signal,
+ DropTrigConf::SignalLength, JBB);
}
void
Dblqh::execDROP_TRIG_REF(Signal* signal)
{
jamEntry();
- NodeId myNodeId = getOwnNodeId();
- BlockReference dictref = calcDictBlockRef(myNodeId);
- sendSignal(dictref, GSN_DROP_TRIG_REF, signal, DropTrigRef::SignalLength, JBB);
+ sendSignal(DBDICT_REF, GSN_DROP_TRIG_REF, signal,
+ DropTrigRef::SignalLength, JBB);
}
Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
index 470b98fd04c..e16d3df6d8d 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
@@ -445,6 +445,7 @@ Dbtup::commitRecord(Signal* signal,
befOpPtr.p->changeMask.bitOR(attributeMask);
befOpPtr.p->gci = regOperPtr->gci;
+ befOpPtr.p->optype = opType;
operPtr.p = befOpPtr.p;
checkDetachedTriggers(signal,
befOpPtr.p,
@@ -483,6 +484,7 @@ Dbtup::commitRecord(Signal* signal,
befOpPtr.p->pageIndex = befOpPtr.p->pageIndexC;
befOpPtr.p->gci = regOperPtr->gci;
+ befOpPtr.p->optype = opType;
operPtr.p = befOpPtr.p;
checkDetachedTriggers(signal,
befOpPtr.p,
diff --git a/ndb/src/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/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
index 208525bfc15..9c147be9f16 100644
--- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp
+++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp
@@ -250,10 +250,10 @@ NdbEventOperationImpl::execute()
int hasSubscriber;
int r= m_bufferHandle->prepareAddSubscribeEvent(this,
hasSubscriber /*return value*/);
- m_error.code= 4709;
if (r < 0)
{
+ m_error.code= 4709;
DBUG_RETURN(-1);
}
diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index d83e9614eb5..0533493ba09 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -35,7 +35,8 @@ testPartitioning \
testBitfield \
DbCreate DbAsyncGenerator \
test_event_multi_table \
-testSRBank
+testSRBank \
+test_event_merge
#flexTimedAsynch
#testBlobs
@@ -80,6 +81,7 @@ DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterfa
DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
test_event_multi_table_SOURCES = test_event_multi_table.cpp
testSRBank_SOURCES = testSRBank.cpp
+test_event_merge_SOURCES = test_event_merge.cpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
@@ -160,3 +162,4 @@ testScan.dsp: Makefile \
@$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES)
@$(top_srcdir)/ndb/config/win-sources $@ $(testScan_SOURCES)
@$(top_srcdir)/ndb/config/win-libraries $@ LINK $(LDADD)
+
diff --git a/ndb/test/ndbapi/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<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
new file mode 100644
index 00000000000..f57667caf62
--- /dev/null
+++ b/ndb/test/ndbapi/test_event_merge.cpp
@@ -0,0 +1,1795 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if NDB_VERSION_D < MAKE_VERSION(5, 1, 0)
+#define version50
+#else
+#undef version50
+#endif
+
+// 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))
+#endif
+
+/*
+ * Test composite operations on same PK via events. The merge of event
+ * data can happen in 2 places:
+ *
+ * 1) In TUP at commit, the detached triggers report a single composite
+ * operation and its post/pre data
+ *
+ * 2) In event API version >= 5.1 separate commits within same GCI are
+ * by default merged. This is required to read blob data via NdbBlob.
+ *
+ * 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 type=INS
+ * DEL o INS = UPD type=INS type=INS
+ * UPD o DEL = DEL no event
+ * UPD o UPD = UPD
+ */
+
+struct Opts {
+ my_bool abort_on_error;
+ int loglevel;
+ uint loop;
+ uint maxops;
+ uint maxpk;
+ 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_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 r = (uint)random();
+ 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) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; errdb(); if (g_opts.abort_on_error) abort(); return -1; } while (0)
+
+#define chkrc(x) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " FAIL " << #x << endl; if (g_opts.abort_on_error) abort(); return -1; } while (0)
+
+#define reqrc(x) \
+ do { if (x) break; ndbout << "line " << __LINE__ << " ASSERT " << #x << endl; abort(); } while (0)
+
+#define ll0(x) \
+ do { if (g_loglevel < 0) break; ndbout << x << endl; } while (0)
+
+#define ll1(x) \
+ do { if (g_loglevel < 1) break; ndbout << x << endl; } while (0)
+
+#define ll2(x) \
+ do { if (g_loglevel < 2) break; ndbout << x << endl; } while (0)
+
+static void
+errdb()
+{
+ uint any = 0;
+ if (g_ndb != 0) {
+ const NdbError& e = g_ndb->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " ndb: error " << e);
+ }
+ if (g_dic != 0) {
+ const NdbError& e = g_dic->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " dic: error " << e);
+ }
+ if (g_con != 0) {
+ const NdbError& e = g_con->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " con: error " << e);
+ }
+ if (g_op != 0) {
+ const NdbError& e = g_op->getNdbError();
+ if (e.code != 0)
+ ll0(++any << " op: error " << e);
+ }
+ if (g_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");
+}
+
+struct Col {
+ uint no;
+ const char* name;
+ NdbDictionary::Column::Type type;
+ bool pk;
+ 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 },
+ { 4, "tx1", NdbDictionary::Column::Text, false, true, 0, 0 },
+ { 5, "tx2", NdbDictionary::Column::Text, false, true, 0, 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 < ncol())
+ return g_col[i];
+ assert(false);
+ return g_col[0];
+}
+
+static const Col&
+getcol(const char* name)
+{
+ uint i;
+ for (i = 0; i < ncol(); i++)
+ if (strcmp(g_col[i].name, name) == 0)
+ break;
+ return getcol(i);
+}
+
+static int
+createtable()
+{
+ g_tab = 0;
+ NdbDictionary::Table tab(g_tabname);
+ tab.setLogging(false);
+ CHARSET_INFO* cs;
+ chkrc((cs = get_charset_by_name(g_csname, MYF(0))) != 0);
+ uint i;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = g_col[i];
+ NdbDictionary::Column col(c.name);
+ col.setType(c.type);
+ col.setPrimaryKey(c.pk);
+ if (! c.pk)
+ col.setNullable(true);
+ col.setLength(c.length);
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ break;
+ case NdbDictionary::Column::Char:
+ col.setLength(c.length);
+ col.setCharset(cs);
+ break;
+ case NdbDictionary::Column::Text:
+ col.setInlineSize(g_blobinlinesize);
+ col.setPartSize(g_blobpartsize);
+ col.setStripeSize(g_blobstripesize);
+ col.setCharset(cs);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ tab.addColumn(col);
+ }
+ g_dic = g_ndb->getDictionary();
+ if (! g_opts.use_table) {
+ if (g_dic->getTable(g_tabname) != 0)
+ chkdb(g_dic->dropTable(g_tabname) == 0);
+ chkdb(g_dic->createTable(tab) == 0);
+ }
+ chkdb((g_tab = g_dic->getTable(g_tabname)) != 0);
+ g_dic = 0;
+ if (! g_opts.use_table) {
+ // extra row for GCI probe
+ chkdb((g_con = g_ndb->startTransaction()) != 0);
+ chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0);
+ chkdb(g_op->insertTuple() == 0);
+ Uint32 pk1;
+ char pk2[g_charlen + 1];
+ pk1 = g_maxpk;
+ 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);
+ g_ndb->closeTransaction(g_con);
+ g_op = 0;
+ g_con = 0;
+ }
+ return 0;
+}
+
+static int
+droptable()
+{
+ if (! g_opts.use_table) {
+ g_dic = g_ndb->getDictionary();
+ chkdb(g_dic->dropTable(g_tab->getName()) == 0);
+ g_tab = 0;
+ g_dic = 0;
+ }
+ return 0;
+}
+
+struct Data {
+ struct Txt { char* val; uint len; };
+ union Ptr { Uint32* u32; char* ch; Txt* txt; void* v; };
+ Uint32 pk1;
+ char pk2[g_charlen + 1];
+ Uint32 seq;
+ 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));
+ 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 < ncol(); i++) {
+ const Col& c = getcol(i);
+ out << (i == 0 ? "" : " ") << c.name;
+ out << (! (d.noop & (1 << i)) ? "=" : ":");
+ if (d.ind[i] == -1)
+ continue;
+ if (d.ind[i] == 1) {
+ out << "NULL";
+ continue;
+ }
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ out << *d.ptr[i].u32;
+ break;
+ case NdbDictionary::Column::Char:
+ {
+ char buf[g_charlen + 1];
+ memcpy(buf, d.ptr[i].ch, g_charlen);
+ uint n = g_charlen;
+ while (1) {
+ buf[n] = 0;
+ if (n == 0 || buf[n - 1] != 0x20)
+ break;
+ n--;
+ }
+ 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:
+ assert(false);
+ break;
+ }
+ }
+ return out;
+}
+
+static const uint g_optypes = 3; // real ops 0-2
+
+/*
+ * Represents single or composite operation or received event. The
+ * post/pre data is either computed here for operations or received from
+ * the event.
+ */
+struct Op { // single or composite
+ enum Kind { OP = 1, EV = 2 };
+ enum Type { NUL = -1, INS, DEL, UPD };
+ Kind kind;
+ Type type;
+ Op* next_op; // within one commit
+ Op* next_com; // next commit chain or next event
+ 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
+ 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 = next_gci = next_ev = next_free = 0;
+ free = false;
+ num_op = num_com = 0;
+ data[0].init();
+ data[1].init();
+ match = false;
+ gci = 0;
+ }
+};
+
+static NdbOut&
+operator<<(NdbOut& out, Op::Type t)
+{
+ switch (t) {
+ case Op::NUL:
+ out << "NUL";
+ break;
+ case Op::INS:
+ out << "INS";
+ break;
+ case Op::DEL:
+ out << "DEL";
+ break;
+ case Op::UPD:
+ out << "UPD";
+ break;
+ default:
+ out << (int)t;
+ break;
+ }
+ return out;
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const Op& op)
+{
+ out << op.type;
+ out << " " << op.data[0];
+ out << " [" << op.data[1] << "]";
+ if (op.gci != 0)
+ out << " gci:" << op.gci;
+ return out;
+}
+
+static int
+seteventtype(Op* ev, NdbDictionary::Event::TableEvent te)
+{
+ Op::Type t = Op::NUL;
+ switch (te) {
+ case NdbDictionary::Event::TE_INSERT:
+ t = Op::INS;
+ break;
+ case NdbDictionary::Event::TE_DELETE:
+ t = Op::DEL;
+ break;
+ case NdbDictionary::Event::TE_UPDATE:
+ t = Op::UPD;
+ break;
+ default:
+ ll0("EVT: " << *ev << ": bad event type" << (int)te);
+ return -1;
+ }
+ ev->type = t;
+ return 0;
+}
+
+static Op* g_opfree = 0;
+static uint g_freeops = 0;
+static uint g_usedops = 0;
+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_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_pos[g_maxpk];
+
+static Op*
+getop(Op::Kind a_kind)
+{
+ 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++;
+ }
+ Op* op = g_opfree;
+ g_opfree = op->next_free;
+ assert(g_freeops != 0);
+ g_freeops--;
+ g_usedops++;
+ op->init(a_kind);
+ return op;
+}
+
+static void
+freeop(Op* op)
+{
+ 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_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 {
+ Op::Type t1, t2, t3;
+};
+
+static Comp
+g_comp[] = {
+ { Op::INS, Op::DEL, Op::NUL },
+ { Op::INS, Op::UPD, Op::INS },
+ { Op::DEL, Op::INS, Op::UPD },
+ { Op::UPD, Op::DEL, Op::DEL },
+ { Op::UPD, Op::UPD, Op::UPD }
+};
+
+static const uint g_ncomp = sizeof(g_comp)/sizeof(g_comp[0]);
+
+static int
+checkop(const Op* op, Uint32& pk1)
+{
+ Op::Type t = op->type;
+ 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 < ncol(); i++) {
+ const Col& c = getcol(i);
+ 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;
+}
+
+static Comp*
+comptype(Op::Type t1, Op::Type t2) // only non-NUL
+{
+ uint i;
+ for (i = 0; i < g_ncomp; i++)
+ if (g_comp[i].t1 == t1 && g_comp[i].t2 == t2)
+ return &g_comp[i];
+ return 0;
+}
+
+static void
+copycol(const Col& c, const Data& d1, Data& d3)
+{
+ 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
+copydata(const Data& d1, Data& d3, bool pk, bool nonpk)
+{
+ uint i;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = g_col[i];
+ if (c.pk && pk || ! c.pk && nonpk)
+ copycol(c, d1, d3);
+ }
+}
+
+static void
+compdata(const Data& d1, const Data& d2, Data& d3, bool pk, bool nonpk)
+{
+ uint i;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = g_col[i];
+ 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);
+ }
+ }
+}
+
+static void
+copyop(const Op* op1, Op* op3)
+{
+ op3->type = op1->type;
+ 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);
+}
+
+static int
+compop(const Op* op1, const Op* op2, Op* op3) // op1 o op2 = op3
+{
+ Comp* comp;
+ if (op2->type == Op::NUL) {
+ copyop(op1, op3);
+ return 0;
+ }
+ if (op1->type == Op::NUL) {
+ copyop(op2, op3);
+ return 0;
+ }
+ 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);
+ 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(res_op, pk1_tmp) == 0);
+ copyop(res_op, op3);
+ freeop(res_op);
+ return 0;
+}
+
+static int
+createevent()
+{
+ ll1("createevent");
+ g_evt = 0;
+ g_dic = g_ndb->getDictionary();
+ NdbDictionary::Event evt(g_evtname);
+ evt.setTable(*g_tab);
+ evt.addTableEvent(NdbDictionary::Event::TE_ALL);
+ 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);
+ chkdb((g_evt = g_dic->getEvent(evt.getName())) != 0);
+ g_dic = 0;
+ return 0;
+}
+
+static int
+dropevent()
+{
+ ll1("dropevent");
+ g_dic = g_ndb->getDictionary();
+ chkdb(g_dic->dropEvent(g_evt->getName()) == 0);
+ g_evt = 0;
+ g_dic = 0;
+ return 0;
+}
+
+static int
+createeventop()
+{
+ ll1("createeventop");
+#ifdef version50
+ uint bsz = 10 * g_opts.maxops;
+ chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName(), bsz)) != 0);
+#else
+ chkdb((g_evt_op = g_ndb->createEventOperation(g_evt->getName())) != 0);
+#ifdef version51rbr
+ g_evt_op->separateEvents(g_opts.separate_events); // not yet inherited
+#endif
+#endif
+ uint i;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = g_col[i];
+ Data (&d)[2] = g_rec_ev->data;
+ 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;
+}
+
+static int
+dropeventop()
+{
+ ll1("dropeventop");
+ chkdb(g_ndb->dropEventOperation(g_evt_op) == 0);
+ g_evt_op = 0;
+ return 0;
+}
+
+static int
+waitgci() // wait for event to be installed and for at least 1 GCI to pass
+{
+ const uint ngci = 3;
+ ll1("waitgci " << ngci);
+ Uint32 gci[2];
+ uint i = 0;
+ while (1) {
+ chkdb((g_con = g_ndb->startTransaction()) != 0);
+ { // forced to exec a dummy op
+ Uint32 pk1;
+ char pk2[g_charlen + 1];
+ pk1 = g_maxpk;
+ 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);
+ chkdb(g_op->equal("pk2", (char*)&pk2[0]) == 0);
+ chkdb(g_con->execute(Commit) == 0);
+ g_op = 0;
+ }
+ gci[i] = g_con->getGCI();
+ g_ndb->closeTransaction(g_con);
+ g_con = 0;
+ if (i == 1 && gci[0] + ngci <= gci[1]) {
+ ll1("waitgci: " << gci[0] << " " << gci[1]);
+ break;
+ }
+ i = 1;
+ sleep(1);
+ }
+ return 0;
+}
+
+// scan table and set current tot_op for each pk1
+static int
+scantab()
+{
+ 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 < ncol(); i++) {
+ const Col& c = getcol(i);
+ 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);
+ }
+ }
+ chkdb(g_con->execute(NoCommit) == 0);
+ int ret;
+ while ((ret = g_scan_op->nextResult()) == 0) {
+ Uint32 pk1 = d0.pk1;
+ if (pk1 >= g_opts.maxpk)
+ continue;
+ rec_op->type = Op::INS;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = getcol(i);
+ int ind;
+ if (! c.isblob()) {
+ ind = ra[i]->isNULL();
+ } else {
+#ifdef version51rbr
+ int ret;
+ ret = bh[i]->getDefined(ind);
+ assert(ret == 0);
+ if (ind == 0) {
+ Data::Txt& t = *d0.ptr[i].txt;
+ Uint64 len64;
+ ret = bh[i]->getLength(len64);
+ assert(ret == 0);
+ t.len = (uint)len64;
+ delete [] t.val;
+ t.val = new char [t.len];
+ memset(t.val, 'X', t.len);
+ Uint32 len = t.len;
+ ret = bh[i]->readData(t.val, len);
+ assert(ret == 0 && len == t.len);
+ }
+#endif
+ }
+ assert(ind >= 0);
+ d0.ind[i] = ind;
+ }
+ assert(g_pk_op[pk1] == 0);
+ Op* tot_op = g_pk_op[pk1] = getop(Op::OP);
+ copyop(rec_op, tot_op);
+ tot_op->type = Op::INS;
+ }
+ chkdb(ret == 1);
+ g_ndb->closeTransaction(g_con);
+ g_scan_op = 0;
+ g_con = 0;
+ freeop(rec_op);
+ return 0;
+}
+
+static void
+makedata(const Col& c, Data& d, Uint32 pk1, Op::Type t)
+{
+ uint i = c.no;
+ if (c.pk) {
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ {
+ Uint32* p = d.ptr[i].u32;
+ *p = pk1;
+ }
+ break;
+ case NdbDictionary::Column::Char:
+ {
+ char* p = d.ptr[i].ch;
+ sprintf(p, "%-*u", g_charlen, pk1);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ d.ind[i] = 0;
+ } else if (t == Op::DEL) {
+ ;
+ } else if (i == getcol("seq").no) {
+ d.seq = g_seq++;
+ d.ind[i] = 0;
+ } else if (t == Op::INS && c.nullable && urandom(10, 100)) {
+ d.noop |= (1 << i);
+ d.ind[i] = 1; // implicit NULL value is known
+ } else if (t == Op::UPD && urandom(10, 100)) {
+ d.noop |= (1 << i);
+ d.ind[i] = -1; // fixed up in caller
+ } else if (c.nullable && urandom(10, 100)) {
+ d.ind[i] = 1;
+ } else {
+ switch (c.type) {
+ case NdbDictionary::Column::Unsigned:
+ {
+ Uint32* p = d.ptr[i].u32;
+ uint u = urandom();
+ *p = u;
+ }
+ break;
+ case NdbDictionary::Column::Char:
+ {
+ char* p = d.ptr[i].ch;
+ uint u = urandom(g_charlen);
+ uint j;
+ for (j = 0; j < g_charlen; j++) {
+ 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;
+ default:
+ assert(false);
+ break;
+ }
+ d.ind[i] = 0;
+ }
+}
+
+static void
+makeop(const Op* prev_op, Op* op, Uint32 pk1, Op::Type t)
+{
+ 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");
+ Uint32 pk1 = 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);
+ // 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(Op::OP);
+ assert(tot_op->type == Op::NUL || tot_op->type == Op::INS);
+ // add new commit chain to end
+ 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.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 current g_opts.opstring part
+ Op::Type t;
+ if (g_opts.opstring == 0) {
+ if (n == len)
+ break;
+ do {
+ t = (Op::Type)urandom(g_optypes);
+ } while (tot_op->type == Op::NUL && (t == Op::DEL || t == Op::UPD) ||
+ tot_op->type == Op::INS && t == Op::INS);
+ } else {
+ 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 = str[k];
+ if (c == 'c') {
+ if (k + 1 == m)
+ pk1 += 1;
+ break;
+ }
+ const char* p = "idu";
+ const char* q = strchr(p, c);
+ assert(q != 0);
+ t = (Op::Type)(q - p);
+ }
+ 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;
+ }
+ ll1("makeops: used ops = " << g_usedops);
+}
+
+static int
+addndbop(Op* op)
+{
+ chkdb((g_op = g_con->getNdbOperation(g_tabname)) != 0);
+ switch (op->type) {
+ case Op::INS:
+ chkdb(g_op->insertTuple() == 0);
+ break;
+ case Op::DEL:
+ chkdb(g_op->deleteTuple() == 0);
+ break;
+ case Op::UPD:
+ chkdb(g_op->updateTuple() == 0);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ uint i;
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = getcol(i);
+ const Data& d = op->data[0];
+ if (! c.pk)
+ continue;
+ chkdb(g_op->equal(c.name, (const char*)d.ptr[i].v) == 0);
+ }
+ if (op->type != Op::DEL) {
+ for (i = 0; i < ncol(); i++) {
+ const Col& c = getcol(i);
+ const Data& d = op->data[0];
+ if (c.pk)
+ continue;
+ if (d.noop & (1 << i))
+ continue;
+ 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;
+ return 0;
+}
+
+static int
+runops()
+{
+ ll1("runops");
+ Uint32 pk1;
+ Op* gci_op[g_maxpk];
+ uint left = 0; // number of pks with ops
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ 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_gci != 0);
+ gci_op[pk1] = tot_op->next_gci;
+ left++;
+ }
+ while (left != 0) {
+ pk1 = urandom(g_opts.maxpk);
+ if (gci_op[pk1] == 0)
+ continue;
+ // do the ops in one transaction
+ 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->next_op;
+ assert(op != 0);
+ while (op != 0) {
+ 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
+ gci_op[pk1] = gci_op[pk1]->next_gci;
+ if (gci_op[pk1] == 0) {
+ assert(left != 0);
+ left--;
+ }
+ }
+ assert(left == 0);
+ 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 (&d2)[2] = ev->data;
+ // get PK
+ Uint32 pk1 = d2[0].pk1;
+ chkrc(pk1 < g_opts.maxpk);
+ // on error repeat and print details
+ uint loop = 0;
+ while (loop <= 1) {
+ uint g_loglevel = loop == 0 ? g_opts.loglevel : 2;
+ ll1("matchevent: pk1=" << pk1 << " type=" << t);
+ ll2("EVT: " << *ev);
+ Op* tot_op = g_pk_op[pk1];
+ Op* gci_op = tot_op ? tot_op->next_gci : 0;
+ uint pos = 0;
+ bool ok = false;
+ 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;
+ }
+ // 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");
+ }
+ }
+ pos++;
+ }
+ gci_op = gci_op->next_gci;
+ }
+ if (ok) {
+ ll1("matchevent: match");
+ return 0;
+ }
+ ll1("matchevent: ERROR: no match");
+ if (g_loglevel >= 2)
+ return -1;
+ loop++;
+ }
+ return 0;
+}
+
+static int
+matchevents()
+{
+ uint nomatch = 0;
+ Uint32 pk1;
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ Op* tot_ev = g_pk_ev[pk1];
+ if (tot_ev == 0)
+ continue;
+ Op* ev = tot_ev->next_ev;
+ while (ev != 0) {
+ if (matchevent(ev) < 0)
+ nomatch++;
+ g_ev_pos[pk1]++;
+ ev = ev->next_ev;
+ }
+ }
+ chkrc(nomatch == 0);
+ return 0;
+}
+
+static int
+matchops()
+{
+ Uint32 pk1;
+ for (pk1 = 0; pk1 < g_opts.maxpk; pk1++) {
+ Op* tot_op = g_pk_op[pk1];
+ if (tot_op == 0)
+ continue;
+ Op* com_op = tot_op->next_com;
+ while (com_op != 0) {
+ if (com_op->type != Op::NUL && ! com_op->match) {
+ ll0("COM: " << *com_op);
+ Op* op = com_op->next_op;
+ assert(op != 0);
+ while (op != 0) {
+ ll0("---: " << *op);
+ op = op->next_op;
+ }
+ ll0("no matching event");
+ return -1;
+ }
+ com_op = com_op->next_com;
+ }
+ }
+ return 0;
+}
+
+static 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");
+ uint mspoll = 1000;
+ uint npoll = 6; // strangely long delay
+ while (npoll != 0) {
+ npoll--;
+ int ret;
+ ll1("poll");
+ ret = g_ndb->pollEvents(mspoll);
+ if (ret <= 0)
+ continue;
+ while (1) {
+ g_rec_ev->init(Op::EV);
+#ifdef version50
+ int overrun = g_opts.maxops;
+ chkdb((ret = g_evt_op->next(&overrun)) >= 0);
+ chkrc(overrun == 0);
+ if (ret == 0)
+ break;
+#else
+ NdbEventOperation* tmp_op = g_ndb->nextEvent();
+ if (tmp_op == 0)
+ break;
+ reqrc(g_evt_op == tmp_op);
+#endif
+ chkrc(seteventtype(g_rec_ev, g_evt_op->getEventType()) == 0);
+ 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
+ Op* tot_ev = g_pk_ev[pk1];
+ if (tot_ev == 0)
+ 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 = getop(Op::EV);
+ copyop(g_rec_ev, ev);
+ last_ev->next_ev = ev;
+ }
+ }
+ ll1("runevents: used ops = " << g_usedops);
+ return 0;
+}
+
+static void
+setseed(int n)
+{
+ uint seed;
+ if (n == -1) {
+ if (g_opts.seed == 0)
+ return;
+ if (g_opts.seed != -1)
+ seed = (uint)g_opts.seed;
+ else
+ seed = 1 + (ushort)getpid();
+ } else {
+ if (g_opts.seed != 0)
+ return;
+ seed = n;
+ }
+ ll0("seed=" << seed);
+ srandom(seed);
+}
+
+static int
+runtest()
+{
+ setseed(-1);
+ chkrc(createtable() == 0);
+ chkrc(createevent() == 0);
+ for (g_loop = 0; g_opts.loop == 0 || g_loop < g_opts.loop; g_loop++) {
+ ll0("loop " << g_loop);
+ setseed(g_loop);
+ resetmem();
+ 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);
+ 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);
+ chkrc(droptable() == 0);
+ return 0;
+}
+
+NDB_STD_OPTS_VARS;
+
+static struct my_option
+my_long_options[] =
+{
+ NDB_STD_OPTS("test_event_merge"),
+ { "abort-on-error", 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", 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", 1003, "Number of test loops (default 2, 0=forever)",
+ (gptr*)&g_opts.loop, (gptr*)&g_opts.loop, 0,
+ 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, 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 },
+ { "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", 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", 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", 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,
+ 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
+};
+
+static void
+usage()
+{
+ my_print_help(my_long_options);
+}
+
+static int
+checkopts()
+{
+#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;
+}
+
+int
+main(int argc, char** argv)
+{
+ ndb_init();
+ const char* progname =
+ strchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
+ uint i;
+ ndbout << progname;
+ for (i = 1; i < argc; i++)
+ ndbout << " " << argv[i];
+ ndbout << endl;
+ int ret;
+ ret = handle_options(&argc, &argv, my_long_options, ndb_std_get_one_option);
+ if (ret != 0 || argc != 0 || checkopts() != 0)
+ return NDBT_ProgramExit(NDBT_WRONGARGS);
+ g_ncc = new Ndb_cluster_connection();
+ if (g_ncc->connect(30) == 0) {
+ g_ndb = new Ndb(g_ncc, "TEST_DB");
+ if (g_ndb->init() == 0 && g_ndb->waitUntilReady(30) == 0) {
+ if (runtest() == 0)
+ return NDBT_ProgramExit(NDBT_OK);
+ }
+ }
+ 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/ndb/tools/ndb_error_reporter b/ndb/tools/ndb_error_reporter
new file mode 100755
index 00000000000..2b5aadb6171
--- /dev/null
+++ b/ndb/tools/ndb_error_reporter
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+if(@ARGV < 1)
+{
+ print STDERR "Usage:\n";
+ print STDERR "\tndb_error_reporter config.ini [username] [--fs]\n\n";
+ print STDERR "\tusername is a user that you can use to ssh into\n";
+ print STDERR "\t all of your nodes with.\n\n";
+ print STDERR "\t--fs means include the filesystems in the report\n";
+ print STDERR "\t WARNING: This may require a lot of disk space.\n";
+ print STDERR "\t Only use this option when asked to.\n\n";
+ exit(1);
+}
+
+my $config_file= $ARGV[0];
+my $config_get_fs= 0;
+my $config_username= '';
+if(defined($ARGV[1]))
+{
+ $config_get_fs= 1 if $ARGV[1] eq '--fs';
+ $config_username= $ARGV[1].'@' if $ARGV[1] ne '--fs';
+ $config_get_fs= (defined $ARGV[2] && $ARGV[2] eq '--fs')?1:$config_get_fs;
+}
+
+if(!stat($config_file))
+{
+ print STDERR "Cannot open configuration file.\n\n";
+ exit(1);
+}
+
+my @nodes= split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndbd`;
+
+push @nodes, split ' ',`ndb_config --config-file=$ARGV[0] --nodes --query=id --type=ndb_mgmd`;
+
+sub config {
+ my $nodeid= shift;
+ my $query= shift;
+ my $res= `ndb_config --config-file=$ARGV[0] --id=$nodeid --query=$query`;
+ chomp $res;
+ $res;
+}
+
+my @t= localtime();
+my $reportdir= sprintf('ndb_error_report_%u%02u%02u%02u%02u%02u',
+ ($t[5]+1900),($t[4]+1),$t[3],$t[2],$t[1],$t[0]);
+
+if(stat($reportdir) || stat($reportdir.'tar.bz2'))
+{
+ print STDERR "It looks like another ndb_error_report process is running.\n";
+ print STDERR "If that is not the case, remove the ndb_error_report directory";
+ print STDERR " and run ndb_error_report again.\n\n";
+ exit(1);
+}
+
+mkdir($reportdir);
+
+foreach my $node (@nodes)
+{
+ print "\n\n Copying data from node $node".
+ (($config_get_fs)?" with filesystem":"").
+ "\n\n";
+ my $recurse= ($config_get_fs)?'-r ':'';
+ system 'scp '.$recurse.$config_username.config($node,'host').
+ ':'.config($node,'datadir')."/ndb_".$node."* ".
+ "$reportdir/\n";
+}
+
+print "\n\n Copying configuration file...\n\n\t$config_file\n\n";
+system "cp $config_file $reportdir/";
+
+my $r = system 'bzip2 2>&1 > /dev/null < /dev/null';
+my $outfile;
+if($r==0)
+{
+ $outfile= "$reportdir.tar.bz2";
+ system "tar c $reportdir|bzip2 > $outfile";
+}
+else
+{
+ $outfile= "$reportdir.tar.gz";
+ system "tar c $reportdir|gzip > $outfile";
+}
+
+system "rm -rf $reportdir";
+
+print "\n\nPlease attach $outfile to your error report\n\n";
diff --git a/ndb/tools/ndb_size.pl b/ndb/tools/ndb_size.pl
index ece0901e0b2..e0085c619f0 100644
--- a/ndb/tools/ndb_size.pl
+++ b/ndb/tools/ndb_size.pl
@@ -146,9 +146,9 @@ foreach(@{$tables})
elsif($type =~ /varchar/ || $type =~ /varbinary/)
{
my $fixed= 1+$size;
- my @dynamic=$dbh->selectrow_array("select avg(length("
- .$dbh->quote($name)
- .")) from `".$table.'`');
+ my @dynamic=$dbh->selectrow_array("select avg(length(`"
+ .$name.
+ ."`)) from `".$table.'`');
$dynamic[0]=0 if !$dynamic[0];
@realsize= ($fixed,$fixed,ceil($dynamic[0]));
}
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/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index b2b85018d7a..2dcc8dc7bc4 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -763,9 +763,6 @@ sub usage
print <unlock();
return; /* error is logged */
+ }
/* allow users to delete instances */
instance_map->unlock();
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index d83af2b9cf0..a79a6ad6742 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -107,7 +107,7 @@ Token shift_token(const char **text, uint *word_len)
int get_text_id(const char **text, uint *word_len, const char **id)
{
get_word(text, word_len);
- if (word_len == 0)
+ if (*word_len == 0)
return 1;
*id= *text;
return 0;
diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh
index d61551ffb3b..31282d06abf 100644
--- a/sql-bench/bench-init.pl.sh
+++ b/sql-bench/bench-init.pl.sh
@@ -447,7 +447,7 @@ All benchmarks takes the following options:
--create-options=#
Extra argument to all create statements. If you for example want to
create all MySQL tables as BDB tables use:
- --create-options=TYPE=BDB
+ --create-options=ENGINE=BDB
--database (Default $opt_database)
In which database the test tables are created.
diff --git a/sql-bench/server-cfg.sh b/sql-bench/server-cfg.sh
index b0c40102a6b..75528b24b77 100644
--- a/sql-bench/server-cfg.sh
+++ b/sql-bench/server-cfg.sh
@@ -174,29 +174,29 @@ sub new
# Some fixes that depends on the environment
if (defined($main::opt_create_options) &&
- $main::opt_create_options =~ /type=heap/i)
+ $main::opt_create_options =~ /engine=heap/i)
{
$limits{'working_blobs'} = 0; # HEAP tables can't handle BLOB's
}
if (defined($main::opt_create_options) &&
- $main::opt_create_options =~ /type=innodb/i)
+ $main::opt_create_options =~ /engine=innodb/i)
{
$self->{'transactions'} = 1; # Transactions enabled
}
if (defined($main::opt_create_options) &&
- $main::opt_create_options =~ /type=ndb/i)
+ $main::opt_create_options =~ /engine=ndb/i)
{
$self->{'transactions'} = 1; # Transactions enabled
$limits{'max_columns'} = 90; # Max number of columns in table
$limits{'max_tables'} = 32; # No comments
}
if (defined($main::opt_create_options) &&
- $main::opt_create_options =~ /type=bdb/i)
+ $main::opt_create_options =~ /engine=bdb/i)
{
$self->{'transactions'} = 1; # Transactions enabled
}
if (defined($main::opt_create_options) &&
- $main::opt_create_options =~ /type=gemini/i)
+ $main::opt_create_options =~ /engine=gemini/i)
{
$limits{'working_blobs'} = 0; # Blobs not implemented yet
$limits{'max_tables'} = 500;
diff --git a/sql-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/client.c b/sql-common/client.c
index 4c2debd41ff..824d3705c23 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -599,7 +599,7 @@ net_safe_read(MYSQL *mysql)
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d",
vio_description(net->vio),len));
#ifdef MYSQL_SERVER
- if (vio_was_interrupted(net->vio))
+ if (net->vio && vio_was_interrupted(net->vio))
return (packet_error);
#endif /*MYSQL_SERVER*/
end_server(mysql);
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 72809ee9b4b..c9d39260761 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -575,18 +575,34 @@ fractional:
/* Get fractional second part */
if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
{
- uint field_length=5;
+ int field_length= 5;
str++; value=(uint) (uchar) (*str - '0');
- while (++str != end &&
- my_isdigit(&my_charset_latin1,str[0]) &&
- field_length--)
- value=value*10 + (uint) (uchar) (*str - '0');
- if (field_length)
+ while (++str != end && my_isdigit(&my_charset_latin1, *str))
+ {
+ if (field_length-- > 0)
+ value= value*10 + (uint) (uchar) (*str - '0');
+ }
+ if (field_length > 0)
value*= (long) log_10_int[field_length];
+ else if (field_length < 0)
+ *was_cut= 1;
date[4]=value;
}
else
date[4]=0;
+
+ /* Check for exponent part: E | E */
+ /* (may occur as result of %g formatting of time value) */
+ if ((end - str) > 1 &&
+ (*str == 'e' || *str == 'E') &&
+ (my_isdigit(&my_charset_latin1, str[1]) ||
+ ((str[1] == '-' || str[1] == '+') &&
+ (end - str) > 2 &&
+ my_isdigit(&my_charset_latin1, str[2]))))
+ {
+ *was_cut= 1;
+ return 1;
+ }
if (internal_format_positions[7] != 255)
{
diff --git a/sql-common/my_user.c b/sql-common/my_user.c
new file mode 100644
index 00000000000..c39f08e520f
--- /dev/null
+++ b/sql-common/my_user.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2005 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include
+#include
+
+
+/*
+ Parse user value to user name and host name parts.
+
+ SYNOPSIS
+ user_id_str [IN] User value string (the source).
+ user_id_len [IN] Length of the user value.
+ user_name_str [OUT] Buffer to store user name part.
+ Must be not less than USERNAME_LENGTH + 1.
+ user_name_len [OUT] A place to store length of the user name part.
+ host_name_str [OUT] Buffer to store host name part.
+ Must be not less than HOSTNAME_LENGTH + 1.
+ host_name_len [OUT] A place to store length of the host name part.
+*/
+
+void parse_user(const char *user_id_str, uint user_id_len,
+ char *user_name_str, uint *user_name_len,
+ char *host_name_str, uint *host_name_len)
+{
+ char *p= strrchr(user_id_str, '@');
+
+ if (!p)
+ {
+ *user_name_len= 0;
+ *host_name_len= 0;
+ }
+ else
+ {
+ *user_name_len= p - user_id_str;
+ *host_name_len= user_id_len - *user_name_len - 1;
+
+ memcpy(user_name_str, user_id_str, *user_name_len);
+ memcpy(host_name_str, p + 1, *host_name_len);
+ }
+
+ user_name_str[*user_name_len]= 0;
+ host_name_str[*host_name_len]= 0;
+}
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 1437751bf2f..d701c18a4d7 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -97,7 +97,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
stacktrace.c repl_failsafe.h repl_failsafe.cc \
sql_olap.cc sql_view.cc \
gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
- tztime.cc my_time.c my_decimal.cc\
+ tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
examples/ha_example.cc ha_archive.cc \
@@ -133,6 +133,8 @@ link_sources: mysql_tzinfo_to_sql.cc
@LN_CP_F@ $(top_srcdir)/sql-common/client.c client.c
rm -f my_time.c
@LN_CP_F@ $(top_srcdir)/sql-common/my_time.c my_time.c
+ rm -f my_user.c
+ @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c
mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES)
$(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $<
diff --git a/sql/field.cc b/sql/field.cc
index 8f9dc832520..df76eb729f8 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1570,7 +1570,6 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
bool Field::quote_data(String *unquoted_string)
{
char escaped_string[IO_SIZE];
- char *unquoted_string_buffer= (char *)(unquoted_string->ptr());
DBUG_ENTER("Field::quote_data");
if (!needs_quotes())
@@ -4541,8 +4540,6 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
}
}
- if (error > 1)
- error= 2;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -6212,8 +6209,8 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table)
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
to now VARCHAR fields.
*/
- if (new_field= new Field_varstring(field_length, maybe_null(),
- field_name, new_table, charset()))
+ if ((new_field= new Field_varstring(field_length, maybe_null(),
+ field_name, new_table, charset())))
{
/*
delayed_insert::get_local_table() needs a ptr copied from old table.
@@ -7067,7 +7064,7 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type)
}
get_ptr(&blob);
gobj= Geometry::construct(&buffer, blob, blob_length);
- if (gobj->get_mbr(&mbr, &dummy))
+ if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, SIZEOF_STORED_DOUBLE*4);
else
{
@@ -7396,7 +7393,7 @@ void Field_geom::get_key_image(char *buff, uint length, imagetype type)
}
get_ptr(&blob);
gobj= Geometry::construct(&buffer, blob, blob_length);
- if (gobj->get_mbr(&mbr, &dummy))
+ if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, SIZEOF_STORED_DOUBLE*4);
else
{
@@ -8154,17 +8151,14 @@ const char *Field_bit::unpack(char *to, const char *from)
*/
Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
- uchar *null_ptr_arg, uchar null_bit_arg,
- uchar *bit_ptr_arg, uchar bit_ofs_arg,
- enum utype unireg_check_arg,
+ uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg)
- : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, bit_ptr_arg,
- bit_ofs_arg, unireg_check_arg, field_name_arg, table_arg),
+ : Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0,
+ 0, unireg_check_arg, field_name_arg, table_arg),
create_length(len_arg)
{
- bit_ptr= 0;
- bit_ofs= 0;
bit_len= 0;
field_length= ((len_arg + 7) & ~7) / 8;
}
@@ -8865,8 +8859,8 @@ Field *make_field(char *ptr, uint32 field_length,
return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
case FIELD_TYPE_BIT:
return f_bit_as_char(pack_flag) ?
- new Field_bit_as_char(ptr, field_length, null_pos, null_bit, bit_ptr,
- bit_offset, unireg_check, field_name, table) :
+ new Field_bit_as_char(ptr, field_length, null_pos, null_bit,
+ unireg_check, field_name, table) :
new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
bit_offset, unireg_check, field_name, table);
default: // Impossible (Wrong version)
@@ -8981,11 +8975,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/field.h b/sql/field.h
index 67705523088..218308ead13 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1348,12 +1348,12 @@ public:
}
};
-
+
class Field_bit_as_char: public Field_bit {
public:
uchar create_length;
Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc
index 2747f678cc3..c60d40c2685 100644
--- a/sql/ha_archive.cc
+++ b/sql/ha_archive.cc
@@ -20,7 +20,7 @@
#include "mysql_priv.h"
-#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)
+#if defined(HAVE_ARCHIVE_DB)
#include "ha_archive.h"
#include
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index d2f827989f5..14b79a9a418 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -2616,8 +2616,7 @@ int ha_federated::stash_remote_error()
{
DBUG_ENTER("ha_federated::stash_remote_error()");
remote_error_number= mysql_errno(mysql);
- my_snprintf(remote_error_buf, sizeof(remote_error_buf), "%s",
- mysql_error(mysql));
+ strmake(remote_error_buf, mysql_error(mysql), sizeof(remote_error_buf)-1);
DBUG_RETURN(HA_FEDERATED_ERROR_WITH_REMOTE_SYSTEM);
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index afeb1238aa7..c0f8559ab29 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1218,7 +1218,7 @@ innobase_init(void)
"innobase_buffer_pool_size can't be over 4GB"
" on 32-bit systems");
- DBUG_RETURN(0);
+ goto error;
}
if (innobase_log_file_size > UINT_MAX32) {
@@ -1226,7 +1226,7 @@ innobase_init(void)
"innobase_log_file_size can't be over 4GB"
" on 32-bit systems");
- DBUG_RETURN(0);
+ goto error;
}
}
@@ -1391,6 +1391,7 @@ innobase_init(void)
ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL ==
my_charset_latin1.number);
+ ut_a(DATA_MYSQL_BINARY_CHARSET_COLL == my_charset_bin.number);
/* Store the latin1_swedish_ci character ordering table to InnoDB. For
non-latin1_swedish_ci charsets we use the MySQL comparison functions,
@@ -2847,8 +2848,6 @@ ha_innobase::store_key_val_for_row(
char* buff_start = buff;
enum_field_types mysql_type;
Field* field;
- ulint blob_len;
- byte* blob_data;
ibool is_null;
DBUG_ENTER("store_key_val_for_row");
@@ -2903,14 +2902,18 @@ ha_innobase::store_key_val_for_row(
ulint len;
byte* data;
ulint key_len;
+ ulint true_len;
CHARSET_INFO* cs;
int error=0;
+ key_len = key_part->length;
+
if (is_null) {
- buff += key_part->length + 2;
+ buff += key_len + 2;
continue;
}
+ cs = field->charset();
lenlen = (ulint)
(((Field_varstring*)field)->length_bytes);
@@ -2920,32 +2923,33 @@ ha_innobase::store_key_val_for_row(
+ (ulint)get_field_offset(table, field)),
lenlen);
- /* In a column prefix index, we may need to truncate
- the stored value: */
-
- cs = key_part->field->charset();
+ true_len = len;
- if (cs->mbmaxlen > 1 && key_part->length > 0) {
- key_len = (ulint) cs->cset->well_formed_len(cs,
- (const char *) data,
- (const char *) data + key_part->length,
- key_part->length / cs->mbmaxlen,
- &error);
- } else {
- key_len = key_part->length;
+ /* For multi byte character sets we need to calculate
+ the true length of the key */
+
+ if (len > 0 && cs->mbmaxlen > 1) {
+ true_len = (ulint) cs->cset->well_formed_len(cs,
+ (const char *) data,
+ (const char *) data + len,
+ key_len / cs->mbmaxlen,
+ &error);
}
- if (len > key_len) {
- len = key_len;
+ /* In a column prefix index, we may need to truncate
+ the stored value: */
+
+ if (true_len > key_len) {
+ true_len = key_len;
}
/* The length in a key value is always stored in 2
bytes */
- row_mysql_store_true_var_len((byte*)buff, len, 2);
+ row_mysql_store_true_var_len((byte*)buff, true_len, 2);
buff += 2;
- memcpy(buff, data, len);
+ memcpy(buff, data, true_len);
/* Note that we always reserve the maximum possible
length of the true VARCHAR in the key value, though
@@ -2953,7 +2957,7 @@ ha_innobase::store_key_val_for_row(
actual data. The rest of the space was reset to zero
in the bzero() call above. */
- buff += key_part->length;
+ buff += key_len;
} else if (mysql_type == FIELD_TYPE_TINY_BLOB
|| mysql_type == FIELD_TYPE_MEDIUM_BLOB
@@ -2963,58 +2967,66 @@ ha_innobase::store_key_val_for_row(
CHARSET_INFO* cs;
ulint key_len;
ulint len;
+ ulint true_len;
int error=0;
+ ulint blob_len;
+ byte* blob_data;
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
+ key_len = key_part->length;
+
if (is_null) {
- buff += key_part->length + 2;
+ buff += key_len + 2;
continue;
}
+ cs = field->charset();
+
blob_data = row_mysql_read_blob_ref(&blob_len,
(byte*) (record
+ (ulint)get_field_offset(table, field)),
(ulint) field->pack_length());
+ true_len = blob_len;
+
ut_a(get_field_offset(table, field)
== key_part->offset);
+ /* For multi byte character sets we need to calculate
+ the true length of the key */
+
+ if (blob_len > 0 && cs->mbmaxlen > 1) {
+ true_len = (ulint) cs->cset->well_formed_len(cs,
+ (const char *) blob_data,
+ (const char *) blob_data
+ + blob_len,
+ key_len / cs->mbmaxlen,
+ &error);
+ }
+
/* All indexes on BLOB and TEXT are column prefix
indexes, and we may need to truncate the data to be
stored in the key value: */
- cs = key_part->field->charset();
-
- if (cs->mbmaxlen > 1 && key_part->length > 0) {
- key_len = (ulint) cs->cset->well_formed_len(cs,
- (const char *) blob_data,
- (const char *) blob_data
- + key_part->length,
- key_part->length / cs->mbmaxlen,
- &error);
- } else {
- key_len = key_part->length;
- }
-
- if (blob_len > key_len) {
- blob_len = key_len;
+ if (true_len > key_len) {
+ true_len = key_len;
}
/* MySQL reserves 2 bytes for the length and the
storage of the number is little-endian */
innobase_write_to_2_little_endian(
- (byte*)buff, (ulint)blob_len);
+ (byte*)buff, true_len);
buff += 2;
- memcpy(buff, blob_data, blob_len);
+ memcpy(buff, blob_data, true_len);
/* Note that we always reserve the maximum possible
length of the BLOB prefix in the key value. */
- buff += key_part->length;
+ buff += key_len;
} else {
/* Here we handle all other data types except the
true VARCHAR, BLOB and TEXT. Note that the column
@@ -3022,38 +3034,64 @@ ha_innobase::store_key_val_for_row(
index. */
CHARSET_INFO* cs;
- ulint len;
+ ulint true_len;
+ ulint key_len;
const mysql_byte* src_start;
int error=0;
+ enum_field_types real_type;
+
+ key_len = key_part->length;
if (is_null) {
- buff += key_part->length;
+ buff += key_len;
continue;
}
- cs = key_part->field->charset();
src_start = record + key_part->offset;
+ real_type = field->real_type();
+ true_len = key_len;
- if (key_part->length > 0 && cs->mbmaxlen > 1) {
- len = (ulint) cs->cset->well_formed_len(cs,
- (const char *) src_start,
- (const char *) src_start + key_part->length,
- key_part->length / cs->mbmaxlen,
- &error);
- } else {
- len = key_part->length;
+ /* Character set for the field is defined only
+ to fields whose type is string and real field
+ type is not enum or set. For these fields check
+ if character set is multi byte. */
+
+ if (real_type != FIELD_TYPE_ENUM
+ && real_type != FIELD_TYPE_SET
+ && ( mysql_type == MYSQL_TYPE_VAR_STRING
+ || mysql_type == MYSQL_TYPE_STRING)) {
+
+ cs = field->charset();
+
+ /* For multi byte character sets we need to
+ calculate the true length of the key */
+
+ if (key_len > 0 && cs->mbmaxlen > 1) {
+
+ true_len = (ulint)
+ cs->cset->well_formed_len(cs,
+ (const char *)src_start,
+ (const char *)src_start
+ + key_len,
+ key_len / cs->mbmaxlen,
+ &error);
+ }
}
- memcpy(buff, src_start, len);
- buff+=len;
+ memcpy(buff, src_start, true_len);
+ buff += true_len;
- /* Pad the unused space with spaces */
+ /* Pad the unused space with spaces. Note that no
+ padding is ever needed for UCS-2 because in MySQL,
+ all UCS2 characters are 2 bytes, as MySQL does not
+ support surrogate pairs, which are needed to represent
+ characters in the range U+10000 to U+10FFFF. */
- if (len < key_part->length) {
- len = key_part->length - len;
- memset(buff, ' ', len);
- buff+=len;
+ if (true_len < key_len) {
+ ulint pad_len = key_len - true_len;
+ memset(buff, ' ', pad_len);
+ buff += pad_len;
}
}
}
@@ -3770,9 +3808,8 @@ ha_innobase::delete_row(
}
/**************************************************************************
-Removes a new lock set on a row. This can be called after a row has been read
-in the processing of an UPDATE or a DELETE query, if the option
-innodb_locks_unsafe_for_binlog is set. */
+Removes a new lock set on a row. This method does nothing unless the
+option innodb_locks_unsafe_for_binlog is set.*/
void
ha_innobase::unlock_row(void)
@@ -3794,6 +3831,9 @@ ha_innobase::unlock_row(void)
if (srv_locks_unsafe_for_binlog) {
row_unlock_for_mysql(prebuilt, FALSE);
}
+
+ DBUG_VOID_RETURN;
+
}
/**********************************************************************
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 08fd2d9a8e3..ff6431fa0f3 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -266,7 +266,8 @@ int ha_myisam::dump(THD* thd, int fd)
if (fd < 0)
{
- my_net_write(net, "", 0);
+ if (my_net_write(net, "", 0))
+ error = errno ? errno : EPIPE;
net_flush(net);
}
@@ -365,12 +366,14 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
{
uint old_testflag=param.testflag;
param.testflag|=T_MEDIUM;
- init_io_cache(¶m.read_cache, file->dfile,
- my_default_record_cache_size, READ_CACHE,
- share->pack.header_length, 1, MYF(MY_WME));
- error |= chk_data_link(¶m, file, param.testflag & T_EXTEND);
- end_io_cache(&(param.read_cache));
- param.testflag=old_testflag;
+ if (!(error= init_io_cache(¶m.read_cache, file->dfile,
+ my_default_record_cache_size, READ_CACHE,
+ share->pack.header_length, 1, MYF(MY_WME))))
+ {
+ error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
+ end_io_cache(&(param.read_cache));
+ }
+ param.testflag= old_testflag;
}
}
if (!error)
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 0552eded9b6..699b3f05a70 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -300,7 +300,8 @@ Thd_ndb::~Thd_ndb()
if (ndb)
{
#ifndef DBUG_OFF
- Ndb::Free_list_usage tmp; tmp.m_name= 0;
+ Ndb::Free_list_usage tmp;
+ tmp.m_name= 0;
while (ndb->get_free_list_usage(&tmp))
{
uint leaked= (uint) tmp.m_created - tmp.m_free;
@@ -312,8 +313,8 @@ Thd_ndb::~Thd_ndb()
}
#endif
delete ndb;
+ ndb= NULL;
}
- ndb= NULL;
changed_tables.empty();
}
@@ -3255,6 +3256,10 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
if (lock_type != F_UNLCK)
{
DBUG_PRINT("info", ("lock_type != F_UNLCK"));
+ if (!thd->transaction.on)
+ m_transaction_on= FALSE;
+ else
+ m_transaction_on= thd->variables.ndb_use_transactions;
if (!thd_ndb->lock_count++)
{
PRINT_OPTION_FLAGS(thd);
@@ -3269,7 +3274,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
ERR_RETURN(ndb->getNdbError());
no_uncommitted_rows_reset(thd);
thd_ndb->stmt= trans;
- trans_register_ha(thd, FALSE, &ndbcluster_hton);
+ if (m_transaction_on)
+ trans_register_ha(thd, FALSE, &ndbcluster_hton);
}
else
{
@@ -3284,7 +3290,8 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
ERR_RETURN(ndb->getNdbError());
no_uncommitted_rows_reset(thd);
thd_ndb->all= trans;
- trans_register_ha(thd, TRUE, &ndbcluster_hton);
+ if (m_transaction_on)
+ trans_register_ha(thd, TRUE, &ndbcluster_hton);
/*
If this is the start of a LOCK TABLE, a table look
@@ -3318,10 +3325,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
m_ha_not_exact_count= !thd->variables.ndb_use_exact_count;
m_autoincrement_prefetch=
(ha_rows) thd->variables.ndb_autoincrement_prefetch_sz;
- if (!thd->transaction.on)
- m_transaction_on= FALSE;
- else
- m_transaction_on= thd->variables.ndb_use_transactions;
m_active_trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt;
DBUG_ASSERT(m_active_trans);
@@ -4903,7 +4906,8 @@ bool ndbcluster_end()
if (g_ndb)
{
#ifndef DBUG_OFF
- Ndb::Free_list_usage tmp; tmp.m_name= 0;
+ Ndb::Free_list_usage tmp;
+ tmp.m_name= 0;
while (g_ndb->get_free_list_usage(&tmp))
{
uint leaked= (uint) tmp.m_created - tmp.m_free;
@@ -4915,10 +4919,9 @@ bool ndbcluster_end()
}
#endif
delete g_ndb;
+ g_ndb= NULL;
}
- g_ndb= NULL;
- if (g_ndb_cluster_connection)
- delete g_ndb_cluster_connection;
+ delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL;
hash_free(&ndbcluster_open_tables);
@@ -7463,7 +7466,8 @@ ndbcluster_show_status(THD* thd)
if (have_ndbcluster != SHOW_OPTION_YES)
{
my_message(ER_NOT_SUPPORTED_YET,
- "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined",
+ "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is "
+ "defined",
MYF(0));
DBUG_RETURN(TRUE);
}
@@ -7474,13 +7478,15 @@ ndbcluster_show_status(THD* thd)
field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG));
- if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb)
{
Ndb* ndb= (get_thd_ndb(thd))->ndb;
- Ndb::Free_list_usage tmp; tmp.m_name= 0;
+ Ndb::Free_list_usage tmp;
+ tmp.m_name= 0;
while (ndb->get_free_list_usage(&tmp))
{
protocol->prepare_for_resend();
diff --git a/sql/handler.cc b/sql/handler.cc
index 47010de3002..4e128eb5938 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -60,7 +60,7 @@ handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
HTON_NO_FLAGS };
#endif
-#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)
+#if defined(HAVE_ARCHIVE_DB)
#include "ha_archive.h"
extern handlerton archive_hton;
#else
@@ -300,39 +300,56 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
case DB_TYPE_HASH:
return new (alloc) ha_hash(table);
#endif
+ case DB_TYPE_MRG_MYISAM:
case DB_TYPE_MRG_ISAM:
return new (alloc) ha_myisammrg(table);
#ifdef HAVE_BERKELEY_DB
case DB_TYPE_BERKELEY_DB:
- return new (alloc) ha_berkeley(table);
+ if (have_berkeley_db == SHOW_OPTION_YES)
+ return new (alloc) ha_berkeley(table);
+ return NULL;
#endif
#ifdef HAVE_INNOBASE_DB
case DB_TYPE_INNODB:
- return new (alloc) ha_innobase(table);
+ if (have_innodb == SHOW_OPTION_YES)
+ return new (alloc) ha_innobase(table);
+ return NULL;
#endif
#ifdef HAVE_EXAMPLE_DB
case DB_TYPE_EXAMPLE_DB:
- return new (alloc) ha_example(table);
+ if (have_example_db == SHOW_OPTION_YES)
+ return new (alloc) ha_example(table);
+ return NULL;
#endif
-#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)
+#if defined(HAVE_ARCHIVE_DB)
case DB_TYPE_ARCHIVE_DB:
- return new (alloc) ha_archive(table);
+ if (have_archive_db == SHOW_OPTION_YES)
+ return new (alloc) ha_archive(table);
+ return NULL;
#endif
#ifdef HAVE_BLACKHOLE_DB
case DB_TYPE_BLACKHOLE_DB:
- return new (alloc) ha_blackhole(table);
+ if (have_blackhole_db == SHOW_OPTION_YES)
+ return new (alloc) ha_blackhole(table);
+ return NULL;
#endif
#ifdef HAVE_FEDERATED_DB
case DB_TYPE_FEDERATED_DB:
- return new (alloc) ha_federated(table);
+ if (have_federated_db == SHOW_OPTION_YES)
+ return new (alloc) ha_federated(table);
+ return NULL;
#endif
#ifdef HAVE_CSV_DB
case DB_TYPE_CSV_DB:
- return new (alloc) ha_tina(table);
+ if (have_csv_db == SHOW_OPTION_YES)
+ return new (alloc) ha_tina(table);
+ return NULL;
#endif
#ifdef HAVE_NDBCLUSTER_DB
case DB_TYPE_NDBCLUSTER:
- return new (alloc) ha_ndbcluster(table);
+ if (have_ndbcluster == SHOW_OPTION_YES)
+ return new (alloc) ha_ndbcluster(table);
+ return NULL;
#endif
case DB_TYPE_HEAP:
return new (alloc) ha_heap(table);
@@ -346,8 +363,6 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
/* Fall back to MyISAM */
case DB_TYPE_MYISAM:
return new (alloc) ha_myisam(table);
- case DB_TYPE_MRG_MYISAM:
- return new (alloc) ha_myisammrg(table);
}
}
@@ -513,7 +528,7 @@ int ha_panic(enum ha_panic_function flag)
if (have_federated_db == SHOW_OPTION_YES)
error|= federated_db_end();
#endif
-#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)
+#if defined(HAVE_ARCHIVE_DB)
if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end();
#endif
@@ -1911,7 +1926,8 @@ int ha_enable_transaction(THD *thd, bool on)
is an optimization hint that storage engine is free to ignore.
So, let's commit an open transaction (if any) now.
*/
- error= end_trans(thd, COMMIT);
+ if (!(error= ha_commit_stmt(thd)))
+ error= end_trans(thd, COMMIT);
}
DBUG_RETURN(error);
}
diff --git a/sql/item.cc b/sql/item.cc
index 659970f2a91..45a23322ef2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -949,7 +949,7 @@ void Item_splocal::print(String *str)
*****************************************************************************/
Item_case_expr::Item_case_expr(int case_expr_id)
- :Item_sp_variable(STRING_WITH_LEN("case_expr")),
+ :Item_sp_variable((char *) STRING_WITH_LEN("case_expr")),
m_case_expr_id(case_expr_id)
{
}
@@ -985,7 +985,7 @@ Item_case_expr::this_item_addr(THD *thd, Item **)
void Item_case_expr::print(String *str)
{
- str->append(STRING_WITH_LEN("case_expr@"));
+ VOID(str->append(STRING_WITH_LEN("case_expr@")));
str->qs_append(m_case_expr_id);
}
@@ -3843,7 +3843,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table);
case MYSQL_TYPE_BIT:
- return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0,
+ return new Field_bit_as_char(NULL, max_length, null_ptr, 0,
Field::NONE, name, table);
default:
/* This case should never be chosen */
@@ -4890,6 +4890,12 @@ int Item_ref::save_in_field(Field *to, bool no_conversions)
}
+void Item_ref::save_org_in_field(Field *field)
+{
+ (*ref)->save_org_in_field(field);
+}
+
+
void Item_ref::make_field(Send_field *field)
{
(*ref)->make_field(field);
diff --git a/sql/item.h b/sql/item.h
index 4b49ff907d3..eee9bc5b284 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1745,11 +1745,7 @@ public:
void make_field(Send_field *field);
bool fix_fields(THD *, Item **);
int save_in_field(Field *field, bool no_conversions);
- void save_org_in_field(Field *field)
- {
- (*ref)->save_org_in_field(field);
- null_value= (*ref)->null_value;
- }
+ void save_org_in_field(Field *field);
enum Item_result result_type () const { return (*ref)->result_type(); }
enum_field_types field_type() const { return (*ref)->field_type(); }
Field *get_tmp_table_field()
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 15614a32c39..bb3f6e8b231 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -3059,6 +3059,12 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
return FALSE;
}
+void Item_func_like::cleanup()
+{
+ canDoTurboBM= FALSE;
+ Item_bool_func2::cleanup();
+}
+
#ifdef USE_REGEX
bool
@@ -3765,6 +3771,7 @@ void Item_equal::update_used_tables()
longlong Item_equal::val_int()
{
+ Item_field *item_field;
if (cond_false)
return 0;
List_iterator_fast it(fields);
@@ -3772,10 +3779,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..15aebd2492c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1001,6 +1001,7 @@ public:
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "like"; }
bool fix_fields(THD *thd, Item **ref);
+ void cleanup();
};
#ifdef USE_REGEX
@@ -1150,6 +1151,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_func.cc b/sql/item_func.cc
index 272e77a4318..428a796682c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -888,7 +888,7 @@ String *Item_decimal_typecast::val_str(String *str)
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
if (null_value)
return NULL;
- my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
+ my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str);
return str;
}
@@ -4709,7 +4709,7 @@ Item_func_sp::sp_result_field(void) const
{
char *empty_name= (char *) "";
TABLE_SHARE *share;
- dummy_table->s= share= &dummy_table->share_not_to_be_used;
+ dummy_table->s= share= &dummy_table->share_not_to_be_used;
dummy_table->alias = empty_name;
dummy_table->maybe_null = maybe_null;
dummy_table->in_use= current_thd;
@@ -4742,8 +4742,13 @@ Item_func_sp::execute(Field **flp)
if (!(f= *flp))
{
- *flp= f= sp_result_field();
- f->move_field((f->pack_length() > sizeof(result_buf)) ?
+ if (!(*flp= f= sp_result_field()))
+ {
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ return 0;
+ }
+
+ f->move_field((f->pack_length() > sizeof(result_buf)) ?
sql_alloc(f->pack_length()) : result_buf);
f->null_ptr= (uchar *)&null_value;
f->null_bit= 1;
diff --git a/sql/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/lock.cc b/sql/lock.cc
index fe8dcb3aa5e..d0bfcfd7272 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -423,6 +423,127 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
}
+/*
+ Find duplicate lock in tables.
+
+ SYNOPSIS
+ mysql_lock_have_duplicate()
+ thd The current thread.
+ needle The table to check for duplicate lock.
+ haystack The list of tables to search for the dup lock.
+
+ NOTE
+ This is mainly meant for MERGE tables in INSERT ... SELECT
+ situations. The 'real', underlying tables can be found only after
+ the table is opened. The easier way is to check this after the
+ tables are locked.
+
+ RETURN
+ 1 A table from 'tables' matches a lock on 'table'.
+ 0 No duplicate lock is present.
+ -1 Error.
+*/
+
+TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
+ TABLE_LIST *haystack)
+{
+ uint count;
+ uint dup_pos;
+ TABLE *write_lock_used; /* dummy */
+ TABLE **tables1;
+ TABLE **tables2;
+ TABLE **table_ptr;
+ TABLE_LIST *tlist_ptr;
+ MYSQL_LOCK *sql_lock1;
+ MYSQL_LOCK *sql_lock2;
+ THR_LOCK_DATA **lock_data1;
+ THR_LOCK_DATA **end_data1;
+ THR_LOCK_DATA **lock_data2;
+ THR_LOCK_DATA **end_data2;
+ THR_LOCK *lock1;
+ DBUG_ENTER("mysql_lock_have_duplicate");
+
+ /* Table may not be defined for derived or view tables. */
+ if (! needle->table)
+ DBUG_RETURN(NULL);
+
+ /* Get lock(s) for needle. */
+ tables1= &needle->table;
+ if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
+ goto err0;
+
+ /* Count real tables in list. */
+ count=0;
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ count++;
+ /* Allocate a table array. */
+ if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
+ goto err1;
+ table_ptr= tables2;
+ /* Assign table pointers. */
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ *(table_ptr++)= tlist_ptr->table;
+ /* Get lock(s) for haystack. */
+ if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
+ goto err1;
+
+ /* Initialize duplicate position to an impossible value. */
+ dup_pos= UINT_MAX;
+ /*
+ Find a duplicate lock.
+ In case of merge tables, sql_lock1 can have more than 1 lock.
+ */
+ for (lock_data1= sql_lock1->locks,
+ end_data1= lock_data1 + sql_lock1->lock_count;
+ lock_data1 < end_data1;
+ lock_data1++)
+ {
+ lock1= (*lock_data1)->lock;
+ for (lock_data2= sql_lock2->locks,
+ end_data2= lock_data2 + sql_lock2->lock_count;
+ lock_data2 < end_data2;
+ lock_data2++)
+ {
+ if ((*lock_data2)->lock == lock1)
+ {
+ DBUG_PRINT("ingo", ("duplicate lock found"));
+ /* Change duplicate position to the real value. */
+ dup_pos= lock_data2 - sql_lock2->locks;
+ goto end;
+ }
+ }
+ }
+
+ end:
+ tlist_ptr= NULL; /* In case that no duplicate was found. */
+ if (dup_pos != UINT_MAX)
+ {
+ /* Duplicate found. Search the matching TABLE_LIST object. */
+ count= 0;
+ for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
+ {
+ if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
+ {
+ count+= tlist_ptr->table->file->lock_count();
+ if (count > dup_pos)
+ break;
+ }
+ }
+ }
+ my_free((gptr) sql_lock2, MYF(0));
+ my_free((gptr) sql_lock1, MYF(0));
+ DBUG_RETURN(tlist_ptr);
+
+ err1:
+ my_free((gptr) sql_lock1, MYF(0));
+ err0:
+ /* This non-null but special value indicates error, if caller cares. */
+ DBUG_RETURN(needle);
+}
+
+
/* unlock a set of external */
static int unlock_external(THD *thd, TABLE **table,uint count)
@@ -460,6 +581,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
MYSQL_LOCK *sql_lock;
THR_LOCK_DATA **locks;
TABLE **to;
+ DBUG_ENTER("get_lock_data");
*write_lock_used=0;
for (i=tables=lock_count=0 ; i < count ; i++)
@@ -488,7 +610,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
my_malloc(sizeof(*sql_lock)+
sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
MYF(0))))
- return 0;
+ DBUG_RETURN(0);
locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
to=sql_lock->table=(TABLE**) (locks+tables);
sql_lock->table_count=lock_count;
@@ -508,7 +630,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
{
my_error(ER_OPEN_AS_READONLY, MYF(0), table->alias);
my_free((gptr) sql_lock,MYF(0));
- return 0;
+ DBUG_RETURN(0);
}
}
THR_LOCK_DATA **org_locks = locks;
@@ -518,7 +640,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
for ( ; org_locks != locks ; org_locks++)
(*org_locks)->debug_print_param= (void *) table;
}
- return sql_lock;
+ DBUG_RETURN(sql_lock);
}
@@ -601,6 +723,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
char key[MAX_DBKEY_LENGTH];
char *db= table_list->db;
uint key_length;
+ HASH_SEARCH_STATE state;
DBUG_ENTER("lock_table_name");
DBUG_PRINT("enter",("db: %s name: %s", db, table_list->table_name));
@@ -611,9 +734,9 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
/* Only insert the table if we haven't insert it already */
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state);
table ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table = (TABLE*) hash_next(&open_cache, (byte*)key, key_length, &state))
if (table->in_use == thd)
DBUG_RETURN(0);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 056bcca1a02..a07411971ce 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -114,13 +114,24 @@ static char *pretty_print_str(char *packet, char *str, int len)
/*
- slave_load_file_stem()
+ Creates a temporary name for load data infile:
+
+ SYNOPSIS
+ slave_load_file_stem()
+ buf Store new filename here
+ file_id File_id (part of file name)
+ event_server_id Event_id (part of file name)
+ ext Extension for file name
+
+ RETURN
+ Pointer to start of extension
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static inline char* slave_load_file_stem(char*buf, uint file_id,
- int event_server_id)
+static char *slave_load_file_stem(char *buf, uint file_id,
+ int event_server_id, const char *ext)
{
+ char *res;
fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME);
to_unix_path(buf);
@@ -129,7 +140,9 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
*buf++ = '-';
buf = int10_to_str(event_server_id, buf, 10);
*buf++ = '-';
- return int10_to_str(file_id, buf, 10);
+ res= int10_to_str(file_id, buf, 10);
+ strmov(res, ext); // Add extension last
+ return res; // Pointer to extension
}
#endif
@@ -901,7 +914,6 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
/* Pretty-print event common header if header is exactly 19 bytes */
if (print_event_info->common_header_len == LOG_EVENT_MINIMAL_HEADER_LEN)
{
- DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from);
fprintf(file, "# Position Timestamp Type Master ID "
"Size Master Pos Flags \n");
fprintf(file, "# %8.8lx %02x %02x %02x %02x %02x "
@@ -927,7 +939,6 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
if (i % 16 == 15)
{
- DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from);
fprintf(file, "# %8.8lx %-48.48s |%16s|\n",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
@@ -941,12 +952,10 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info)
*c= '\0';
/* Non-full last line */
- if (hex_string[0]) {
- DBUG_ASSERT(hexdump_from == (unsigned long) hexdump_from);
+ if (hex_string[0])
fprintf(file, "# %8.8lx %-48.48s |%s|\n# ",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
- }
}
}
@@ -3253,6 +3262,10 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
case INSERT_ID_EVENT:
msg="INSERT_ID";
break;
+ case INVALID_INT_EVENT:
+ default: // cannot happen
+ msg="INVALID_INT";
+ break;
}
fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff));
fflush(file);
@@ -4160,16 +4173,15 @@ void Create_file_log_event::pack_info(Protocol *protocol)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
{
- char proc_info[17+FN_REFLEN+10], *fname_buf= proc_info+17;
- char *p;
+ char proc_info[17+FN_REFLEN+10], *fname_buf;
+ char *ext;
int fd = -1;
IO_CACHE file;
int error = 1;
bzero((char*)&file, sizeof(file));
- p = slave_load_file_stem(fname_buf, file_id, server_id);
- strmov(p, ".info"); // strmov takes less code than memcpy
- strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0
+ fname_buf= strmov(proc_info, "Making temp file ");
+ ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info");
thd->proc_info= proc_info;
my_delete(fname_buf, MYF(0)); // old copy may exist already
if ((fd= my_create(fname_buf, CREATE_MODE,
@@ -4178,19 +4190,21 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno,
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
goto err;
}
// a trick to avoid allocating another buffer
- strmov(p, ".data");
- fname = fname_buf;
- fname_len = (uint)(p-fname) + 5;
+ fname= fname_buf;
+ fname_len= (uint) (strmov(ext, ".data") - fname);
if (write_base(&file))
{
- strmov(p, ".info"); // to have it right in the error message
+ strmov(ext, ".info"); // to have it right in the error message
slave_print_error(rli,my_errno,
- "Error in Create_file event: could not write to file '%s'",
+ "Error in Create_file event: could not write to file "
+ "'%s'",
fname_buf);
goto err;
}
@@ -4203,12 +4217,16 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
MYF(MY_WME))) < 0)
{
- slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno,
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Error in Create_file event: write to '%s' failed", fname_buf);
+ slave_print_error(rli,my_errno,
+ "Error in Create_file event: write to '%s' failed",
+ fname_buf);
goto err;
}
error=0; // Everything is ok
@@ -4332,13 +4350,12 @@ int Append_block_log_event::get_create_or_append() const
int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
{
char proc_info[17+FN_REFLEN+10], *fname= proc_info+17;
- char *p= slave_load_file_stem(fname, file_id, server_id);
int fd;
int error = 1;
DBUG_ENTER("Append_block_log_event::exec_event");
- memcpy(p, ".data", 6);
- strnmov(proc_info, STRING_WITH_LEN("Making temp file ")); // no end 0
+ fname= strmov(proc_info, "Making temp file ");
+ slave_load_file_stem(fname, file_id, server_id, ".data");
thd->proc_info= proc_info;
if (get_create_or_append())
{
@@ -4464,10 +4481,9 @@ void Delete_file_log_event::pack_info(Protocol *protocol)
int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
{
char fname[FN_REFLEN+10];
- char *p= slave_load_file_stem(fname, file_id, server_id);
- memcpy(p, ".data", 6);
+ char *ext= slave_load_file_stem(fname, file_id, server_id, ".data");
(void) my_delete(fname, MYF(MY_WME));
- memcpy(p, ".info", 6);
+ strmov(ext, ".info");
(void) my_delete(fname, MYF(MY_WME));
return Log_event::exec_event(rli);
}
@@ -4560,19 +4576,21 @@ void Execute_load_log_event::pack_info(Protocol *protocol)
int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
{
char fname[FN_REFLEN+10];
- char *p= slave_load_file_stem(fname, file_id, server_id);
+ char *ext;
int fd;
- int error = 1;
+ int error= 1;
IO_CACHE file;
- Load_log_event* lev = 0;
+ Load_log_event *lev= 0;
- memcpy(p, ".info", 6);
+ ext= slave_load_file_stem(fname, file_id, server_id, ".info");
if ((fd = my_open(fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
MYF(MY_WME))) < 0 ||
init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Error in Exec_load event: could not open file '%s'", fname);
+ slave_print_error(rli,my_errno,
+ "Error in Exec_load event: could not open file '%s'",
+ fname);
goto err;
}
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
@@ -4580,7 +4598,9 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
rli->relay_log.description_event_for_exec)) ||
lev->get_type_code() != NEW_LOAD_EVENT)
{
- slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname);
+ slave_print_error(rli,0,
+ "Error in Exec_load event: file '%s' appears corrupted",
+ fname);
goto err;
}
@@ -4625,7 +4645,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
fd= -1;
}
(void) my_delete(fname, MYF(MY_WME));
- memcpy(p, ".data", 6);
+ memcpy(ext, ".data", 6);
(void) my_delete(fname, MYF(MY_WME));
error = 0;
@@ -4823,11 +4843,10 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
memcpy(p, query, fn_pos_start);
p+= fn_pos_start;
fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'")));
- p= slave_load_file_stem(p, file_id, server_id);
- fname_end= (p= strmake(p, STRING_WITH_LEN(".data")));
+ p= slave_load_file_stem(p, file_id, server_id, ".data");
+ fname_end= p= strend(p); // Safer than p=p+5
*(p++)='\'';
- switch (dup_handling)
- {
+ switch (dup_handling) {
case LOAD_DUP_IGNORE:
p= strmake(p, STRING_WITH_LEN(" IGNORE"));
break;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index aac3511ef9d..ca2cda0f7c6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -986,7 +986,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list,
const char *db_name,
const char *table_name);
-TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table);
@@ -1274,6 +1274,8 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
void mysql_lock_abort(THD *thd, TABLE *table);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
+TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
+ TABLE_LIST *haystack);
bool lock_global_read_lock(THD *thd);
void unlock_global_read_lock(THD *thd);
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index aaa467603f5..80b22f726ae 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -385,6 +385,7 @@ my_bool sp_automatic_privileges= 1;
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
#endif
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
+uint mysqld_port_timeout;
uint delay_key_write_options, protocol_version;
uint lower_case_table_names;
uint tc_heuristic_recover= 0;
@@ -1357,7 +1358,12 @@ static void network_init(void)
struct sockaddr_un UNIXaddr;
#endif
int arg=1;
+ int ret;
+ uint waited;
+ uint this_wait;
+ uint retry;
DBUG_ENTER("server_init");
+ LINT_INIT(ret);
set_ports();
@@ -1383,8 +1389,26 @@ static void network_init(void)
*/
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
#endif /* __WIN__ */
- if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
- sizeof(IPaddr)) < 0)
+ /*
+ Sometimes the port is not released fast enough when stopping and
+ restarting the server. This happens quite often with the test suite
+ on busy Linux systems. Retry to bind the address at these intervals:
+ Sleep intervals: 1, 2, 4, 6, 9, 13, 17, 22, ...
+ Retry at second: 1, 3, 7, 13, 22, 35, 52, 74, ...
+ Limit the sequence by mysqld_port_timeout (set --port-open-timeout=#).
+ */
+ for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+ {
+ if (((ret= bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
+ sizeof(IPaddr))) >= 0) ||
+ (socket_errno != SOCKET_EADDRINUSE) ||
+ (waited >= mysqld_port_timeout))
+ break;
+ sql_print_information("Retrying bind on TCP/IP port %u", mysqld_port);
+ this_wait= retry * retry / 3 + 1;
+ sleep(this_wait);
+ }
+ if (ret < 0)
{
DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
sql_perror("Can't start server: Bind on TCP/IP port");
@@ -1589,7 +1613,7 @@ void end_thread(THD *thd, bool put_in_cache)
wake_thread--;
thd=thread_cache.get();
thd->real_id=pthread_self();
- thd->thread_stack= (char *) &thd;
+ thd->thread_stack= (char*) &thd; // For store_globals
(void) thd->store_globals();
thd->thr_create_time= time(NULL);
threads.append(thd);
@@ -3298,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
@@ -4552,7 +4581,8 @@ enum options_mysqld
OPT_TIMED_MUTEXES,
OPT_OLD_STYLE_USER_LIMITS,
OPT_LOG_SLOW_ADMIN_STATEMENTS,
- OPT_TABLE_LOCK_WAIT_TIMEOUT
+ OPT_TABLE_LOCK_WAIT_TIMEOUT,
+ OPT_PORT_OPEN_TIMEOUT
};
@@ -4637,7 +4667,7 @@ Disable with --skip-bdb (will save memory).",
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
- "Don't use client side character set value sent during handshake.",
+ "Don't ignore client side character set value sent during handshake.",
(gptr*) &opt_character_set_client_handshake,
(gptr*) &opt_character_set_client_handshake,
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
@@ -5092,6 +5122,10 @@ Disable with --skip-ndbcluster (will save memory).",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port,
(gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT,
+ "Maximum time in seconds to wait for the port to become free. "
+ "(Default: no wait)", (gptr*) &mysqld_port_timeout,
+ (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"relay-log", OPT_RELAY_LOG,
"The location and name to use for relay logs.",
(gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
@@ -6323,7 +6357,7 @@ static void mysql_init_variables(void)
#else
have_example_db= SHOW_OPTION_NO;
#endif
-#if defined(HAVE_ARCHIVE_DB) && !defined(__NETWARE__)
+#if defined(HAVE_ARCHIVE_DB)
have_archive_db= SHOW_OPTION_YES;
#else
have_archive_db= SHOW_OPTION_NO;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 221a343053d..7c4f5fbe218 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -652,7 +652,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond,
int *error)
-
{
SQL_SELECT *select;
DBUG_ENTER("make_select");
@@ -5738,6 +5737,7 @@ bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List- *fields)
/*
Create quick select from ref/ref_or_null scan.
+
SYNOPSIS
get_quick_select_for_ref()
thd Thread handle
@@ -5757,15 +5757,18 @@ bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List
- *fields)
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
TABLE_REF *ref, ha_rows records)
{
- MEM_ROOT *old_root= thd->mem_root;
- /* The following call may change thd->mem_root */
- QUICK_RANGE_SELECT *quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0);
- /* save mem_root set by QUICK_RANGE_SELECT constructor */
- MEM_ROOT *alloc= thd->mem_root;
+ MEM_ROOT *old_root, *alloc;
+ QUICK_RANGE_SELECT *quick;
KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part;
QUICK_RANGE *range;
uint part;
+
+ old_root= thd->mem_root;
+ /* The following call may change thd->mem_root */
+ quick= new QUICK_RANGE_SELECT(thd, table, ref->key, 0);
+ /* save mem_root set by QUICK_RANGE_SELECT constructor */
+ alloc= thd->mem_root;
/*
return back default mem_root (thd->mem_root) changed by
QUICK_RANGE_SELECT constructor
@@ -5775,10 +5778,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
if (!quick)
return 0; /* no ranges found */
if (quick->init())
- {
- delete quick;
goto err;
- }
quick->records= records;
if (cp_buffer_from_ref(thd,ref) && thd->is_fatal_error ||
@@ -7112,7 +7112,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
ha_rows cur_records;
SEL_ARG *cur_index_tree= NULL;
ha_rows cur_quick_prefix_records= 0;
- uint cur_param_idx;
+ uint cur_param_idx=MAX_KEY;
key_map cur_used_key_parts;
uint pk= param->table->s->primary_key;
@@ -7328,6 +7328,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost))
{
+ DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY);
index_info= cur_index_info;
index= cur_index;
best_read_cost= cur_read_cost;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index f84058f3b64..cdb00ea7d0c 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -705,7 +705,7 @@ class SQL_SELECT :public Sql_alloc {
class FT_SELECT: public QUICK_RANGE_SELECT {
public:
FT_SELECT(THD *thd, TABLE *table, uint key) :
- QUICK_RANGE_SELECT (thd, table, key, 1) { init(); }
+ QUICK_RANGE_SELECT (thd, table, key, 1) { VOID(init()); }
~FT_SELECT() { file->ft_end(); }
int init() { return error=file->ft_init(); }
int reset() { return 0; }
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 37acce2934b..ed8e694dcb7 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -180,14 +180,14 @@ int opt_sum_query(TABLE_LIST *tables, List
- &all_fields,COND *conds)
indexes to find the key.
*/
Item *expr=item_sum->args[0];
- if (expr->type() == Item::FIELD_ITEM)
+ if (expr->real_item()->type() == Item::FIELD_ITEM)
{
byte key_buff[MAX_KEY_LENGTH];
TABLE_REF ref;
uint range_fl, prefix_len;
ref.key_buff= key_buff;
- Item_field *item_field= ((Item_field*) expr);
+ Item_field *item_field= (Item_field*) (expr->real_item());
TABLE *table= item_field->field->table;
/*
@@ -267,14 +267,14 @@ int opt_sum_query(TABLE_LIST *tables, List
- &all_fields,COND *conds)
indexes to find the key.
*/
Item *expr=item_sum->args[0];
- if (expr->type() == Item::FIELD_ITEM)
+ if (expr->real_item()->type() == Item::FIELD_ITEM)
{
byte key_buff[MAX_KEY_LENGTH];
TABLE_REF ref;
- uint range_fl, prefix_len;
+ uint range_fl, prefix_len;
ref.key_buff= key_buff;
- Item_field *item_field= ((Item_field*) expr);
+ Item_field *item_field= (Item_field*) (expr->real_item());
TABLE *table= item_field->field->table;
/*
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 69757e0be06..041b770ac0b 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -944,6 +944,6 @@ File_parser_dummy_hook::process_unknown_string(char *&unknown_key,
char *end)
{
DBUG_ENTER("file_parser_dummy_hook::process_unknown_string");
- DBUG_PRINT("info", ("unknown key:%60s", unknown_key));
+ DBUG_PRINT("info", ("Unknown key: '%60s'", unknown_key));
DBUG_RETURN(FALSE);
}
diff --git a/sql/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/repl_failsafe.cc b/sql/repl_failsafe.cc
index d76be2ec2e4..5cdd24afba4 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -929,7 +929,8 @@ bool load_master_data(THD* thd)
host was specified; there could have been a problem when replication
started, which led to relay log's IO_CACHE to not be inited.
*/
- flush_master_info(active_mi, 0);
+ if (flush_master_info(active_mi, 0))
+ sql_print_error("Failed to flush master info file");
}
mysql_free_result(master_status_res);
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 632c37d2296..f10da4ad9ba 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2518,7 +2518,6 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
{
- pthread_mutex_t *lock_log= mysql_bin_log.get_log_lock();
sync_binlog_period= (ulong) var->save_result.ulonglong_value;
return 0;
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index efa7860f251..577173a36a1 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5175,8 +5175,8 @@ ER_SP_WRONG_NO_OF_FETCH_ARGS
eng "Incorrect number of FETCH variables"
ger "Falsche Anzahl von FETCH-Variablen"
ER_SP_FETCH_NO_DATA 02000
- eng "No data to FETCH"
- ger "Keine Daten mit FETCH abzuholen"
+ eng "No data - zero rows fetched, selected, or processed"
+ ger "Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet"
ER_SP_DUP_PARAM 42000
eng "Duplicate parameter: %s"
ger "Doppelter Parameter: %s"
@@ -5375,7 +5375,7 @@ ER_WSAS_FAILED
eng "WSAStartup Failed"
ger "WSAStartup fehlgeschlagen"
ER_DIFF_GROUPS_PROC
- eng "Can't handle procedures with differents groups yet"
+ eng "Can't handle procedures with different groups yet"
ger "Kann Prozeduren mit unterschiedlichen Gruppen noch nicht verarbeiten"
ER_NO_GROUP_FOR_PROC
eng "Select must have a group with this procedure"
diff --git a/sql/slave.cc b/sql/slave.cc
index 5e1c838730c..3795cbaf7c0 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2017,7 +2017,8 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
" to the relay log, "
"SHOW SLAVE STATUS may be inaccurate");
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
- flush_master_info(mi, 1);
+ if (flush_master_info(mi, 1))
+ sql_print_error("Failed to flush master info file");
delete ev;
}
else
@@ -2555,7 +2556,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
-
+
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
DBUG_RETURN(TRUE);
}
@@ -2563,8 +2564,13 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(FALSE);
}
-
-bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
+/*
+ RETURN
+ 2 - flush relay log failed
+ 1 - flush master info failed
+ 0 - all ok
+*/
+int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
{
IO_CACHE* file = &mi->file;
char lbuf[22];
@@ -2583,8 +2589,9 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
When we come to this place in code, relay log may or not be initialized;
the caller is responsible for setting 'flush_relay_log_cache' accordingly.
*/
- if (flush_relay_log_cache)
- flush_io_cache(mi->rli.relay_log.get_log_file());
+ if (flush_relay_log_cache &&
+ flush_io_cache(mi->rli.relay_log.get_log_file()))
+ DBUG_RETURN(2);
/*
We flushed the relay log BEFORE the master.info file, because if we crash
@@ -2596,13 +2603,13 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
*/
/*
- In certain cases this code may create master.info files that seems
- corrupted, because of extra lines filled with garbage in the end
- file (this happens if new contents take less space than previous
- contents of file). But because of number of lines in the first line
+ In certain cases this code may create master.info files that seems
+ corrupted, because of extra lines filled with garbage in the end
+ file (this happens if new contents take less space than previous
+ contents of file). But because of number of lines in the first line
of file we don't care about this garbage.
*/
-
+
my_b_seek(file, 0L);
my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
LINES_IN_MASTER_INFO_WITH_SSL,
@@ -2611,8 +2618,7 @@ bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
mi->password, mi->port, mi->connect_retry,
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
mi->ssl_cipher, mi->ssl_key);
- flush_io_cache(file);
- DBUG_RETURN(0);
+ DBUG_RETURN(-flush_io_cache(file));
}
@@ -3644,7 +3650,11 @@ reconnect done to recover from failed read");
sql_print_error("Slave I/O thread could not queue event from master");
goto err;
}
- flush_master_info(mi, 1); /* sure that we can flush the relay log */
+ if (flush_master_info(mi, 1))
+ {
+ sql_print_error("Failed to flush master info file");
+ goto err;
+ }
/*
See if the relay logs take too much space.
We don't lock mi->rli.log_space_lock here; this dirty read saves time
diff --git a/sql/slave.h b/sql/slave.h
index 4d3c338680d..040ce4eaf85 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -500,7 +500,7 @@ typedef struct st_table_rule_ent
int init_slave();
void init_slave_skip_errors(const char* arg);
-bool flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache);
+int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache);
bool flush_relay_log_info(RELAY_LOG_INFO* rli);
int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
diff --git a/sql/sp.cc b/sql/sp.cc
index d5b93f0d2f2..37a9c02124e 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -399,14 +399,14 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
const char *body, st_sp_chistics &chistics,
const char *definer, longlong created, longlong modified)
{
- LEX *oldlex= thd->lex, newlex;
- sp_rcontext *save_spcont= thd->spcont;
+ LEX *old_lex= thd->lex, newlex;
String defstr;
char olddb[128];
bool dbchanged;
ulong old_sql_mode= thd->variables.sql_mode;
- ha_rows select_limit= thd->variables.select_limit;
- int ret= SP_INTERNAL_ERROR;
+ ha_rows old_select_limit= thd->variables.select_limit;
+ sp_rcontext *old_spcont= thd->spcont;
+ int ret;
thd->variables.sql_mode= sql_mode;
thd->variables.select_limit= HA_POS_ERROR;
@@ -422,7 +422,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
returns, strlen(returns),
body, strlen(body),
&chistics))
+ {
+ ret= SP_INTERNAL_ERROR;
goto end;
+ }
dbchanged= FALSE;
if ((ret= sp_use_new_db(thd, name->m_db.str, olddb, sizeof(olddb),
@@ -451,10 +454,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
(*sphp)->optimize();
}
end:
- thd->spcont= save_spcont;
+ thd->spcont= old_spcont;
thd->variables.sql_mode= old_sql_mode;
- thd->variables.select_limit= select_limit;
- thd->lex= oldlex;
+ thd->variables.select_limit= old_select_limit;
+ thd->lex= old_lex;
return ret;
}
@@ -477,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");
@@ -926,7 +929,6 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
ulong depth= (type == TYPE_ENUM_PROCEDURE ?
thd->variables.max_sp_recursion_depth :
0);
-
DBUG_ENTER("sp_find_routine");
DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d",
name->m_db.length, name->m_db.str,
@@ -936,6 +938,11 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
if ((sp= sp_cache_lookup(cp, name)))
{
ulong level;
+ sp_head *new_sp;
+ const char *returns= "";
+ char definer[USER_HOST_BUFF_SIZE];
+ String retstr(64);
+
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
if (sp->m_first_free_instance)
{
@@ -946,7 +953,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
DBUG_ASSERT(!(sp->m_first_free_instance->m_flags & sp_head::IS_INVOKED));
if (sp->m_first_free_instance->m_recursion_level > depth)
{
- sp->recursion_level_error();
+ sp->recursion_level_error(thd);
DBUG_RETURN(0);
}
DBUG_RETURN(sp->m_first_free_instance);
@@ -954,37 +961,32 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
level= sp->m_last_cached_sp->m_recursion_level + 1;
if (level > depth)
{
- sp->recursion_level_error();
+ sp->recursion_level_error(thd);
DBUG_RETURN(0);
}
+
+ strxmov(definer, sp->m_definer_user.str, "@",
+ sp->m_definer_host.str, NullS);
+ if (type == TYPE_ENUM_FUNCTION)
{
- sp_head *new_sp;
- const char *returns= "";
- char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
- String retstr(64);
- strxmov(definer, sp->m_definer_user.str, "@",
- sp->m_definer_host.str, NullS);
- if (type == TYPE_ENUM_FUNCTION)
- {
- sp_returns_type(thd, retstr, sp);
- returns= retstr.ptr();
- }
- if (db_load_routine(thd, type, name, &new_sp,
- sp->m_sql_mode, sp->m_params.str, returns,
- sp->m_body.str, *sp->m_chistics, definer,
- sp->m_created, sp->m_modified) == SP_OK)
- {
- sp->m_last_cached_sp->m_next_cached_sp= new_sp;
- new_sp->m_recursion_level= level;
- new_sp->m_first_instance= sp;
- sp->m_last_cached_sp= sp->m_first_free_instance= new_sp;
- DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x",
+ sp_returns_type(thd, retstr, sp);
+ returns= retstr.ptr();
+ }
+ if (db_load_routine(thd, type, name, &new_sp,
+ sp->m_sql_mode, sp->m_params.str, returns,
+ sp->m_body.str, *sp->m_chistics, definer,
+ sp->m_created, sp->m_modified) == SP_OK)
+ {
+ sp->m_last_cached_sp->m_next_cached_sp= new_sp;
+ new_sp->m_recursion_level= level;
+ new_sp->m_first_instance= sp;
+ sp->m_last_cached_sp= sp->m_first_free_instance= new_sp;
+ DBUG_PRINT("info", ("added level: 0x%lx, level: %lu, flags %x",
(ulong)new_sp, new_sp->m_recursion_level,
new_sp->m_flags));
- DBUG_RETURN(new_sp);
- }
- DBUG_RETURN(0);
+ DBUG_RETURN(new_sp);
}
+ DBUG_RETURN(0);
}
if (!cache_only)
{
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 88d3ed83278..8853ee97e98 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -24,6 +24,15 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
+/*
+ Sufficient max length of printed destinations and frame offsets (all uints).
+*/
+#define SP_INSTR_UINT_MAXLEN 8
+#define SP_STMT_PRINT_MAXLEN 40
+
+
+#include
+
Item_result
sp_map_result_type(enum enum_field_types type)
{
@@ -421,7 +430,8 @@ sp_head::operator delete(void *ptr, size_t size)
sp_head::sp_head()
:Query_arena(&main_mem_root, INITIALIZED_FOR_SP),
m_flags(0), m_recursion_level(0), m_next_cached_sp(0),
- m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this)
+ m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this),
+ m_cont_level(0)
{
m_return_field_def.charset = NULL;
@@ -430,6 +440,7 @@ sp_head::sp_head()
DBUG_ENTER("sp_head::sp_head");
m_backpatch.empty();
+ m_cont_backpatch.empty();
m_lex.empty();
hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
@@ -867,17 +878,17 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
SYNOPSIS
sp_head::recursion_level_error()
+ thd Thread handle
NOTE
For functions and triggers we return error about prohibited recursion.
For stored procedures we return about reaching recursion limit.
*/
-void sp_head::recursion_level_error()
+void sp_head::recursion_level_error(THD *thd)
{
if (m_type == TYPE_ENUM_PROCEDURE)
{
- THD *thd= current_thd;
my_error(ER_SP_RECURSION_LIMIT, MYF(0),
thd->variables.max_sp_recursion_depth,
m_name.str);
@@ -928,14 +939,15 @@ sp_head::execute(THD *thd)
DBUG_ASSERT(!(m_flags & IS_INVOKED));
m_flags|= IS_INVOKED;
m_first_instance->m_first_free_instance= m_next_cached_sp;
- DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x",
- (ulong)m_first_instance, this, m_next_cached_sp,
- (m_next_cached_sp ?
- m_next_cached_sp->m_recursion_level :
- 0),
- (m_next_cached_sp ?
- m_next_cached_sp->m_flags :
- 0)));
+ if (m_next_cached_sp)
+ {
+ DBUG_PRINT("info",
+ ("first free for 0x%lx ++: 0x%lx->0x%lx level: %lu flags %x",
+ (ulong)m_first_instance, (ulong) this,
+ (ulong) m_next_cached_sp,
+ m_next_cached_sp->m_recursion_level,
+ m_next_cached_sp->m_flags));
+ }
/*
Check that if there are not any instances after this one then
pointer to the last instance points on this instance or if there are
@@ -1103,13 +1115,15 @@ sp_head::execute(THD *thd)
state= EXECUTED;
done:
- DBUG_PRINT("info", ("err_status=%d killed=%d query_error=%d",
+ DBUG_PRINT("info", ("err_status: %d killed: %d query_error: %d",
err_status, thd->killed, thd->query_error));
if (thd->killed)
err_status= TRUE;
- /* If the DB has changed, the pointer has changed too, but the
- original thd->db will then have been freed */
+ /*
+ If the DB has changed, the pointer has changed too, but the
+ original thd->db will then have been freed
+ */
if (dbchanged)
{
/*
@@ -1120,10 +1134,11 @@ sp_head::execute(THD *thd)
err_status|= mysql_change_db(thd, olddb, 1);
}
m_flags&= ~IS_INVOKED;
- DBUG_PRINT("info", ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
- (ulong)m_first_instance,
- m_first_instance->m_first_free_instance, this,
- m_recursion_level, m_flags));
+ DBUG_PRINT("info",
+ ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x",
+ (ulong) m_first_instance,
+ (ulong) m_first_instance->m_first_free_instance,
+ (ulong) this, m_recursion_level, m_flags));
/*
Check that we have one of following:
@@ -1133,7 +1148,7 @@ sp_head::execute(THD *thd)
2) There are some free instances which mean that first free instance
should go just after this one and recursion level of that free instance
- should be on 1 more then recursion leven of this instance.
+ should be on 1 more then recursion level of this instance.
*/
DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 &&
this == m_first_instance->m_last_cached_sp &&
@@ -1722,6 +1737,39 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
}
+void
+sp_head::new_cont_backpatch(sp_instr_jump_if_not *i)
+{
+ m_cont_level+= 1;
+ if (i)
+ {
+ /* Use the cont. destination slot to store the level */
+ i->m_cont_dest= m_cont_level;
+ (void)m_cont_backpatch.push_front(i);
+ }
+}
+
+void
+sp_head::add_cont_backpatch(sp_instr_jump_if_not *i)
+{
+ i->m_cont_dest= m_cont_level;
+ (void)m_cont_backpatch.push_front(i);
+}
+
+void
+sp_head::do_cont_backpatch()
+{
+ uint dest= instructions();
+ uint lev= m_cont_level--;
+ sp_instr_jump_if_not *i;
+
+ while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev)
+ {
+ i->m_cont_dest= dest;
+ (void)m_cont_backpatch.pop();
+ }
+}
+
void
sp_head::set_info(longlong created, longlong modified,
st_sp_chistics *chistics, ulong sql_mode)
@@ -1741,29 +1789,21 @@ sp_head::set_info(longlong created, longlong modified,
void
-sp_head::set_definer(char *definer, uint definerlen)
+sp_head::set_definer(const char *definer, uint definerlen)
{
- char *p= strrchr(definer, '@');
+ 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= strmake_root(mem_root, "", 0);
- m_definer_user.length= 0;
-
- m_definer_host.str= strmake_root(mem_root, "", 0);
- 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;
}
@@ -1845,9 +1885,9 @@ sp_head::show_create_procedure(THD *thd)
byte *sql_mode_str;
ulong sql_mode_len;
bool full_access;
-
DBUG_ENTER("sp_head::show_create_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str));
+
LINT_INIT(sql_mode_str);
LINT_INIT(sql_mode_len);
@@ -1944,7 +1984,10 @@ sp_head::show_create_function(THD *thd)
/*
- TODO: what does this do??
+ Do some minimal optimization of the code:
+ 1) Mark used instructions
+ 1.1) While doing this, shortcut jumps to jump instructions
+ 2) Compact the code, removing unused instructions
*/
void sp_head::optimize()
@@ -1967,7 +2010,7 @@ void sp_head::optimize()
else
{
if (src != dst)
- {
+ { // Move the instruction and update prev. jumps
sp_instr *ibp;
List_iterator_fast li(bp);
@@ -1975,8 +2018,7 @@ void sp_head::optimize()
while ((ibp= li++))
{
sp_instr_jump *ji= static_cast(ibp);
- if (ji->m_dest == src)
- ji->m_dest= dst;
+ ji->set_destination(src, dst);
}
}
i->opt_move(dst, &bp);
@@ -2200,12 +2242,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
DBUG_RETURN(res);
}
-/*
- Sufficient max length of printed destinations and frame offsets (all uints).
-*/
-#define SP_INSTR_UINT_MAXLEN 8
-#define SP_STMT_PRINT_MAXLEN 40
void
sp_instr_stmt::print(String *str)
{
@@ -2227,16 +2264,16 @@ sp_instr_stmt::print(String *str)
/* Copy the query string and replace '\n' with ' ' in the process */
for (i= 0 ; i < len ; i++)
{
- if (m_query.str[i] == '\n')
- str->qs_append(' ');
- else
- str->qs_append(m_query.str[i]);
+ char c= m_query.str[i];
+ if (c == '\n')
+ c= ' ';
+ str->qs_append(c);
}
if (m_query.length > SP_STMT_PRINT_MAXLEN)
str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */
str->qs_append('"');
}
-#undef SP_STMT_PRINT_MAXLEN
+
int
sp_instr_stmt::exec_core(THD *thd, uint *nextp)
@@ -2414,67 +2451,6 @@ sp_instr_jump::opt_move(uint dst, List *bp)
}
-/*
- sp_instr_jump_if class functions
-*/
-
-int
-sp_instr_jump_if::execute(THD *thd, uint *nextp)
-{
- DBUG_ENTER("sp_instr_jump_if::execute");
- DBUG_PRINT("info", ("destination: %u", m_dest));
- DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
-}
-
-int
-sp_instr_jump_if::exec_core(THD *thd, uint *nextp)
-{
- Item *it;
- int res;
-
- it= sp_prepare_func_item(thd, &m_expr);
- if (!it)
- res= -1;
- else
- {
- res= 0;
- if (it->val_bool())
- *nextp = m_dest;
- else
- *nextp = m_ip+1;
- }
-
- return res;
-}
-
-void
-sp_instr_jump_if::print(String *str)
-{
- /* jump_if dest ... */
- if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too
- return;
- str->qs_append(STRING_WITH_LEN("jump_if "));
- str->qs_append(m_dest);
- str->qs_append(' ');
- m_expr->print(str);
-}
-
-uint
-sp_instr_jump_if::opt_mark(sp_head *sp)
-{
- sp_instr *i;
-
- marked= 1;
- if ((i= sp->get_instr(m_dest)))
- {
- m_dest= i->opt_shortcut_jump(sp, this);
- m_optdest= sp->get_instr(m_dest);
- }
- sp->opt_mark(m_dest);
- return m_ip+1;
-}
-
-
/*
sp_instr_jump_if_not class functions
*/
@@ -2496,7 +2472,10 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
it= sp_prepare_func_item(thd, &m_expr);
if (! it)
+ {
res= -1;
+ *nextp = m_cont_dest;
+ }
else
{
res= 0;
@@ -2514,11 +2493,13 @@ void
sp_instr_jump_if_not::print(String *str)
{
/* jump_if_not dest ... */
- if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too
+ if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too
return;
str->qs_append(STRING_WITH_LEN("jump_if_not "));
str->qs_append(m_dest);
- str->qs_append(' ');
+ str->append('(');
+ str->qs_append(m_cont_dest);
+ str->append(") ");
m_expr->print(str);
}
@@ -2535,9 +2516,35 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
m_optdest= sp->get_instr(m_dest);
}
sp->opt_mark(m_dest);
+ if ((i= sp->get_instr(m_cont_dest)))
+ {
+ m_cont_dest= i->opt_shortcut_jump(sp, this);
+ m_cont_optdest= sp->get_instr(m_cont_dest);
+ }
+ sp->opt_mark(m_cont_dest);
return m_ip+1;
}
+void
+sp_instr_jump_if_not::opt_move(uint dst, List *bp)
+{
+ /*
+ cont. destinations may point backwards after shortcutting jumps
+ during the mark phase. If it's still pointing forwards, only
+ push this for backpatching if sp_instr_jump::opt_move() will not
+ do it (i.e. if the m_dest points backwards).
+ */
+ if (m_cont_dest > m_ip)
+ { // Forward
+ if (m_dest < m_ip)
+ bp->push_back(this);
+ }
+ else if (m_cont_optdest)
+ m_cont_dest= m_cont_optdest->m_ip; // Backward
+ /* This will take care of m_dest and m_ip */
+ sp_instr_jump::opt_move(dst, bp);
+}
+
/*
sp_instr_freturn class functions
@@ -2602,6 +2609,7 @@ sp_instr_hpush_jump::execute(THD *thd, uint *nextp)
DBUG_RETURN(0);
}
+
void
sp_instr_hpush_jump::print(String *str)
{
@@ -2612,8 +2620,7 @@ sp_instr_hpush_jump::print(String *str)
str->qs_append(m_dest);
str->qs_append(' ');
str->qs_append(m_frame);
- switch (m_type)
- {
+ switch (m_type) {
case SP_HANDLER_NONE:
str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug
break;
@@ -2627,11 +2634,13 @@ sp_instr_hpush_jump::print(String *str)
str->qs_append(STRING_WITH_LEN(" UNDO"));
break;
default:
- str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); // This would be a bug as well
+ // This would be a bug as well
+ str->qs_append(STRING_WITH_LEN(" UNKNOWN:"));
str->qs_append(m_type);
}
}
+
uint
sp_instr_hpush_jump::opt_mark(sp_head *sp)
{
@@ -3129,7 +3138,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 */
@@ -3199,10 +3215,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
@@ -3214,14 +3234,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/sp_head.h b/sql/sp_head.h
index ad747b3466f..bd50afebde7 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -41,6 +41,7 @@ sp_get_flags_for_command(LEX *lex);
struct sp_label;
class sp_instr;
+class sp_instr_jump_if_not;
struct sp_cond_type;
struct sp_pvar;
@@ -266,6 +267,18 @@ public:
int
check_backpatch(THD *thd);
+ // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
+ void
+ new_cont_backpatch(sp_instr_jump_if_not *i);
+
+ // Add an instruction to the current level
+ void
+ add_cont_backpatch(sp_instr_jump_if_not *i);
+
+ // Backpatch (and pop) the current level to the current position.
+ void
+ do_cont_backpatch();
+
char *name(uint *lenp = 0) const
{
if (lenp)
@@ -285,7 +298,7 @@ public:
void set_info(longlong created, longlong modified,
st_sp_chistics *chistics, ulong sql_mode);
- void set_definer(char *definer, uint definerlen);
+ void set_definer(const char *definer, uint definerlen);
void reset_thd_mem_root(THD *thd);
@@ -294,7 +307,7 @@ public:
void optimize();
void opt_mark(uint ip);
- void recursion_level_error();
+ void recursion_level_error(THD *thd);
inline sp_instr *
get_instr(uint i)
@@ -356,6 +369,18 @@ private:
sp_instr *instr;
} bp_t;
List m_backpatch; // Instructions needing backpatching
+ /*
+ We need a special list for backpatching of conditional jump's continue
+ destination (in the case of a continue handler catching an error in
+ the test), since it would otherwise interfere with the normal backpatch
+ mechanism - jump_if_not instructions have two different destination
+ which are to be patched differently.
+ Since these occur in a more restricted way (always the same "level" in
+ the code), we don't need the label.
+ */
+ List m_cont_backpatch;
+ uint m_cont_level; // The current cont. backpatch level
+
/*
Multi-set representing optimized list of tables to be locked by this
routine. Does not include tables which are used by invoked routines.
@@ -669,6 +694,12 @@ public:
m_dest= dest;
}
+ virtual void set_destination(uint old_dest, uint new_dest)
+ {
+ if (m_dest == old_dest)
+ m_dest= new_dest;
+ }
+
protected:
sp_instr *m_optdest; // Used during optimization
@@ -676,45 +707,6 @@ protected:
}; // class sp_instr_jump : public sp_instr
-class sp_instr_jump_if : public sp_instr_jump
-{
- sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */
- void operator=(sp_instr_jump_if &);
-
-public:
-
- sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
- : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
- {}
-
- sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
- : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
- {}
-
- virtual ~sp_instr_jump_if()
- {}
-
- virtual int execute(THD *thd, uint *nextp);
-
- virtual int exec_core(THD *thd, uint *nextp);
-
- virtual void print(String *str);
-
- virtual uint opt_mark(sp_head *sp);
-
- virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
- {
- return m_ip;
- }
-
-private:
-
- Item *m_expr; // The condition
- sp_lex_keeper m_lex_keeper;
-
-}; // class sp_instr_jump_if : public sp_instr_jump
-
-
class sp_instr_jump_if_not : public sp_instr_jump
{
sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */
@@ -722,12 +714,16 @@ class sp_instr_jump_if_not : public sp_instr_jump
public:
+ uint m_cont_dest; // Where continue handlers will go
+
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
- : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
+ : sp_instr_jump(ip, ctx), m_cont_dest(0), m_expr(i),
+ m_lex_keeper(lex, TRUE), m_cont_optdest(0)
{}
sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
- : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
+ : sp_instr_jump(ip, ctx, dest), m_cont_dest(0), m_expr(i),
+ m_lex_keeper(lex, TRUE), m_cont_optdest(0)
{}
virtual ~sp_instr_jump_if_not()
@@ -746,10 +742,20 @@ public:
return m_ip;
}
+ virtual void opt_move(uint dst, List *ibp);
+
+ virtual void set_destination(uint old_dest, uint new_dest)
+ {
+ sp_instr_jump::set_destination(old_dest, new_dest);
+ if (m_cont_dest == old_dest)
+ m_cont_dest= new_dest;
+ }
+
private:
Item *m_expr; // The condition
sp_lex_keeper m_lex_keeper;
+ sp_instr *m_cont_optdest; // Used during optimization
}; // class sp_instr_jump_if_not : public sp_instr_jump
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 6d803362d86..d1cd7b964c2 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -52,6 +52,15 @@ typedef struct sp_pvar
#define SP_LAB_BEGIN 2 // Label at BEGIN
#define SP_LAB_ITER 3 // Label at iteration control
+/*
+ An SQL/PSM label. Can refer to the identifier used with the
+ "label_name:" construct which may precede some SQL/PSM statements, or
+ to an implicit implementation-dependent identifier which the parser
+ inserts before a high-level flow control statement such as
+ IF/WHILE/REPEAT/LOOP, when such statement is rewritten into
+ a combination of low-level jump/jump_if instructions and labels.
+*/
+
typedef struct sp_label
{
char *name;
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index eca87e69f8e..215de01e657 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -160,6 +160,10 @@ sp_rcontext::set_return_value(THD *thd, Item *return_value_item)
}
+#define IS_WARNING_CONDITION(S) ((S)[0] == '0' && (S)[1] == '1')
+#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2')
+#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2')
+
bool
sp_rcontext::find_handler(uint sql_errno,
MYSQL_ERROR::enum_warning_level level)
@@ -193,18 +197,17 @@ sp_rcontext::find_handler(uint sql_errno,
found= i;
break;
case sp_cond_type_t::warning:
- if ((sqlstate[0] == '0' && sqlstate[1] == '1' ||
- level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
- found < 0)
+ if ((IS_WARNING_CONDITION(sqlstate) ||
+ level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
+ found < 0)
found= i;
break;
case sp_cond_type_t::notfound:
- if (sqlstate[0] == '0' && sqlstate[1] == '2' &&
- found < 0)
+ if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0)
found= i;
break;
case sp_cond_type_t::exception:
- if ((sqlstate[0] != '0' || sqlstate[1] > '2') &&
+ if (IS_EXCEPTION_CONDITION(sqlstate) &&
level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
found < 0)
found= i;
@@ -213,7 +216,13 @@ sp_rcontext::find_handler(uint sql_errno,
}
if (found < 0)
{
- if (m_prev_runtime_ctx)
+ /*
+ Only "exception conditions" are propagated to handlers in calling
+ contexts. If no handler is found locally for a "completion condition"
+ (warning or "not found") we will simply resume execution.
+ */
+ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
+ level == MYSQL_ERROR::WARN_LEVEL_ERROR)
return m_prev_runtime_ctx->find_handler(sql_errno, level);
return FALSE;
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index dadb4b75d7c..7bc5aac270b 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -68,6 +68,7 @@ static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
static void init_check_host(void);
+static void rebuild_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user,
my_bool exact);
static bool update_user_table(THD *thd, TABLE *table,
@@ -937,7 +938,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
(host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
- (user ? user : "(NULL)"), (db ? db : "(NULL)")));
+ user, (db ? db : "(NULL)")));
sctx->user= user;
sctx->host= host;
sctx->ip= ip;
@@ -966,7 +967,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
for (i=0 ; i < acl_users.elements ; i++)
{
acl_user= dynamic_element(&acl_users,i,ACL_USER*);
- if ((!acl_user->user && (!user || !user[0])) ||
+ if ((!acl_user->user && !user[0]) ||
(acl_user->user && strcmp(user, acl_user->user) == 0))
{
if (compare_hostname(&acl_user->host, host, ip))
@@ -1095,10 +1096,8 @@ static void acl_insert_user(const char *user, const char *host,
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
- /* We must free acl_check_hosts as its memory is mapped to acl_user */
- delete_dynamic(&acl_wild_hosts);
- hash_free(&acl_check_hosts);
- init_check_host();
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
}
@@ -1283,7 +1282,7 @@ static void init_check_host(void)
if (j == acl_wild_hosts.elements) // If new
(void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
}
- else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
+ else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname,
(uint) strlen(acl_user->host.hostname)))
{
if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
@@ -1300,6 +1299,22 @@ static void init_check_host(void)
}
+/*
+ Rebuild lists used for checking of allowed hosts
+
+ We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
+ dropping or renaming user, since they contain pointers to elements of
+ 'acl_user' array, which are invalidated by drop operation, and use
+ ACL_USER::host::hostname as a key, which is changed by rename.
+*/
+void rebuild_check_host(void)
+{
+ delete_dynamic(&acl_wild_hosts);
+ hash_free(&acl_check_hosts);
+ init_check_host();
+}
+
+
/* Return true if there is no users that can match the given host */
bool acl_check_host(const char *host, const char *ip)
@@ -1528,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);
@@ -2229,14 +2245,14 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
char helping [NAME_LEN*2+USERNAME_LENGTH+3];
uint len;
GRANT_NAME *grant_name,*found=0;
+ HASH_SEARCH_STATE state;
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
- for (grant_name=(GRANT_NAME*) hash_search(name_hash,
- (byte*) helping,
- len) ;
+ for (grant_name= (GRANT_NAME*) hash_first(name_hash, (byte*) helping,
+ len, &state);
grant_name ;
grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping,
- len))
+ len, &state))
{
if (exact)
{
@@ -2474,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;
@@ -2592,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;
@@ -3538,7 +3554,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
of other queries). For simple queries first_not_own_table is 0.
*/
for (i= 0, table= tables;
- table && table != first_not_own_table && i < number;
+ table != first_not_own_table && i < number;
table= table->next_global, i++)
{
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
@@ -4623,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;
@@ -4939,8 +4955,6 @@ static int handle_grant_struct(uint struct_no, bool drop,
}
if (! user)
user= "";
- if (! host)
- host= "";
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
struct_no, idx, user, host));
@@ -5241,6 +5255,9 @@ bool mysql_drop_user(THD *thd, List &list)
}
}
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5265,7 +5282,7 @@ bool mysql_drop_user(THD *thd, List &list)
bool mysql_rename_user(THD *thd, List &list)
{
- int result= 0;
+ int result;
String wrong_users;
LEX_USER *user_from;
LEX_USER *user_to;
@@ -5297,6 +5314,9 @@ bool mysql_rename_user(THD *thd, List &list)
}
}
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 51d2317cad4..9d1720cc527 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -698,6 +698,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
SYNOPSIS
unique_table()
+ thd thread handle
table table which should be checked
table_list list of tables
@@ -723,7 +724,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
0 if table is unique
*/
-TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
+TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
{
TABLE_LIST *res;
const char *d_name, *t_name;
@@ -758,9 +759,10 @@ TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;)
{
- if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
- (!res->table || res->table != table->table) &&
- (res->select_lex && !res->select_lex->exclude_from_table_unique_test))
+ if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
+ (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
+ ((!res->table || res->table != table->table) &&
+ res->select_lex && !res->select_lex->exclude_from_table_unique_test))
break;
/*
If we found entry of this table or or table of SELECT which already
@@ -1083,6 +1085,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
+ HASH_SEARCH_STATE state;
DBUG_ENTER("open_table");
/* find a unused table in the open table cache */
@@ -1245,9 +1248,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ &state);
table && table->in_use ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ &state))
{
if (table->s->version != refresh_version)
{
@@ -1383,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)
@@ -1459,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);
@@ -1619,10 +1636,12 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
char *key= table->s->table_cache_key;
uint key_length= table->s->key_length;
- for (TABLE *search=(TABLE*) hash_search(&open_cache,
- (byte*) key,key_length) ;
+ HASH_SEARCH_STATE state;
+ for (TABLE *search= (TABLE*) hash_first(&open_cache, (byte*) key,
+ key_length, &state);
search ;
- search = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ search= (TABLE*) hash_next(&open_cache, (byte*) key,
+ key_length, &state))
{
if (search->locked_by_flush ||
search->locked_by_name && wait_for_name_lock ||
@@ -5057,15 +5076,17 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
bool result=0, signalled= 0;
DBUG_ENTER("remove_table_from_cache");
-
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
for (;;)
{
+ HASH_SEARCH_STATE state;
result= signalled= 0;
- for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+ for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ &state);
table;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+ table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ &state))
{
THD *in_use;
table->s->version=0L; /* Free when thread is ready */
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 0a01832bb39..cf3ba9c8c40 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -3050,6 +3050,7 @@ my_bool Query_cache::move_by_type(byte **border,
}
case Query_cache_block::TABLE:
{
+ HASH_SEARCH_STATE record_idx;
DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
if (*border == 0)
break;
@@ -3067,7 +3068,7 @@ my_bool Query_cache::move_by_type(byte **border,
byte *key;
uint key_length;
key=query_cache_table_get_key((byte*) block, &key_length, 0);
- hash_search(&tables, (byte*) key, key_length);
+ hash_first(&tables, (byte*) key, key_length, &record_idx);
block->destroy();
new_block->init(len);
@@ -3101,7 +3102,7 @@ my_bool Query_cache::move_by_type(byte **border,
/* Fix pointer to table name */
new_block->table()->table(new_block->table()->db() + tablename_offset);
/* Fix hash to point at moved block */
- hash_replace(&tables, tables.current_record, (byte*) new_block);
+ hash_replace(&tables, &record_idx, (byte*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
@@ -3109,6 +3110,7 @@ my_bool Query_cache::move_by_type(byte **border,
}
case Query_cache_block::QUERY:
{
+ HASH_SEARCH_STATE record_idx;
DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
if (*border == 0)
break;
@@ -3126,7 +3128,7 @@ my_bool Query_cache::move_by_type(byte **border,
byte *key;
uint key_length;
key=query_cache_query_get_key((byte*) block, &key_length, 0);
- hash_search(&queries, (byte*) key, key_length);
+ hash_first(&queries, (byte*) key, key_length, &record_idx);
// Move table of used tables
memmove((char*) new_block->table(0), (char*) block->table(0),
ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
@@ -3194,7 +3196,7 @@ my_bool Query_cache::move_by_type(byte **border,
net->query_cache_query= (gptr) new_block;
}
/* Fix hash to point at moved block */
- hash_replace(&queries, queries.current_record, (byte*) new_block);
+ hash_replace(&queries, &record_idx, (byte*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
break;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 5c3fe59e6fd..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.
@@ -473,10 +478,12 @@ void THD::awake(THD::killed_state state_to_set)
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
+ {
thr_alarm_kill(real_id);
#ifdef SIGNAL_WITH_VIO_CLOSE
- close_active_vio();
+ close_active_vio();
#endif
+ }
if (mysys_var)
{
pthread_mutex_lock(&mysys_var->mutex);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 2500b213f4c..1e547d77b11 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -287,7 +287,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
}
-/*
+/*
Load database options file
load_db_opt()
@@ -313,68 +313,72 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
bzero((char*) create,sizeof(*create));
create->default_table_charset= thd->variables.collation_server;
-
+
/* Check if options for this database are already in the hash */
if (!get_dbopt(path, create))
- DBUG_RETURN(0);
-
- /* Otherwise, load options from the .opt file */
- if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
- {
- IO_CACHE cache;
- init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0));
+ DBUG_RETURN(0);
- while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0)
+ /* Otherwise, load options from the .opt file */
+ if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
+ goto err1;
+
+ IO_CACHE cache;
+ if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)))
+ goto err2;
+
+ while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0)
+ {
+ char *pos= buf+nbytes-1;
+ /* Remove end space and control characters */
+ while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1]))
+ pos--;
+ *pos=0;
+ if ((pos= strchr(buf, '=')))
{
- char *pos= buf+nbytes-1;
- /* Remove end space and control characters */
- while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1]))
- pos--;
- *pos=0;
- if ((pos= strchr(buf, '=')))
+ if (!strncmp(buf,"default-character-set", (pos-buf)))
{
- if (!strncmp(buf,"default-character-set", (pos-buf)))
- {
- /*
- Try character set name, and if it fails
- try collation name, probably it's an old
- 4.1.0 db.opt file, which didn't have
- separate default-character-set and
- default-collation commands.
- */
- if (!(create->default_table_charset=
- get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) &&
- !(create->default_table_charset=
- get_charset_by_name(pos+1, MYF(0))))
- {
- sql_print_error("Error while loading database options: '%s':",path);
- sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
- create->default_table_charset= default_charset_info;
- }
- }
- else if (!strncmp(buf,"default-collation", (pos-buf)))
- {
- if (!(create->default_table_charset= get_charset_by_name(pos+1,
- MYF(0))))
- {
- sql_print_error("Error while loading database options: '%s':",path);
- sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1);
- create->default_table_charset= default_charset_info;
- }
- }
+ /*
+ Try character set name, and if it fails
+ try collation name, probably it's an old
+ 4.1.0 db.opt file, which didn't have
+ separate default-character-set and
+ default-collation commands.
+ */
+ if (!(create->default_table_charset=
+ get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) &&
+ !(create->default_table_charset=
+ get_charset_by_name(pos+1, MYF(0))))
+ {
+ sql_print_error("Error while loading database options: '%s':",path);
+ sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
+ create->default_table_charset= default_charset_info;
+ }
+ }
+ else if (!strncmp(buf,"default-collation", (pos-buf)))
+ {
+ if (!(create->default_table_charset= get_charset_by_name(pos+1,
+ MYF(0))))
+ {
+ sql_print_error("Error while loading database options: '%s':",path);
+ sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1);
+ create->default_table_charset= default_charset_info;
+ }
}
}
- end_io_cache(&cache);
- my_close(file,MYF(0));
- /*
- Put the loaded value into the hash.
- Note that another thread could've added the same
- entry to the hash after we called get_dbopt(),
- but it's not an error, as put_dbopt() takes this
- possibility into account.
- */
- error= put_dbopt(path, create);
}
+ /*
+ Put the loaded value into the hash.
+ Note that another thread could've added the same
+ entry to the hash after we called get_dbopt(),
+ but it's not an error, as put_dbopt() takes this
+ possibility into account.
+ */
+ error= put_dbopt(path, create);
+
+ end_io_cache(&cache);
+err2:
+ my_close(file,MYF(0));
+err1:
DBUG_RETURN(error);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 393e8184725..d8a8f28b92b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -348,7 +348,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
}
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "DELETE", duplicate);
DBUG_RETURN(TRUE);
@@ -438,7 +438,7 @@ bool mysql_multi_delete_prepare(THD *thd)
*/
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(target_tbl->correspondent_table,
+ if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
lex->query_tables)))
{
update_non_unique_table_error(target_tbl->correspondent_table,
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index da72d283259..1cd7778a053 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -227,6 +227,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* add to hash */
if (my_hash_insert(&thd->handler_tables_hash, (byte*) hash_tables))
{
+ my_free((char*) hash_tables, MYF(0));
mysql_ha_close(thd, tables);
goto err;
}
@@ -369,28 +370,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p",
hash_tables->db, hash_tables->table_name,
hash_tables->alias, table));
- /* Table might have been flushed. */
- if (table && (table->s->version != refresh_version))
- {
- /*
- We must follow the thd->handler_tables chain, as we need the
- address of the 'next' pointer referencing this table
- for close_thread_table().
- */
- for (table_ptr= &(thd->handler_tables);
- *table_ptr && (*table_ptr != table);
- table_ptr= &(*table_ptr)->next)
- {}
- (*table_ptr)->file->ha_index_or_rnd_end();
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
- {
- /* Tell threads waiting for refresh that something has happened */
- VOID(pthread_cond_broadcast(&COND_refresh));
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
- table= hash_tables->table= NULL;
- }
if (!table)
{
/*
@@ -435,9 +414,21 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && ((!cond->fixed &&
- cond->fix_fields(thd, &cond)) || cond->check_cols(1)))
- goto err0;
+ HANDLER_TABLES_HACK(thd);
+ lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used);
+ HANDLER_TABLES_HACK(thd);
+
+ if (!lock)
+ goto err0; // mysql_lock_tables() printed error message already
+
+ if (cond)
+ {
+ if (table->query_id != thd->query_id)
+ cond->cleanup(); // File was reopened
+ if ((!cond->fixed &&
+ cond->fix_fields(thd, &cond)) || cond->check_cols(1))
+ goto err0;
+ }
if (keyname)
{
@@ -454,13 +445,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
- HANDLER_TABLES_HACK(thd);
- lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used);
- HANDLER_TABLES_HACK(thd);
-
- if (!lock)
- goto err0; // mysql_lock_tables() printed error message already
-
/*
In ::external_lock InnoDB resets the fields which tell it that
the handle is used in the HANDLER interface. Tell it again that
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index b47412981ea..d6d1a6ed119 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -567,7 +567,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||
- (res->quick && res->quick->reset()))
+ (res && res->quick && res->quick->reset()))
{
delete res;
res=0;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e5ea296afab..eb74144c1ea 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -669,7 +669,8 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
- bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0);
+ VOID(bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8,
+ 0));
bitmap_clear_all(&used_fields);
view->contain_auto_increment= 0;
@@ -873,7 +874,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
Item *fake_conds= 0;
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE);
@@ -2174,7 +2175,7 @@ select_insert::prepare(List
- &values, SELECT_LEX_UNIT *u)
query
*/
if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
- unique_table(table_list, table_list->next_global))
+ unique_table(thd, table_list, table_list->next_global))
{
/* Using same table for INSERT and SELECT */
lex->current_select->options|= OPTION_BUFFER_RESULT;
@@ -2434,7 +2435,11 @@ select_create::prepare(List
- &values, SELECT_LEX_UNIT *u)
}
/* First field to copy */
- field=table->field+table->s->fields - values.elements;
+ field= table->field+table->s->fields - values.elements;
+
+ /* Mark all fields that are given values */
+ for (Field **f= field ; *f ; f++)
+ (*f)->query_id= thd->query_id;
/* Don't set timestamp if used */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 2a0145af9c7..4f3bfee5d3a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -178,7 +178,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table is marked to be 'used for insert' in which case we should never
mark this table as as 'const table' (ie, one that has only one row).
*/
- if (unique_table(table_list, table_list->next_global))
+ if (unique_table(thd, table_list, table_list->next_global))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 664bdf9706b..df366643cf9 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);
@@ -1185,6 +1185,7 @@ end_thread:
or this thread has been schedule to handle the next query
*/
thd= current_thd;
+ thd->thread_stack= (char*) &thd;
} while (!(test_flags & TEST_NO_THREADS));
/* The following is only executed if we are not using --one-thread */
return(0); /* purecov: deadcode */
@@ -1593,6 +1594,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
statistic_increment(thd->status_var.com_other, &LOCK_status);
thd->enable_slow_log= opt_log_slow_admin_statements;
db= thd->alloc(db_len + tbl_len + 2);
+ if (!db)
+ {
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ break;
+ }
tbl_name= strmake(db, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
mysql_table_dump(thd, db, tbl_name, -1);
@@ -1606,14 +1612,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
statistic_increment(thd->status_var.com_other, &LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
- /*
+ /*
Old clients send null-terminated string ('\0' for empty string) for
password. New clients send the size (1 byte) + string (not null
terminated, so also '\0' for empty string).
*/
- char db_buff[NAME_LEN+1]; // buffer to store db in utf8
+ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
*passwd++ : strlen(passwd);
db+= passwd_len + 1;
#ifndef EMBEDDED_LIBRARY
@@ -2835,7 +2841,7 @@ mysql_execute_command(THD *thd)
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(create_table, select_tables)))
+ if ((duplicate= unique_table(thd, create_table, select_tables)))
{
update_non_unique_table_error(create_table, "CREATE", duplicate);
res= 1;
@@ -2851,7 +2857,7 @@ mysql_execute_command(THD *thd)
tab= tab->next_local)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(tab, select_tables)))
+ if ((duplicate= unique_table(thd, tab, select_tables)))
{
update_non_unique_table_error(tab, "CREATE", duplicate);
res= 1;
@@ -4848,7 +4854,6 @@ end_with_restore_list:
if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
reset_one_shot_variables(thd);
-
/*
The return value for ROW_COUNT() is "implementation dependent" if the
statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
@@ -4860,13 +4865,10 @@ end_with_restore_list:
if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
uc_update_queries[lex->sql_command]<2)
thd->row_count_func= -1;
- goto cleanup;
+ DBUG_RETURN(res || thd->net.report_error);
error:
- res= 1;
-
-cleanup:
- DBUG_RETURN(res || thd->net.report_error);
+ DBUG_RETURN(1);
}
@@ -5089,7 +5091,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
- for (; tables && tables != first_not_own_table; tables= tables->next_global)
+ for (; tables != first_not_own_table; tables= tables->next_global)
{
if (tables->schema_table &&
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
@@ -6541,12 +6543,13 @@ 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
if (options & REFRESH_MASTER)
{
+ DBUG_ASSERT(thd);
tmp_write_to_binlog= 0;
if (reset_master(thd))
{
@@ -6627,20 +6630,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);
@@ -7252,7 +7253,7 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
/* Create and initialize. */
- if (! (definer= (LEX_USER*) thd->alloc(sizeof (LEX_USER))))
+ if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
return 0;
definer->user= *user_name;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index cd293fc21c7..07678d97800 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1197,7 +1197,12 @@ bool change_master(THD* thd, MASTER_INFO* mi)
Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never
a slave before).
*/
- flush_master_info(mi, 0);
+ if (flush_master_info(mi, 0))
+ {
+ my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file");
+ unlock_slave_threads(mi);
+ DBUG_RETURN(TRUE);
+ }
if (need_relay_log_purge)
{
relay_log_purge= 1;
@@ -1307,14 +1312,15 @@ bool mysql_show_binlog_events(THD* thd)
bool ret = TRUE;
IO_CACHE log;
File file = -1;
- Format_description_log_event *description_event= new
- Format_description_log_event(3); /* MySQL 4.0 by default */
Log_event::init_show_field_list(&field_list);
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
+ Format_description_log_event *description_event= new
+ Format_description_log_event(3); /* MySQL 4.0 by default */
+
if (mysql_bin_log.is_open())
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9b5b4b90ccb..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)
@@ -2917,6 +2918,56 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
}
+/*
+ Add to KEY_FIELD array all 'ref' access candidates within nested join
+
+ SYNPOSIS
+ add_key_fields_for_nj()
+ nested_join_table IN Nested join pseudo-table to process
+ end INOUT End of the key field array
+ and_level INOUT And-level
+
+ DESCRIPTION
+ This function populates KEY_FIELD array with entries generated from the
+ ON condition of the given nested join, and does the same for nested joins
+ contained within this nested join.
+
+ NOTES
+ We can add accesses to the tables that are direct children of this nested
+ join (1), and are not inner tables w.r.t their neighbours (2).
+
+ Example for #1 (outer brackets pair denotes nested join this function is
+ invoked for):
+ ... LEFT JOIN (t1 LEFT JOIN (t2 ... ) ) ON cond
+ Example for #2:
+ ... LEFT JOIN (t1 LEFT JOIN t2 ) ON cond
+ In examples 1-2 for condition cond, we can add 'ref' access candidates to
+ t1 only.
+ Example #3:
+ ... LEFT JOIN (t1, t2 LEFT JOIN t3 ON inner_cond) ON cond
+ Here we can add 'ref' access candidates for t1 and t2, but not for t3.
+*/
+
+static void add_key_fields_for_nj(TABLE_LIST *nested_join_table,
+ KEY_FIELD **end, uint *and_level)
+{
+ List_iterator li(nested_join_table->nested_join->join_list);
+ table_map tables= 0;
+ TABLE_LIST *table;
+ DBUG_ASSERT(nested_join_table->nested_join);
+
+ while ((table= li++))
+ {
+ if (table->nested_join)
+ add_key_fields_for_nj(table, end, and_level);
+ else
+ if (!table->on_expr)
+ tables |= table->table->map;
+ }
+ add_key_fields(end, and_level, nested_join_table->on_expr, tables);
+}
+
+
/*
Update keyuse array with all possible keys we can use to fetch rows
@@ -2981,23 +3032,21 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
into account as well.
*/
if (*join_tab[i].on_expr_ref)
- {
add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref,
join_tab[i].table->map);
- }
- else
+ }
+
+ /* Process ON conditions for the nested joins */
+ {
+ List_iterator li(*join_tab->join->join_list);
+ TABLE_LIST *table;
+ while ((table= li++))
{
- TABLE_LIST *tab= join_tab[i].table->pos_in_table_list;
- TABLE_LIST *embedding= tab->embedding;
- if (embedding)
- {
- NESTED_JOIN *nested_join= embedding->nested_join;
- if (nested_join->join_list.head() == tab)
- add_key_fields(&end, &and_level, embedding->on_expr,
- nested_join->used_tables);
- }
+ if (table->nested_join)
+ add_key_fields_for_nj(table, &end, &and_level);
}
}
+
/* fill keyuse with found key parts */
for ( ; field != end ; field++)
add_key_part(keyuse,field);
@@ -3470,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;
/*
@@ -4459,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;
/*
@@ -8189,7 +8259,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
uint convert_blob_length)
{
Item::Type orig_type= type;
- Item *orig_item;
+ Item *orig_item= 0;
if (type != Item::FIELD_ITEM &&
item->real_item()->type() == Item::FIELD_ITEM &&
@@ -8240,10 +8310,12 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
}
else
result= create_tmp_field_from_field(thd, (*from_field= field->field),
- item->name, table,
- modify_item ? field :
- NULL,
- convert_blob_length);
+ orig_item ? orig_item->name :
+ item->name,
+ table,
+ modify_item ? field :
+ NULL,
+ convert_blob_length);
if (orig_type == Item::REF_ITEM && orig_modify)
((Item_ref*)orig_item)->set_result_field(result);
return result;
@@ -8590,6 +8662,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List
- &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;
}
}
@@ -8809,7 +8886,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List
- &fields,
}
}
- if (distinct)
+ if (distinct && field_count != param->hidden_field_count)
{
/*
Create an unique key or an unique constraint over all columns
@@ -9867,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)
@@ -10698,7 +10776,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
item->save_org_in_field(group->field);
/* Store in the used key if the field was 0 */
if (item->maybe_null)
- group->buff[-1]=item->null_value ? 1 : 0;
+ group->buff[-1]= (char) group->field->is_null();
}
if (!table->file->index_read(table->record[1],
join->tmp_table_param.group_buff,0,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 82870d46e6c..17a8c846944 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -663,7 +663,7 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
it's a keyword
*/
- packet->reserve(length*2 + 2);
+ VOID(packet->reserve(length*2 + 2));
quote_char= (char) q;
packet->append("e_char, 1, system_charset_info);
@@ -950,13 +950,13 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
if (key_part->field)
append_identifier(thd,packet,key_part->field->field_name,
strlen(key_part->field->field_name));
- if (!key_part->field ||
+ if (key_part->field &&
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
{
buff[0] = '(';
- char* end=int10_to_str((long) key_part->length /
+ char* end=int10_to_str((long) key_part->length /
key_part->field->charset()->mbmaxlen,
buff + 1,10);
*end++ = ')';
@@ -1732,7 +1732,8 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
{
MEM_ROOT *mem= thd->mem_root;
if (allocate_lex_string)
- lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING));
+ if (!(lex_str= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING))))
+ return 0;
lex_str->str= strmake_root(mem, str, length);
lex_str->length= length;
return lex_str;
@@ -2045,6 +2046,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
int error= 1;
db_type not_used;
Open_tables_state open_tables_state_backup;
+ bool save_view_prepare_mode= lex->view_prepare_mode;
+ lex->view_prepare_mode= TRUE;
DBUG_ENTER("get_all_tables");
LINT_INIT(end);
@@ -2069,6 +2072,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
bool res;
lex->all_selects_list= lsel;
+ /*
+ Restore thd->temporary_tables to be able to process
+ temporary tables(only for 'show index' & 'show columns').
+ This should be changed when processing of temporary tables for
+ I_S tables will be done.
+ */
+ thd->temporary_tables= open_tables_state_backup.temporary_tables;
res= open_normal_and_derived_tables(thd, show_table_list,
MYSQL_LOCK_IGNORE_FLUSH);
/*
@@ -2088,6 +2098,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
show_table_list->view_db.str :
show_table_list->db),
show_table_list->alias));
+ thd->temporary_tables= 0;
close_thread_tables(thd);
show_table_list->table= 0;
goto err;
@@ -2222,6 +2233,7 @@ err:
lex->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
lex->query_tables_last= save_query_tables_last;
+ lex->view_prepare_mode= save_view_prepare_mode;
*save_query_tables_last= 0;
lex->sql_command= save_sql_command;
DBUG_RETURN(error);
@@ -2608,14 +2620,19 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
is_blob= (field->type() == FIELD_TYPE_BLOB);
- if (field->has_charset() || is_blob)
+ if (field->has_charset() || is_blob ||
+ field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
+ field->real_type() == MYSQL_TYPE_STRING) // For binary type
{
+ 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();
}
@@ -2874,7 +2891,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");
@@ -2933,7 +2950,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
/*
I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
rather than in SHOW KEYS
- */
+ */
if (!tables->view)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
thd->net.last_errno, thd->net.last_error);
@@ -2946,7 +2963,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
{
TABLE *show_table= tables->table;
KEY *key_info=show_table->key_info;
- show_table->file->info(HA_STATUS_VARIABLE |
+ show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
for (uint i=0 ; i < show_table->s->keys ; i++,key_info++)
@@ -2958,7 +2975,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
restore_record(table, s->default_values);
table->field[1]->store(base_name, strlen(base_name), cs);
table->field[2]->store(file_name, strlen(file_name), cs);
- table->field[3]->store((longlong) ((key_info->flags &
+ table->field[3]->store((longlong) ((key_info->flags &
HA_NOSAME) ? 0 : 1), TRUE);
table->field[4]->store(base_name, strlen(base_name), cs);
table->field[5]->store(key_info->name, strlen(key_info->name), cs);
@@ -2981,12 +2998,12 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables,
table->field[9]->store((longlong) records, TRUE);
table->field[9]->set_notnull();
}
- if (!(key_info->flags & HA_FULLTEXT) &&
- (!key_part->field ||
- key_part->length !=
+ if (!(key_info->flags & HA_FULLTEXT) &&
+ (key_part->field &&
+ key_part->length !=
show_table->field[key_part->fieldnr-1]->key_length()))
{
- table->field[10]->store((longlong) key_part->length /
+ table->field[10]->store((longlong) key_part->length /
key_part->field->charset()->mbmaxlen);
table->field[10]->set_notnull();
}
@@ -3016,7 +3033,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)
@@ -3200,7 +3217,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..b1a24543a6b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -886,6 +886,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields--;
sql_field->flags= dup_field->flags;
+ sql_field->interval= dup_field->interval;
it2.remove(); // Remove first (create) definition
select_field_pos--;
break;
@@ -1296,7 +1297,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_test.cc b/sql/sql_test.cc
index 1bd298dda04..975cc19ea3f 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -450,7 +450,7 @@ void mysql_print_status()
calc_sum_of_all_status(&tmp);
printf("\nStatus information:\n\n");
- my_getwd(current_dir, sizeof(current_dir),MYF(0));
+ VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0)));
printf("Current dir: %s\n", current_dir);
printf("Running threads: %d Stack size: %ld\n", thread_count,
(long) thread_stack);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 779b044696e..c70914edc31 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -21,7 +21,7 @@
#include "parse_file.h"
static const LEX_STRING triggers_file_type=
- {STRING_WITH_LEN("TRIGGERS")};
+ {(char *) STRING_WITH_LEN("TRIGGERS")};
const char * const triggers_file_ext= ".TRG";
@@ -34,23 +34,30 @@ const char * const triggers_file_ext= ".TRG";
static File_option triggers_file_parameters[]=
{
{
- {STRING_WITH_LEN("triggers") },
+ {(char *) STRING_WITH_LEN("triggers") },
offsetof(class Table_triggers_list, definitions_list),
FILE_OPTIONS_STRLIST
},
{
- {STRING_WITH_LEN("sql_modes") },
+ {(char *) STRING_WITH_LEN("sql_modes") },
offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST
},
{
- {STRING_WITH_LEN("definers") },
+ {(char *) STRING_WITH_LEN("definers") },
offsetof(class Table_triggers_list, definers_list),
FILE_OPTIONS_STRLIST
},
{ { 0, 0 }, 0, FILE_OPTIONS_STRING }
};
+File_option sql_modes_parameters=
+{
+ {(char*) STRING_WITH_LEN("sql_modes") },
+ offsetof(class Table_triggers_list, definition_modes_list),
+ FILE_OPTIONS_ULLLIST
+};
+
/*
This must be kept up to date whenever a new option is added to the list
above, as it specifies the number of required parameters of the trigger in
@@ -71,18 +78,14 @@ struct st_trigname
};
static const LEX_STRING trigname_file_type=
- {STRING_WITH_LEN("TRIGGERNAME")};
+ {(char *) STRING_WITH_LEN("TRIGGERNAME")};
const char * const trigname_file_ext= ".TRN";
static File_option trigname_file_parameters[]=
{
{
- /*
- FIXME: Length specified for "trigger_table" key is erroneous, problem
- caused by this are reported as BUG#14090 and should be fixed ASAP.
- */
- {STRING_WITH_LEN("trigger_table")},
+ {(char *) STRING_WITH_LEN("trigger_table")},
offsetof(struct st_trigname, trigger_table),
FILE_OPTIONS_ESTRING
},
@@ -155,6 +158,17 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
But do we want this ?
*/
+ /*
+ Note that once we will have check for TRIGGER privilege in place we won't
+ need second part of condition below, since check_access() function also
+ checks that db is specified.
+ */
+ if (!thd->lex->spname->m_db.length || create && !tables->db_length)
+ {
+ my_error(ER_NO_DB_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
if (!create &&
!(tables= add_table_for_trigger(thd, thd->lex->spname)))
DBUG_RETURN(TRUE);
@@ -285,6 +299,9 @@ end:
definer. The caller is responsible to provide memory for
storing LEX_STRING object.
+ NOTE
+ Assumes that trigger name is fully qualified.
+
RETURN VALUE
False - success
True - error
@@ -300,16 +317,14 @@ 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;
/* Trigger must be in the same schema as target table. */
- if (my_strcasecmp(table_alias_charset, table->s->db,
- lex->spname->m_db.str ? lex->spname->m_db.str :
- thd->db))
+ if (my_strcasecmp(table_alias_charset, table->s->db, lex->spname->m_db.str))
{
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
return 1;
@@ -428,7 +443,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
+ lex->definer->user.str))
{
push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -771,7 +786,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
sizeof(LEX_STRING))))
DBUG_RETURN(1); // EOM
- trg_definer->str= "";
+ trg_definer->str= (char*) "";
trg_definer->length= 0;
while (it++)
@@ -1010,7 +1025,6 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
{
- const char *db= !trig->m_db.str ? thd->db : trig->m_db.str;
LEX *lex= thd->lex;
char path_buff[FN_REFLEN];
LEX_STRING path;
@@ -1018,7 +1032,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
struct st_trigname trigname;
DBUG_ENTER("add_table_for_trigger");
- strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/",
+ strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", trig->m_db.str, "/",
trig->m_name.str, trigname_file_ext, NullS);
path.length= unpack_filename(path_buff, path_buff);
path.str= path_buff;
@@ -1047,7 +1061,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
- DBUG_RETURN(sp_add_to_query_tables(thd, lex, db,
+ DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
trigname.trigger_table.str, TL_WRITE));
}
@@ -1164,7 +1178,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
if (is_special_var_used(event, time_type))
{
- TABLE_LIST table_list;
+ TABLE_LIST table_list, **save_query_tables_own_last;
bzero((char *) &table_list, sizeof (table_list));
table_list.db= (char *) table->s->db;
table_list.db_length= strlen(table_list.db);
@@ -1172,8 +1186,13 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
table_list.table_name_length= strlen(table_list.table_name);
table_list.alias= (char *) table->alias;
table_list.table= table;
+ save_query_tables_own_last= thd->lex->query_tables_own_last;
+ thd->lex->query_tables_own_last= 0;
- if (check_table_access(thd, SELECT_ACL | UPDATE_ACL, &table_list, 0))
+ err_status= check_table_access(thd, SELECT_ACL | UPDATE_ACL,
+ &table_list, 0);
+ thd->lex->query_tables_own_last= save_query_tables_own_last;
+ if (err_status)
{
sp_restore_security_context(thd, save_ctx);
return TRUE;
@@ -1215,32 +1234,29 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
TRUE Error
*/
+#define INVALID_SQL_MODES_LENGTH 13
+
bool
Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
gptr base,
MEM_ROOT *mem_root,
char *end)
{
-#define INVALID_SQL_MODES_LENGTH 13
DBUG_ENTER("handle_old_incorrect_sql_modes");
DBUG_PRINT("info", ("unknown key:%60s", unknown_key));
+
if (unknown_key + INVALID_SQL_MODES_LENGTH + 1 < end &&
unknown_key[INVALID_SQL_MODES_LENGTH] == '=' &&
!memcmp(unknown_key, STRING_WITH_LEN("sql_modes")))
{
+ char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1;
+
DBUG_PRINT("info", ("sql_modes affected by BUG#14090 detected"));
push_warning_printf(current_thd,
MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_OLD_FILE_FORMAT,
ER(ER_OLD_FILE_FORMAT),
(char *)path, "TRIGGER");
- File_option sql_modes_parameters=
- {
- {STRING_WITH_LEN("sql_modes") },
- offsetof(class Table_triggers_list, definition_modes_list),
- FILE_OPTIONS_ULLLIST
- };
- char *ptr= unknown_key + INVALID_SQL_MODES_LENGTH + 1;
if (get_file_options_ulllist(ptr, end, unknown_key, base,
&sql_modes_parameters, mem_root))
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index a86d1b57190..2ff8a4bc244 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -616,7 +616,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
/* Check that we are not using table that we are updating in a sub select */
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
@@ -839,7 +839,7 @@ reopen_tables:
tl->lock_type != TL_READ_NO_INSERT)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(tl, table_list)))
+ if ((duplicate= unique_table(thd, tl, table_list)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
DBUG_RETURN(TRUE);
@@ -1026,8 +1026,7 @@ int multi_update::prepare(List
- ¬_used_values,
{
TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) &&
- find_table_in_local_list(update_tables, table_ref->db,
- table_ref->table_name))
+ unique_table(thd, table_ref, update_tables))
table->no_cache= 1; // Disable row cache
}
DBUG_RETURN(thd->is_fatal_error != 0);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 25e10362ece..714be26887c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1982,14 +1982,21 @@ sp_proc_stmt:
}
sp->restore_lex(YYTHD);
}
- | IF sp_if END IF {}
+ | IF
+ { Lex->sphead->new_cont_backpatch(NULL); }
+ sp_if END IF
+ { Lex->sphead->do_cont_backpatch(); }
| CASE_SYM WHEN_SYM
{
Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE;
+ Lex->sphead->new_cont_backpatch(NULL);
}
- sp_case END CASE_SYM {}
+ sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); }
| CASE_SYM
- { Lex->sphead->reset_lex(YYTHD); }
+ {
+ Lex->sphead->reset_lex(YYTHD);
+ Lex->sphead->new_cont_backpatch(NULL);
+ }
expr WHEN_SYM
{
LEX *lex= Lex;
@@ -2013,6 +2020,7 @@ sp_proc_stmt:
sp_case END CASE_SYM
{
Lex->spcont->pop_case_expr_id();
+ Lex->sphead->do_cont_backpatch();
}
| sp_labeled_control
{}
@@ -2281,6 +2289,7 @@ sp_if:
$2, lex);
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_cont_backpatch(i);
sp->add_instr(i);
sp->restore_lex(YYTHD);
}
@@ -2339,6 +2348,7 @@ sp_case:
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
}
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_cont_backpatch(i);
sp->add_instr(i);
sp->restore_lex(YYTHD);
}
@@ -2468,6 +2478,7 @@ sp_unlabeled_control:
/* Jumping forward */
sp->push_backpatch(i, lex->spcont->last_label());
+ sp->new_cont_backpatch(i);
sp->add_instr(i);
sp->restore_lex(YYTHD);
}
@@ -2479,6 +2490,7 @@ sp_unlabeled_control:
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
lex->sphead->add_instr(i);
+ lex->sphead->do_cont_backpatch();
}
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
{ Lex->sphead->reset_lex(YYTHD); }
@@ -2492,6 +2504,8 @@ sp_unlabeled_control:
lex);
lex->sphead->add_instr(i);
lex->sphead->restore_lex(YYTHD);
+ /* We can shortcut the cont_backpatch here */
+ i->m_cont_dest= ip+1;
}
;
@@ -5248,13 +5262,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 +5293,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 +5301,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 +9117,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/sql/table.cc b/sql/table.cc
index fc75568b615..45f8edddd0b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1040,7 +1040,10 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
ret_value=uint4korr(pos);
}
if (! save_names)
- my_free((gptr) buf,MYF(0));
+ {
+ if (names)
+ my_free((gptr) buf,MYF(0));
+ }
else if (!names)
bzero((char*) save_names,sizeof(save_names));
else
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 367aed2d113..ad074f8b2b0 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -38,8 +38,8 @@
int unique_write_to_file(gptr key, element_count count, Unique *unique)
{
/*
- Use unique->size (size of element stored in the tree) and not
- unique->tree.size_of_element. The latter is different from unique->size
+ Use unique->size (size of element stored in the tree) and not
+ unique->tree.size_of_element. The latter is different from unique->size
when tree implementation chooses to store pointer to key in TREE_ELEMENT
(instead of storing the element itself there)
*/
@@ -63,27 +63,27 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
comp_func_fixed_arg);
/* If the following fail's the next add will also fail */
my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
- /*
+ /*
If you change the following, change it in get_max_elements function, too.
*/
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size);
- open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
- MYF(MY_WME));
+ VOID(open_cached_file(&file, mysql_tmpdir,TEMP_PREFIX, DISK_BUFFER_SIZE,
+ MYF(MY_WME)));
}
/*
Calculate log2(n!)
-
+
NOTES
Stirling's approximate formula is used:
-
- n! ~= sqrt(2*M_PI*n) * (n/M_E)^n
-
+
+ n! ~= sqrt(2*M_PI*n) * (n/M_E)^n
+
Derivation of formula used for calculations is as follows:
log2(n!) = log(n!)/log(2) = log(sqrt(2*M_PI*n)*(n/M_E)^n) / log(2) =
-
+
= (log(2*M_PI*n)/2 + n*log(n/M_E)) / log(2).
*/
@@ -94,7 +94,7 @@ inline double log2_n_fact(double x)
/*
- Calculate cost of merge_buffers function call for given sequence of
+ Calculate cost of merge_buffers function call for given sequence of
input stream lengths and store the number of rows in result stream in *last.
SYNOPSIS
@@ -103,21 +103,21 @@ inline double log2_n_fact(double x)
elem_size Size of element stored in buffer
first Pointer to first merged element size
last Pointer to last merged element size
-
+
RETURN
Cost of merge_buffers operation in disk seeks.
-
+
NOTES
It is assumed that no rows are eliminated during merge.
- The cost is calculated as
-
+ The cost is calculated as
+
cost(read_and_write) + cost(merge_comparisons).
-
- All bytes in the sequences is read and written back during merge so cost
+
+ All bytes in the sequences is read and written back during merge so cost
of disk io is 2*elem_size*total_buf_elems/IO_SIZE (2 is for read + write)
-
+
For comparisons cost calculations we assume that all merged sequences have
- the same length, so each of total_buf_size elements will be added to a sort
+ the same length, so each of total_buf_size elements will be added to a sort
heap with (n_buffers-1) elements. This gives the comparison cost:
total_buf_elems* log2(n_buffers) / TIME_FOR_COMPARE_ROWID;
@@ -125,16 +125,16 @@ inline double log2_n_fact(double x)
static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
uint *first, uint *last)
-{
+{
uint total_buf_elems= 0;
for (uint *pbuf= first; pbuf <= last; pbuf++)
total_buf_elems+= *pbuf;
*last= total_buf_elems;
-
+
int n_buffers= last - first + 1;
/* Using log2(n)=log(n)/log(2) formula */
- return 2*((double)total_buf_elems*elem_size) / IO_SIZE +
+ return 2*((double)total_buf_elems*elem_size) / IO_SIZE +
total_buf_elems*log((double) n_buffers) / (TIME_FOR_COMPARE_ROWID * M_LN2);
}
@@ -142,13 +142,13 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
/*
Calculate cost of merging buffers into one in Unique::get, i.e. calculate
how long (in terms of disk seeks) the two calls
- merge_many_buffs(...);
- merge_buffers(...);
+ merge_many_buffs(...);
+ merge_buffers(...);
will take.
SYNOPSIS
get_merge_many_buffs_cost()
- buffer buffer space for temporary data, at least
+ buffer buffer space for temporary data, at least
Unique::get_cost_calc_buff_size bytes
maxbuffer # of full buffers
max_n_elems # of elements in first maxbuffer buffers
@@ -156,12 +156,12 @@ static double get_merge_buffers_cost(uint *buff_elems, uint elem_size,
elem_size size of buffer element
NOTES
- maxbuffer+1 buffers are merged, where first maxbuffer buffers contain
+ maxbuffer+1 buffers are merged, where first maxbuffer buffers contain
max_n_elems elements each and last buffer contains last_n_elems elements.
The current implementation does a dumb simulation of merge_many_buffs
function actions.
-
+
RETURN
Cost of merge in disk seeks.
*/
@@ -173,17 +173,17 @@ static double get_merge_many_buffs_cost(uint *buffer,
register int i;
double total_cost= 0.0;
uint *buff_elems= buffer; /* #s of elements in each of merged sequences */
-
- /*
+
+ /*
Set initial state: first maxbuffer sequences contain max_n_elems elements
each, last sequence contains last_n_elems elements.
*/
for (i = 0; i < (int)maxbuffer; i++)
- buff_elems[i]= max_n_elems;
+ buff_elems[i]= max_n_elems;
buff_elems[maxbuffer]= last_n_elems;
- /*
- Do it exactly as merge_many_buff function does, calling
+ /*
+ Do it exactly as merge_many_buff function does, calling
get_merge_buffers_cost to get cost of merge_buffers.
*/
if (maxbuffer >= MERGEBUFF2)
@@ -194,17 +194,17 @@ static double get_merge_many_buffs_cost(uint *buffer,
for (i = 0; i <= (int) maxbuffer - MERGEBUFF*3/2; i += MERGEBUFF)
{
total_cost+=get_merge_buffers_cost(buff_elems, elem_size,
- buff_elems + i,
+ buff_elems + i,
buff_elems + i + MERGEBUFF-1);
lastbuff++;
}
total_cost+=get_merge_buffers_cost(buff_elems, elem_size,
- buff_elems + i,
+ buff_elems + i,
buff_elems + maxbuffer);
maxbuffer= lastbuff;
}
}
-
+
/* Simulate final merge_buff call. */
total_cost += get_merge_buffers_cost(buff_elems, elem_size,
buff_elems, buff_elems + maxbuffer);
@@ -213,7 +213,7 @@ static double get_merge_many_buffs_cost(uint *buffer,
/*
- Calculate cost of using Unique for processing nkeys elements of size
+ Calculate cost of using Unique for processing nkeys elements of size
key_size using max_in_memory_size memory.
SYNOPSIS
@@ -223,12 +223,12 @@ static double get_merge_many_buffs_cost(uint *buffer,
nkeys #of elements in Unique
key_size size of each elements in bytes
max_in_memory_size amount of memory Unique will be allowed to use
-
+
RETURN
Cost in disk seeks.
-
+
NOTES
- cost(using_unqiue) =
+ cost(using_unqiue) =
cost(create_trees) + (see #1)
cost(merge) + (see #2)
cost(read_result) (see #3)
@@ -237,42 +237,42 @@ static double get_merge_many_buffs_cost(uint *buffer,
For each Unique::put operation there will be 2*log2(n+1) elements
comparisons, where n runs from 1 tree_size (we assume that all added
elements are different). Together this gives:
-
+
n_compares = 2*(log2(2) + log2(3) + ... + log2(N+1)) = 2*log2((N+1)!)
-
+
then cost(tree_creation) = n_compares*ROWID_COMPARE_COST;
Total cost of creating trees:
(n_trees - 1)*max_size_tree_cost + non_max_size_tree_cost.
Approximate value of log2(N!) is calculated by log2_n_fact function.
-
+
2. Cost of merging.
If only one tree is created by Unique no merging will be necessary.
Otherwise, we model execution of merge_many_buff function and count
- #of merges. (The reason behind this is that number of buffers is small,
- while size of buffers is big and we don't want to loose precision with
+ #of merges. (The reason behind this is that number of buffers is small,
+ while size of buffers is big and we don't want to loose precision with
O(x)-style formula)
-
+
3. If only one tree is created by Unique no disk io will happen.
- Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume
+ Otherwise, ceil(key_len*n_keys) disk seeks are necessary. We assume
these will be random seeks.
*/
-double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size,
+double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size,
ulong max_in_memory_size)
{
ulong max_elements_in_tree;
ulong last_tree_elems;
int n_full_trees; /* number of trees in unique - 1 */
double result;
-
- max_elements_in_tree=
+
+ max_elements_in_tree=
max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size);
n_full_trees= nkeys / max_elements_in_tree;
last_tree_elems= nkeys % max_elements_in_tree;
-
+
/* Calculate cost of creating trees */
result= 2*log2_n_fact(last_tree_elems + 1.0);
if (n_full_trees)
@@ -285,13 +285,13 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size,
if (!n_full_trees)
return result;
-
- /*
+
+ /*
There is more then one tree and merging is necessary.
First, add cost of writing all trees to disk, assuming that all disk
writes are sequential.
*/
- result += DISK_SEEK_BASE_COST * n_full_trees *
+ result += DISK_SEEK_BASE_COST * n_full_trees *
ceil(((double) key_size)*max_elements_in_tree / IO_SIZE);
result += DISK_SEEK_BASE_COST * ceil(((double) key_size)*last_tree_elems / IO_SIZE);
@@ -303,8 +303,8 @@ double Unique::get_use_cost(uint *buffer, uint nkeys, uint key_size,
return merge_cost;
result += merge_cost;
- /*
- Add cost of reading the resulting sequence, assuming there were no
+ /*
+ Add cost of reading the resulting sequence, assuming there were no
duplicate elements.
*/
result += ceil((double)key_size*nkeys/IO_SIZE);
@@ -320,7 +320,7 @@ Unique::~Unique()
}
- /* Write tree to disk; clear tree */
+ /* Write tree to disk; clear tree */
bool Unique::flush()
{
BUFFPEK file_ptr;
@@ -359,7 +359,7 @@ Unique::reset()
}
elements= 0;
}
-
+
/*
The comparison function, passed to queue_init() in merge_walk() must
use comparison function of Uniques::tree, but compare members of struct
@@ -386,7 +386,7 @@ C_MODE_END
/*
DESCRIPTION
- Function is very similar to merge_buffers, but instead of writing sorted
+ Function is very similar to merge_buffers, but instead of writing sorted
unique keys to the output file, it invokes walk_action for each key.
This saves I/O if you need to pass through all unique keys only once.
SYNOPSIS
@@ -601,7 +601,7 @@ bool Unique::get(TABLE *table)
bool error=1;
/* Open cached file if it isn't open */
- outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
+ outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
if (!outfile || ! my_b_inited(outfile) &&
@@ -618,7 +618,7 @@ bool Unique::get(TABLE *table)
sort_param.keys= max_in_memory_size / sort_param.sort_length;
sort_param.not_killable=1;
- if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
+ if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
sort_param.sort_length,
MYF(0))))
return 1;
@@ -633,7 +633,7 @@ bool Unique::get(TABLE *table)
goto err;
if (merge_buffers(&sort_param, &file, outfile, sort_buffer, file_ptr,
file_ptr, file_ptr+maxbuffer,0))
- goto err;
+ goto err;
error=0;
err:
x_free((gptr) sort_buffer);
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 */
diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c
index 4768e42a0b0..b18e5ee59d2 100644
--- a/strings/ctype-uca.c
+++ b/strings/ctype-uca.c
@@ -6705,6 +6705,14 @@ static const char esperanto[]=
"& S < \\u015d <<< \\u015c"
"& U < \\u016d <<< \\u016c";
+/*
+ A simplified version of Hungarian, without consonant contractions.
+*/
+static const char hungarian[]=
+ "&O < \\u00F6 <<< \\u00D6 << \\u0151 <<< \\u0150"
+ "&U < \\u00FC <<< \\u00DC << \\u0171 <<< \\u0170";
+
+
/*
Unicode Collation Algorithm:
Collation element (weight) scanner,
@@ -8627,6 +8635,39 @@ CHARSET_INFO my_charset_ucs2_esperanto_uca_ci=
};
+CHARSET_INFO my_charset_ucs2_hungarian_uca_ci=
+{
+ 146,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE,
+ "ucs2", /* cs name */
+ "ucs2_hungarian_ci",/* name */
+ "", /* comment */
+ hungarian, /* tailoring */
+ NULL, /* ctype */
+ NULL, /* to_lower */
+ NULL, /* to_upper */
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ my_unicase_default, /* caseinfo */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 8, /* strxfrm_multiply */
+ 1, /* caseup_multiply */
+ 1, /* casedn_multiply */
+ 2, /* mbminlen */
+ 2, /* mbmaxlen */
+ 9, /* min_sort_char */
+ 0xFFFF, /* max_sort_char */
+ ' ', /* pad char */
+ 0, /* escape_with_backslash_is_dangerous */
+ &my_charset_ucs2_handler,
+ &my_collation_ucs2_uca_handler
+};
+
+
#endif
@@ -9252,6 +9293,38 @@ CHARSET_INFO my_charset_utf8_esperanto_uca_ci=
&my_collation_any_uca_handler
};
+CHARSET_INFO my_charset_utf8_hungarian_uca_ci=
+{
+ 210,0,0, /* number */
+ MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_UNICODE,
+ "utf8", /* cs name */
+ "utf8_hungarian_ci",/* name */
+ "", /* comment */
+ hungarian, /* tailoring */
+ ctype_utf8, /* ctype */
+ NULL, /* to_lower */
+ NULL, /* to_upper */
+ NULL, /* sort_order */
+ NULL, /* contractions */
+ NULL, /* sort_order_big*/
+ NULL, /* tab_to_uni */
+ NULL, /* tab_from_uni */
+ my_unicase_default, /* caseinfo */
+ NULL, /* state_map */
+ NULL, /* ident_map */
+ 8, /* strxfrm_multiply */
+ 1, /* caseup_multiply */
+ 1, /* casedn_multiply */
+ 1, /* mbminlen */
+ 3, /* mbmaxlen */
+ 9, /* min_sort_char */
+ 0xFFFF, /* max_sort_char */
+ ' ', /* pad char */
+ 0, /* escape_with_backslash_is_dangerous */
+ &my_charset_utf8_handler,
+ &my_collation_any_uca_handler
+};
+
#endif /* HAVE_CHARSET_utf8 */
#endif /* HAVE_UCA_COLLATIONS */
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 80a7bd84601..e2629f445cb 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -1373,14 +1373,50 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs,
return (int) (t_is_prefix ? t-te : ((se-s) - (te-t)));
}
-static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs,
+static int my_strnncollsp_ucs2_bin(CHARSET_INFO *cs __attribute__((unused)),
const uchar *s, uint slen,
const uchar *t, uint tlen,
my_bool diff_if_only_endspace_difference
__attribute__((unused)))
{
- /* TODO: Needs to be fixed to handle end space! */
- return my_strnncoll_ucs2_bin(cs,s,slen,t,tlen,0);
+ const uchar *se, *te;
+ uint minlen;
+
+ /* extra safety to make sure the lengths are even numbers */
+ slen= (slen >> 1) << 1;
+ tlen= (tlen >> 1) << 1;
+
+ se= s + slen;
+ te= t + tlen;
+
+ for (minlen= min(slen, tlen); minlen; minlen-= 2)
+ {
+ int s_wc= s[0] * 256 + s[1];
+ int t_wc= t[0] * 256 + t[1];
+ if ( s_wc != t_wc )
+ return s_wc > t_wc ? 1 : -1;
+
+ s+= 2;
+ t+= 2;
+ }
+
+ if (slen != tlen)
+ {
+ int swap= 1;
+ if (slen < tlen)
+ {
+ s= t;
+ se= te;
+ swap= -1;
+ }
+
+ for ( ; s < se ; s+= 2)
+ {
+ if (s[0] || s[1] != ' ')
+ return (s[0] == 0 && s[1] < ' ') ? -swap : swap;
+ }
+ }
+ return 0;
}
diff --git a/strings/decimal.c b/strings/decimal.c
index 0c1f03016e0..5fb37d374a2 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1069,9 +1069,9 @@ int decimal2longlong(decimal_t *from, longlong *to)
}
}
/* boundary case: 9223372036854775808 */
- if (unlikely(from->sign==0 && x < 0 && -x < 0))
+ if (unlikely(from->sign==0 && x == LONGLONG_MIN))
{
- *to= -1-x;
+ *to= LONGLONG_MAX;
return E_DEC_OVERFLOW;
}
@@ -2675,7 +2675,8 @@ void test_pr(const char *s1, int prec, int dec, char filler, const char *orig,
int slen= sizeof(s2);
int res;
- sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler);
+ sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'",
+ s1, prec, dec, filler);
end= strend(s1);
string2decimal(s1, &a, &end);
res= decimal2string(&a, s2, &slen, prec, dec, filler);