diff options
344 files changed, 8687 insertions, 6793 deletions
diff --git a/client/mysql.cc b/client/mysql.cc index 19c5dd4e6a9..cb5c2318698 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1174,11 +1174,7 @@ int main(int argc,char *argv[]) close(stdout_fileno_copy); /* Clean up dup(). */ } - if (load_defaults("my",load_default_groups,&argc,&argv)) - { - my_end(0); - exit(1); - } + load_defaults_or_exit("my", load_default_groups, &argc, &argv); defaults_argv=argv; if ((status.exit_status= get_options(argc, (char **) argv))) { @@ -1231,15 +1227,17 @@ int main(int argc,char *argv[]) window_resize(0); #endif - put_info("Welcome to the MariaDB monitor. Commands end with ; or \\g.", - INFO_INFO); - my_snprintf((char*) glob_buffer.ptr(), glob_buffer.alloced_length(), - "Your %s connection id is %lu\nServer version: %s\n", - mysql_get_server_name(&mysql), - mysql_thread_id(&mysql), server_version_string(&mysql)); - put_info((char*) glob_buffer.ptr(),INFO_INFO); - - put_info(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"), INFO_INFO); + if (!status.batch) + { + put_info("Welcome to the MariaDB monitor. Commands end with ; or \\g.", + INFO_INFO); + my_snprintf((char*) glob_buffer.ptr(), glob_buffer.alloced_length(), + "Your %s connection id is %lu\nServer version: %s\n", + mysql_get_server_name(&mysql), + mysql_thread_id(&mysql), server_version_string(&mysql)); + put_info((char*) glob_buffer.ptr(),INFO_INFO); + put_info(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"), INFO_INFO); + } #ifdef HAVE_READLINE initialize_readline((char*) my_progname); diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index c7ef8bfc47a..0e0695c9ebe 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1141,6 +1141,8 @@ int main(int argc, char **argv) char self_name[FN_REFLEN + 1]; MY_INIT(argv[0]); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); + defaults_argv= argv; /* Must be freed by 'free_defaults' */ #if __WIN__ if (GetModuleFileName(NULL, self_name, FN_REFLEN) == 0) @@ -1153,10 +1155,6 @@ int main(int argc, char **argv) init_dynamic_string(&conn_args, "", 512, 256)) die("Out of memory"); - if (load_defaults("my", load_default_groups, &argc, &argv)) - die(NULL); - defaults_argv= argv; /* Must be freed by 'free_defaults' */ - if (handle_options(&argc, &argv, my_long_options, get_one_option)) die(NULL); if (debug_info_flag) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index bd80dd01a1e..5e7fb80b2b5 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -320,8 +320,7 @@ int main(int argc,char *argv[]) MY_INIT(argv[0]); mysql_init(&mysql); sf_leaking_memory=1; /* don't report memory leaks on early exits */ - if ((error= load_defaults("my",load_default_groups,&argc,&argv))) - goto err1; + load_defaults_or_exit("my", load_default_groups, &argc, &argv); save_argv = argv; /* Save for free_defaults */ if ((error=handle_options(&argc, &argv, my_long_options, get_one_option))) @@ -501,10 +500,8 @@ err2: my_free(shared_memory_base_name); #endif free_defaults(save_argv); -err1: my_end(my_end_arg); - exit(error); - return 0; + return error; } diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 7e5bb435eb4..44675ef7ed9 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -3008,9 +3008,7 @@ int main(int argc, char** argv) my_init_time(); // for time functions tzset(); // set tzname - if (load_defaults("my", load_groups, &argc, &argv)) - exit(1); - + load_defaults_or_exit("my", load_groups, &argc, &argv); defaults_argv= argv; if (!(binlog_filter= new Rpl_filter)) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 0854c890824..5e366c5e3d1 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -1181,9 +1181,7 @@ int main(int argc, char **argv) /* ** Check out the args */ - if (load_defaults("my", load_default_groups, &argc, &argv)) - goto end2; - + load_defaults_or_exit("my", load_default_groups, &argc, &argv); defaults_argv= argv; if (get_options(&argc, &argv)) goto end1; @@ -1259,7 +1257,6 @@ int main(int argc, char **argv) my_free(shared_memory_base_name); mysql_library_end(); free_defaults(defaults_argv); - end2: my_end(my_end_arg); return ret; } /* main */ diff --git a/client/mysqldump.c b/client/mysqldump.c index 9ea19855f0b..3dbe8412f3c 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -981,8 +981,7 @@ static int get_options(int *argc, char ***argv) opt_net_buffer_length= *mysql_params->p_net_buffer_length; md_result_file= stdout; - if (load_defaults("my",load_default_groups,argc,argv)) - return 1; + load_defaults_or_exit("my", load_default_groups, argc, argv); defaults_argv= *argv; if (my_hash_init(&ignore_table, charset_info, 16, 0, 0, diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 84bed92bbd4..c7432992d45 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -643,8 +643,7 @@ int main(int argc, char **argv) MY_INIT(argv[0]); sf_leaking_memory=1; /* don't report memory leaks on early exits */ - if (load_defaults("my",load_default_groups,&argc,&argv)) - return 1; + load_defaults_or_exit("my", load_default_groups, &argc, &argv); /* argv is changed in the program */ argv_to_free= argv; if (get_options(&argc, &argv)) diff --git a/client/mysqlshow.c b/client/mysqlshow.c index f1650a4b26a..484ca661d9e 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -72,8 +72,7 @@ int main(int argc, char **argv) static char **defaults_argv; MY_INIT(argv[0]); sf_leaking_memory=1; /* don't report memory leaks on early exits */ - if (load_defaults("my",load_default_groups,&argc,&argv)) - exit(1); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); defaults_argv=argv; get_options(&argc,&argv); diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 83c5838f739..420dc2b94af 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -325,11 +325,7 @@ int main(int argc, char **argv) MY_INIT(argv[0]); sf_leaking_memory=1; /* don't report memory leaks on early exits */ - if (load_defaults("my",load_default_groups,&argc,&argv)) - { - my_end(0); - exit(1); - } + load_defaults_or_exit("my", load_default_groups, &argc, &argv); defaults_argv=argv; if (get_options(&argc,&argv)) { diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 92c6f9f8b96..efc25f38984 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -2723,7 +2723,8 @@ void var_query_set(VAR *var, const char *query, const char** query_end) init_dynamic_string(&ds_query, 0, (end - query) + 32, 256); do_eval(&ds_query, query, end, FALSE); - if (mysql_real_query(mysql, ds_query.str, (ulong)ds_query.length)) + if (mysql_real_query(mysql, ds_query.str, (ulong)ds_query.length) || + !(res= mysql_store_result(mysql))) { handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), &ds_res); @@ -2733,13 +2734,6 @@ void var_query_set(VAR *var, const char *query, const char** query_end) DBUG_VOID_RETURN; } - if (!(res= mysql_store_result(mysql))) - { - report_or_die("Query '%s' didn't return a result set", ds_query.str); - dynstr_free(&ds_query); - eval_expr(var, "", 0); - DBUG_VOID_RETURN; - } dynstr_free(&ds_query); if ((row= mysql_fetch_row(res)) && row[0]) @@ -7335,9 +7329,7 @@ get_one_option(int optid, const struct my_option *opt, char *argument) int parse_args(int argc, char **argv) { - if (load_defaults("my",load_default_groups,&argc,&argv)) - exit(1); - + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; if ((handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake index b5dc8b9f157..9fa127380a4 100644 --- a/cmake/wsrep.cmake +++ b/cmake/wsrep.cmake @@ -26,7 +26,7 @@ ENDIF() OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ${with_wsrep_default}) # Set the patch version -SET(WSREP_PATCH_VERSION "21") +SET(WSREP_PATCH_VERSION "23") # Obtain wsrep API version FILE(STRINGS "${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h" WSREP_API_VERSION diff --git a/configure.cmake b/configure.cmake index c5d1d084f0f..17f31206975 100644 --- a/configure.cmake +++ b/configure.cmake @@ -1010,6 +1010,9 @@ CHECK_INCLUDE_FILE(ucontext.h HAVE_UCONTEXT_H) IF(NOT HAVE_UCONTEXT_H) CHECK_INCLUDE_FILE(sys/ucontext.h HAVE_UCONTEXT_H) ENDIF() +IF(HAVE_UCONTEXT_H) + CHECK_FUNCTION_EXISTS(makecontext HAVE_UCONTEXT_H) +ENDIF() CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_sec "time.h" STRUCT_TIMESPEC_HAS_TV_SEC) CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_nsec "time.h" STRUCT_TIMESPEC_HAS_TV_NSEC) diff --git a/debian/control b/debian/control index a02a25ccc5f..c712a7a09ba 100644 --- a/debian/control +++ b/debian/control @@ -35,8 +35,8 @@ Build-Depends: bison, zlib1g-dev (>= 1:1.1.3-5~) Standards-Version: 3.8.2 Homepage: http://mariadb.org/ -Vcs-Git: https://github.com/MariaDB/server.git Vcs-Browser: https://github.com/MariaDB/server/ +Vcs-Git: https://github.com/MariaDB/server.git Package: libmariadb-dev Architecture: any diff --git a/extra/mariabackup/CMakeLists.txt b/extra/mariabackup/CMakeLists.txt index f4ec59bbadc..f92da3fd3fd 100644 --- a/extra/mariabackup/CMakeLists.txt +++ b/extra/mariabackup/CMakeLists.txt @@ -64,7 +64,7 @@ MYSQL_ADD_EXECUTABLE(mariabackup datasink.c ds_buffer.c ds_compress.c - ds_local.c + ds_local.cc ds_stdout.c ds_tmpfile.c ds_xbstream.c @@ -101,7 +101,7 @@ ENDIF() ######################################################################## MYSQL_ADD_EXECUTABLE(mbstream ds_buffer.c - ds_local.c + ds_local.cc ds_stdout.c datasink.c xbstream.c @@ -115,6 +115,7 @@ TARGET_LINK_LIBRARIES(mbstream mysys crc ) +ADD_DEPENDENCIES(mbstream GenError) IF(MSVC) SET_TARGET_PROPERTIES(mbstream PROPERTIES LINK_FLAGS setargv.obj) diff --git a/extra/mariabackup/common.h b/extra/mariabackup/common.h index 4d73742af49..fae466adc97 100644 --- a/extra/mariabackup/common.h +++ b/extra/mariabackup/common.h @@ -28,7 +28,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include <my_sys.h> -# define fil_is_user_tablespace_id(i) ((i) > srv_undo_tablespaces_open) +/** Determine if (i) is a user tablespace id or not. */ +# define fil_is_user_tablespace_id(i) (i != 0 \ + && !srv_is_undo_tablespace(i)) #ifdef _MSC_VER #define stat _stati64 diff --git a/extra/mariabackup/datasink.c b/extra/mariabackup/datasink.c index 84418cd7528..19ea132c1c7 100644 --- a/extra/mariabackup/datasink.c +++ b/extra/mariabackup/datasink.c @@ -109,7 +109,7 @@ Write to a datasink file. int ds_write(ds_file_t *file, const void *buf, size_t len) { - return file->datasink->write(file, buf, len); + return file->datasink->write(file, (const uchar *)buf, len); } /************************************************************************ diff --git a/extra/mariabackup/datasink.h b/extra/mariabackup/datasink.h index 8bf1321aad1..5962e9ba4b7 100644 --- a/extra/mariabackup/datasink.h +++ b/extra/mariabackup/datasink.h @@ -48,7 +48,7 @@ typedef struct { struct datasink_struct { ds_ctxt_t *(*init)(const char *root); ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); - int (*write)(ds_file_t *file, const void *buf, size_t len); + int (*write)(ds_file_t *file, const unsigned char *buf, size_t len); int (*close)(ds_file_t *file); void (*deinit)(ds_ctxt_t *ctxt); }; diff --git a/extra/mariabackup/ds_buffer.c b/extra/mariabackup/ds_buffer.c index 9a0c660c15c..186b897c675 100644 --- a/extra/mariabackup/ds_buffer.c +++ b/extra/mariabackup/ds_buffer.c @@ -45,7 +45,7 @@ typedef struct { static ds_ctxt_t *buffer_init(const char *root); static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat); -static int buffer_write(ds_file_t *file, const void *buf, size_t len); +static int buffer_write(ds_file_t *file, const uchar *buf, size_t len); static int buffer_close(ds_file_t *file); static void buffer_deinit(ds_ctxt_t *ctxt); @@ -119,7 +119,7 @@ buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) } static int -buffer_write(ds_file_t *file, const void *buf, size_t len) +buffer_write(ds_file_t *file, const uchar *buf, size_t len) { ds_buffer_file_t *buffer_file; @@ -142,7 +142,7 @@ buffer_write(ds_file_t *file, const void *buf, size_t len) buffer_file->pos = 0; - buf = (const char *) buf + bytes; + buf += bytes; len -= bytes; } else { /* We don't have any buffered bytes, just write diff --git a/extra/mariabackup/ds_compress.c b/extra/mariabackup/ds_compress.c index 6b00f6a6dce..d064068a7e2 100644 --- a/extra/mariabackup/ds_compress.c +++ b/extra/mariabackup/ds_compress.c @@ -66,7 +66,7 @@ extern ulonglong xtrabackup_compress_chunk_size; static ds_ctxt_t *compress_init(const char *root); static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat); -static int compress_write(ds_file_t *file, const void *buf, size_t len); +static int compress_write(ds_file_t *file, const uchar *buf, size_t len); static int compress_close(ds_file_t *file); static void compress_deinit(ds_ctxt_t *ctxt); @@ -179,7 +179,7 @@ err: static int -compress_write(ds_file_t *file, const void *buf, size_t len) +compress_write(ds_file_t *file, const uchar *buf, size_t len) { ds_compress_file_t *comp_file; ds_compress_ctxt_t *comp_ctxt; diff --git a/extra/mariabackup/ds_local.c b/extra/mariabackup/ds_local.c deleted file mode 100644 index 7ba027cf00b..00000000000 --- a/extra/mariabackup/ds_local.c +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************** -Copyright (c) 2011-2013 Percona LLC and/or its affiliates. - -Local datasink implementation for XtraBackup. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -*******************************************************/ - -#include <my_global.h> -#include <my_base.h> -#include <mysys_err.h> -#include "common.h" -#include "datasink.h" - -typedef struct { - File fd; -} ds_local_file_t; - -static ds_ctxt_t *local_init(const char *root); -static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path, - MY_STAT *mystat); -static int local_write(ds_file_t *file, const void *buf, size_t len); -static int local_close(ds_file_t *file); -static void local_deinit(ds_ctxt_t *ctxt); - -datasink_t datasink_local = { - &local_init, - &local_open, - &local_write, - &local_close, - &local_deinit -}; - -static -ds_ctxt_t * -local_init(const char *root) -{ - ds_ctxt_t *ctxt; - - if (my_mkdir(root, 0777, MYF(0)) < 0 - && my_errno != EEXIST && my_errno != EISDIR) - { - char errbuf[MYSYS_STRERROR_SIZE]; - my_strerror(errbuf, sizeof(errbuf),my_errno); - my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), - root, my_errno,errbuf, my_errno); - return NULL; - } - - ctxt = my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); - - ctxt->root = my_strdup(root, MYF(MY_FAE)); - - return ctxt; -} - -static -ds_file_t * -local_open(ds_ctxt_t *ctxt, const char *path, - MY_STAT *mystat __attribute__((unused))) -{ - char fullpath[FN_REFLEN]; - char dirpath[FN_REFLEN]; - size_t dirpath_len; - size_t path_len; - ds_local_file_t *local_file; - ds_file_t *file; - File fd; - - fn_format(fullpath, path, ctxt->root, "", MYF(MY_RELATIVE_PATH)); - - /* Create the directory if needed */ - dirname_part(dirpath, fullpath, &dirpath_len); - if (my_mkdir(dirpath, 0777, MYF(0)) < 0 && my_errno != EEXIST) { - char errbuf[MYSYS_STRERROR_SIZE]; - my_strerror(errbuf, sizeof(errbuf), my_errno); - my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), - dirpath, my_errno, errbuf); - return NULL; - } - - fd = my_create(fullpath, 0, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, - MYF(MY_WME)); - if (fd < 0) { - return NULL; - } - - path_len = strlen(fullpath) + 1; /* terminating '\0' */ - - file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + - sizeof(ds_local_file_t) + - path_len, - MYF(MY_FAE)); - local_file = (ds_local_file_t *) (file + 1); - - local_file->fd = fd; - - file->path = (char *) local_file + sizeof(ds_local_file_t); - memcpy(file->path, fullpath, path_len); - - file->ptr = local_file; - - return file; -} - -static -int -local_write(ds_file_t *file, const void *buf, size_t len) -{ - File fd = ((ds_local_file_t *) file->ptr)->fd; - - if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { - posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); - return 0; - } - - return 1; -} - -static -int -local_close(ds_file_t *file) -{ - File fd = ((ds_local_file_t *) file->ptr)->fd; - - my_free(file); - - my_sync(fd, MYF(MY_WME)); - - return my_close(fd, MYF(MY_WME)); -} - -static -void -local_deinit(ds_ctxt_t *ctxt) -{ - my_free(ctxt->root); - my_free(ctxt); -} diff --git a/extra/mariabackup/ds_local.cc b/extra/mariabackup/ds_local.cc new file mode 100644 index 00000000000..1d24111b557 --- /dev/null +++ b/extra/mariabackup/ds_local.cc @@ -0,0 +1,258 @@ +/****************************************************** +Copyright (c) 2011-2013 Percona LLC and/or its affiliates. + +Local datasink implementation for XtraBackup. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +*******************************************************/ + +#include <my_global.h> +#include <my_base.h> +#include <mysys_err.h> +#include "common.h" +#include "datasink.h" +#include "univ.i" +#include "fsp0fsp.h" +#ifdef _WIN32 +#include <winioctl.h> +#endif + +typedef struct { + File fd; + my_bool init_ibd_done; + my_bool is_ibd; + my_bool compressed; + size_t pagesize; +} ds_local_file_t; + +static ds_ctxt_t *local_init(const char *root); +static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path, + MY_STAT *mystat); +static int local_write(ds_file_t *file, const uchar *buf, size_t len); +static int local_close(ds_file_t *file); +static void local_deinit(ds_ctxt_t *ctxt); + +extern "C" { +datasink_t datasink_local = { + &local_init, + &local_open, + &local_write, + &local_close, + &local_deinit +}; +} + +static +ds_ctxt_t * +local_init(const char *root) +{ + ds_ctxt_t *ctxt; + + if (my_mkdir(root, 0777, MYF(0)) < 0 + && my_errno != EEXIST && my_errno != EISDIR) + { + char errbuf[MYSYS_STRERROR_SIZE]; + my_strerror(errbuf, sizeof(errbuf),my_errno); + my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), + root, my_errno,errbuf, my_errno); + return NULL; + } + + ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); + + ctxt->root = my_strdup(root, MYF(MY_FAE)); + + return ctxt; +} + +static +ds_file_t * +local_open(ds_ctxt_t *ctxt, const char *path, + MY_STAT *mystat __attribute__((unused))) +{ + char fullpath[FN_REFLEN]; + char dirpath[FN_REFLEN]; + size_t dirpath_len; + size_t path_len; + ds_local_file_t *local_file; + ds_file_t *file; + File fd; + + fn_format(fullpath, path, ctxt->root, "", MYF(MY_RELATIVE_PATH)); + + /* Create the directory if needed */ + dirname_part(dirpath, fullpath, &dirpath_len); + if (my_mkdir(dirpath, 0777, MYF(0)) < 0 && my_errno != EEXIST) { + char errbuf[MYSYS_STRERROR_SIZE]; + my_strerror(errbuf, sizeof(errbuf), my_errno); + my_error(EE_CANT_MKDIR, MYF(ME_BELL | ME_WAITTANG), + dirpath, my_errno, errbuf); + return NULL; + } + + fd = my_create(fullpath, 0, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, + MYF(MY_WME)); + if (fd < 0) { + return NULL; + } + + path_len = strlen(fullpath) + 1; /* terminating '\0' */ + + file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + + sizeof(ds_local_file_t) + + path_len, + MYF(MY_FAE)); + local_file = (ds_local_file_t *) (file + 1); + + local_file->fd = fd; + local_file->init_ibd_done = 0; + local_file->is_ibd = (path_len > 5) && !strcmp(fullpath + path_len - 5, ".ibd"); + local_file->compressed = 0; + local_file->pagesize = 0; + file->path = (char *) local_file + sizeof(ds_local_file_t); + memcpy(file->path, fullpath, path_len); + + file->ptr = local_file; + + return file; +} + +/* Calculate size of data without trailing zero bytes. */ +static size_t trim_binary_zeros(uchar *buf, size_t pagesize) +{ + size_t i; + for (i = pagesize; (i > 0) && (buf[i - 1] == 0); i--) {}; + return i; +} + + +/* Write data to the output file, and punch "holes" if needed. */ +static int write_compressed(File fd, uchar *data, size_t len, size_t pagesize) +{ + uchar *ptr = data; + for (size_t written= 0; written < len;) + { + size_t n_bytes = MY_MIN(pagesize, len - written); + size_t datasize= trim_binary_zeros(ptr,n_bytes); + if (datasize > 0) { + if (!my_write(fd, ptr, datasize, MYF(MY_WME | MY_NABP))) + posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); + else + return 1; + } + if (datasize < n_bytes) { + /* This punches a "hole" in the file. */ + size_t hole_bytes = n_bytes - datasize; + if (my_seek(fd, hole_bytes, MY_SEEK_CUR, MYF(MY_WME | MY_NABP)) + == MY_FILEPOS_ERROR) + return 1; + } + written += n_bytes; + ptr += n_bytes; + } + return 0; +} + + +/* Calculate Innodb tablespace specific data, when first page is written. + We're interested in page compression and page size. +*/ +static void init_ibd_data(ds_local_file_t *local_file, const uchar *buf, size_t len) +{ + if (len < FIL_PAGE_DATA + FSP_SPACE_FLAGS) { + /* Weird, bail out.*/ + return; + } + + ulint flags = mach_read_from_4(&buf[FIL_PAGE_DATA + FSP_SPACE_FLAGS]); + ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); + local_file->pagesize= ssize == 0 ? UNIV_PAGE_SIZE_ORIG : ((UNIV_ZIP_SIZE_MIN >> 1) << ssize); + local_file->compressed = (my_bool)FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); + +#if defined(_WIN32) && (MYSQL_VERSION_ID > 100200) + /* Make compressed file sparse, on Windows. + In 10.1, we do not use sparse files. */ + if (local_file->compressed) { + HANDLE handle= my_get_osfhandle(local_file->fd); + if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, NULL, 0)) { + fprintf(stderr, "Warning: cannot make file sparse"); + local_file->compressed = 0; + } + } +#endif +} + + +static +int +local_write(ds_file_t *file, const uchar *buf, size_t len) +{ + uchar *b = (uchar*)buf; + ds_local_file_t *local_file= (ds_local_file_t *)file->ptr; + File fd = local_file->fd; + + if (local_file->is_ibd && !local_file->init_ibd_done) { + init_ibd_data(local_file, b , len); + local_file->init_ibd_done= 1; + } + + if (local_file->compressed) { + return write_compressed(fd, b, len, local_file->pagesize); + } + + if (!my_write(fd, b , len, MYF(MY_WME | MY_NABP))) { + posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); + return 0; + } + return 1; +} + +/* Set EOF at file's current position.*/ +static int set_eof(File fd) +{ +#ifdef _WIN32 + return !SetEndOfFile(my_get_osfhandle(fd)); +#elif defined(HAVE_FTRUNCATE) + return ftruncate(fd, my_tell(fd, MYF(MY_WME))); +#else +#error no ftruncate +#endif +} + + +static +int +local_close(ds_file_t *file) +{ + ds_local_file_t *local_file= (ds_local_file_t *)file->ptr; + File fd = local_file->fd; + int ret= 0; + + if (local_file->compressed) { + ret = set_eof(fd); + } + + my_close(fd, MYF(MY_WME)); + my_free(file); + return ret; +} + +static +void +local_deinit(ds_ctxt_t *ctxt) +{ + my_free(ctxt->root); + my_free(ctxt); +} diff --git a/extra/mariabackup/ds_local.h b/extra/mariabackup/ds_local.h index b0f0f04030c..e30906b575d 100644 --- a/extra/mariabackup/ds_local.h +++ b/extra/mariabackup/ds_local.h @@ -23,6 +23,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include "datasink.h" -extern datasink_t datasink_local; +#ifdef __cplusplus +extern "C" +#else +extern +#endif + +datasink_t datasink_local; #endif diff --git a/extra/mariabackup/ds_stdout.c b/extra/mariabackup/ds_stdout.c index 934d59b97c9..a6555c17352 100644 --- a/extra/mariabackup/ds_stdout.c +++ b/extra/mariabackup/ds_stdout.c @@ -31,7 +31,7 @@ typedef struct { static ds_ctxt_t *stdout_init(const char *root); static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat); -static int stdout_write(ds_file_t *file, const void *buf, size_t len); +static int stdout_write(ds_file_t *file, const uchar *buf, size_t len); static int stdout_close(ds_file_t *file); static void stdout_deinit(ds_ctxt_t *ctxt); @@ -92,7 +92,7 @@ stdout_open(ds_ctxt_t *ctxt __attribute__((unused)), static int -stdout_write(ds_file_t *file, const void *buf, size_t len) +stdout_write(ds_file_t *file, const uchar *buf, size_t len) { File fd = ((ds_stdout_file_t *) file->ptr)->fd; diff --git a/extra/mariabackup/ds_tmpfile.c b/extra/mariabackup/ds_tmpfile.c index 75b08af78ce..443b3703b20 100644 --- a/extra/mariabackup/ds_tmpfile.c +++ b/extra/mariabackup/ds_tmpfile.c @@ -42,7 +42,7 @@ typedef struct { static ds_ctxt_t *tmpfile_init(const char *root); static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat); -static int tmpfile_write(ds_file_t *file, const void *buf, size_t len); +static int tmpfile_write(ds_file_t *file, const uchar *buf, size_t len); static int tmpfile_close(ds_file_t *file); static void tmpfile_deinit(ds_ctxt_t *ctxt); @@ -144,7 +144,7 @@ tmpfile_open(ds_ctxt_t *ctxt, const char *path, } static int -tmpfile_write(ds_file_t *file, const void *buf, size_t len) +tmpfile_write(ds_file_t *file, const uchar *buf, size_t len) { File fd = ((ds_tmp_file_t *) file->ptr)->fd; diff --git a/extra/mariabackup/ds_xbstream.c b/extra/mariabackup/ds_xbstream.c index 43cac4fcdf7..74ac27ac428 100644 --- a/extra/mariabackup/ds_xbstream.c +++ b/extra/mariabackup/ds_xbstream.c @@ -41,7 +41,7 @@ General streaming interface */ static ds_ctxt_t *xbstream_init(const char *root); static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat); -static int xbstream_write(ds_file_t *file, const void *buf, size_t len); +static int xbstream_write(ds_file_t *file, const uchar *buf, size_t len); static int xbstream_close(ds_file_t *file); static void xbstream_deinit(ds_ctxt_t *ctxt); @@ -166,7 +166,7 @@ err: static int -xbstream_write(ds_file_t *file, const void *buf, size_t len) +xbstream_write(ds_file_t *file, const uchar *buf, size_t len) { ds_stream_file_t *stream_file; xb_wstream_file_t *xbstream_file; diff --git a/extra/mariabackup/xbcloud.cc b/extra/mariabackup/xbcloud.cc index 56661b03dd0..878b4c81023 100644 --- a/extra/mariabackup/xbcloud.cc +++ b/extra/mariabackup/xbcloud.cc @@ -443,9 +443,7 @@ int parse_args(int argc, char **argv) exit(EXIT_FAILURE); } - if (load_defaults("my", load_default_groups, &argc, &argv)) { - exit(EXIT_FAILURE); - } + load_defaults_or_exit("my", load_default_groups, &argc, &argv); if (handle_options(&argc, &argv, my_long_options, get_one_option)) { exit(EXIT_FAILURE); diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index fd6013e6623..b52f547779c 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -70,6 +70,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include <row0mysql.h> #include <row0quiesce.h> #include <srv0start.h> +#include "trx0sys.h" #include <buf0dblwr.h> #include <list> @@ -451,6 +452,45 @@ void mdl_lock_all() } datafiles_iter_free(it); } + +/** Check if the space id belongs to the table which name should +be skipped based on the --tables, --tables-file and --table-exclude +options. +@param[in] space_id space id to check +@return true if the space id belongs to skip table/database list. */ +static bool backup_includes(space_id_t space_id) +{ + datafiles_iter_t *it = datafiles_iter_new(fil_system); + if (!it) + return true; + + while (fil_node_t *node = datafiles_iter_next(it)){ + if (space_id == 0 + || (node->space->id == space_id + && !check_if_skip_table(node->space->name))) { + + msg("mariabackup: Unsupported redo log detected " + "and it belongs to %s\n", + space_id ? node->name: "the InnoDB system tablespace"); + + msg("mariabackup: ALTER TABLE or OPTIMIZE TABLE " + "was being executed during the backup.\n"); + + if (!opt_lock_ddl_per_table) { + msg("mariabackup: Use --lock-ddl-per-table " + "parameter to lock all the table before " + "backup operation.\n"); + } + + datafiles_iter_free(it); + return false; + } + } + + datafiles_iter_free(it); + return true; +} + /* ======== Date copying thread context ======== */ typedef struct { @@ -2343,8 +2383,8 @@ lsn_t xtrabackup_copy_log(copy_logfile copy, lsn_t start_lsn, lsn_t end_lsn) { lsn_t scanned_lsn = start_lsn; - const byte* log_block = log_sys->buf; + bool more_data = false; for (ulint scanned_checkpoint = 0; scanned_lsn < end_lsn; @@ -2359,8 +2399,15 @@ xtrabackup_copy_log(copy_logfile copy, lsn_t start_lsn, lsn_t end_lsn) } scanned_checkpoint = checkpoint; + ulint data_len = log_block_get_data_len(log_block); + more_data = recv_sys_add_to_parsing_buf( + log_block, + scanned_lsn + data_len); + + recv_sys->scanned_lsn = scanned_lsn + data_len; + if (data_len == OS_FILE_LOG_BLOCK_SIZE) { /* We got a full log block. */ scanned_lsn += data_len; @@ -2376,6 +2423,15 @@ xtrabackup_copy_log(copy_logfile copy, lsn_t start_lsn, lsn_t end_lsn) } } + if (more_data && recv_parse_log_recs(0, STORE_NO, false)) { + + msg("mariabackup: copying the log failed \n"); + + return(0); + } + + recv_sys_justify_left_parsing_buf(); + log_sys->log.scanned_lsn = scanned_lsn; end_lsn = copy == COPY_LAST @@ -2409,9 +2465,12 @@ xtrabackup_copy_logfile(copy_logfile copy) lsn_t start_lsn; lsn_t end_lsn; + recv_sys->parse_start_lsn = log_copy_scanned_lsn; + recv_sys->scanned_lsn = log_copy_scanned_lsn; + recv_sys->recovered_lsn = log_copy_scanned_lsn; + start_lsn = ut_uint64_align_down(log_copy_scanned_lsn, OS_FILE_LOG_BLOCK_SIZE); - /* When copying the first or last part of the log, retry a few times to ensure that all log up to the last checkpoint will be read. */ @@ -2882,6 +2941,83 @@ next_datadir_item: return(err); } +/** Assign srv_undo_space_id_start variable if there are undo tablespace present. +Read the TRX_SYS page from ibdata1 file and get the minimum space id from +the first slot rollback segments of TRX_SYS_PAGE_NO. +@retval DB_ERROR if file open or page read failed. +@retval DB_SUCCESS if srv_undo_space_id assigned successfully. */ +static dberr_t xb_assign_undo_space_start() +{ + ulint dirnamelen; + char name[1000]; + pfs_os_file_t file; + byte* buf; + byte* page; + bool ret; + dberr_t error = DB_SUCCESS; + ulint space, page_no; + + if (srv_undo_tablespaces == 0) { + return error; + } + + os_normalize_path(srv_data_home); + dirnamelen = strlen(srv_data_home); + memcpy(name, srv_data_home, dirnamelen); + + if (dirnamelen && name[dirnamelen - 1] != OS_PATH_SEPARATOR) { + name[dirnamelen++] = OS_PATH_SEPARATOR; + } + + snprintf(name + dirnamelen, strlen(name) + strlen("ibdata1"), + "%s", "ibdata1"); + + file = os_file_create(0, name, OS_FILE_OPEN, + OS_FILE_NORMAL, OS_DATA_FILE, true, &ret); + + if (!ret) { + msg("mariabackup: Error in opening %s\n", name); + return DB_ERROR; + } + + buf = static_cast<byte*>(ut_malloc_nokey(2 * UNIV_PAGE_SIZE)); + page = static_cast<byte*>(ut_align(buf, UNIV_PAGE_SIZE)); + +retry: + if (!os_file_read(IORequestRead, file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, + UNIV_PAGE_SIZE)) { + msg("mariabackup: Reading TRX_SYS page failed.\n"); + error = DB_ERROR; + goto func_exit; + } + + /* TRX_SYS page can't be compressed or encrypted. */ + if (buf_page_is_corrupted(false, page, univ_page_size)) { + goto retry; + } + + /* 0th slot always points to system tablespace. + 1st slot should point to first undotablespace which is minimum. */ + + page_no = mach_read_ulint(TRX_SYS + TRX_SYS_RSEGS + + TRX_SYS_RSEG_SLOT_SIZE + + TRX_SYS_RSEG_PAGE_NO + page, MLOG_4BYTES); + ut_ad(page_no != FIL_NULL); + + space = mach_read_ulint(TRX_SYS + TRX_SYS_RSEGS + + TRX_SYS_RSEG_SLOT_SIZE + + TRX_SYS_RSEG_SPACE + page, MLOG_4BYTES); + + srv_undo_space_id_start = space; + +func_exit: + ut_free(buf); + ret = os_file_close(file); + ut_a(ret); + + return error; +} + /**************************************************************************** Populates the tablespace memory cache by scanning for and opening data files. @returns DB_SUCCESS or error code.*/ @@ -2916,6 +3052,12 @@ xb_load_tablespaces() /* Add separate undo tablespaces to fil_system */ + err = xb_assign_undo_space_start(); + + if (err != DB_SUCCESS) { + return err; + } + err = srv_undo_tablespaces_init(false); if (err != DB_SUCCESS) { @@ -3571,8 +3713,6 @@ xtrabackup_backup_func() "or RENAME TABLE during the backup, inconsistent backup will be " "produced.\n"); - - /* initialize components */ if(innodb_init_param()) { fail: @@ -3842,6 +3982,14 @@ reread_log_header: &io_watching_thread_id); } + /* Populate fil_system with tablespaces to copy */ + err = xb_load_tablespaces(); + if (err != DB_SUCCESS) { + msg("mariabackup: error: xb_load_tablespaces() failed with" + " error %s.\n", ut_strerr(err)); + goto fail; + } + /* copy log file by current position */ log_copy_scanned_lsn = checkpoint_lsn_start; if (xtrabackup_copy_logfile(COPY_FIRST)) @@ -3851,14 +3999,6 @@ reread_log_header: log_copying_running = true; os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); - /* Populate fil_system with tablespaces to copy */ - err = xb_load_tablespaces(); - if (err != DB_SUCCESS) { - msg("mariabackup: error: xb_load_tablespaces() failed with" - " error code %u\n", err); - goto fail; - } - /* FLUSH CHANGED_PAGE_BITMAPS call */ if (!flush_changed_page_bitmaps()) { goto fail; @@ -5058,6 +5198,7 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) srv_operation = SRV_OPERATION_RESTORE; files_charset_info = &my_charset_utf8_general_ci; + check_if_backup_includes = backup_includes; setup_error_messages(); sys_var_init(); @@ -5140,10 +5281,8 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) *argv_client = argv; *argv_server = argv; - if (load_defaults(conf_file, xb_server_default_groups, - &argc_server, argv_server)) { - exit(EXIT_FAILURE); - } + load_defaults_or_exit(conf_file, xb_server_default_groups, + &argc_server, argv_server); int n; for (n = 0; (*argv_server)[n]; n++) {}; @@ -5193,10 +5332,8 @@ handle_options(int argc, char **argv, char ***argv_client, char ***argv_server) xb_server_options, xb_get_one_option))) exit(ho_error); - if (load_defaults(conf_file, xb_client_default_groups, - &argc_client, argv_client)) { - exit(EXIT_FAILURE); - } + load_defaults_or_exit(conf_file, xb_client_default_groups, + &argc_client, argv_client); for (n = 0; (*argv_client)[n]; n++) {}; argc_client = n; diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index 78940e02ca4..07c95a79ddc 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -206,6 +206,9 @@ int main(int argc, char **argv) if ((error= load_defaults(config_file, (const char **) load_default_groups, &count, &arguments))) { + my_end(0); + if (error == 4) + return 0; if (verbose && opt_defaults_file_used) { if (error == 1) @@ -216,8 +219,7 @@ int main(int argc, char **argv) fprintf(stderr, "WARNING: Defaults file '%s' is not a regular file!\n", config_file); } - error= 2; - exit(error); + return 2; } for (argument= arguments+1 ; *argument ; argument++) diff --git a/include/my_default.h b/include/my_default.h index 0ed94b09492..bd3a21f03a8 100644 --- a/include/my_default.h +++ b/include/my_default.h @@ -45,6 +45,13 @@ extern void free_defaults(char **argv); extern void my_print_default_files(const char *conf_file); extern void print_defaults(const char *conf_file, const char **groups); + +/** Simplify load_defaults() common use */ +#define load_defaults_or_exit(A, B, C, D) switch (load_defaults(A, B, C, D)) { \ + case 0: break; \ + case 4: my_end(0); exit(0); \ + default: my_end(0); exit(1); } + C_MODE_END #endif /* MY_DEFAULT_INCLUDED */ diff --git a/include/my_valgrind.h b/include/my_valgrind.h index c585e3c489a..5ba288cedc3 100644 --- a/include/my_valgrind.h +++ b/include/my_valgrind.h @@ -35,6 +35,8 @@ # define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len) #elif defined(__SANITIZE_ADDRESS__) # include <sanitizer/asan_interface.h> +/* How to do manual poisoning: +https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning */ # define MEM_UNDEFINED(a,len) ASAN_UNPOISON_MEMORY_REGION(a,len) # define MEM_NOACCESS(a,len) ASAN_POISON_MEMORY_REGION(a,len) # define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) diff --git a/libmariadb b/libmariadb -Subproject 67cc3438a84df9fa3cc0cfbf9ed81242502702d +Subproject 668757aaa9a55d2bcd806908cb5a8e806cd6dc3 diff --git a/mysql-test/include/maybe_debug.combinations b/mysql-test/include/maybe_debug.combinations new file mode 100644 index 00000000000..5ee57c0bfd8 --- /dev/null +++ b/mysql-test/include/maybe_debug.combinations @@ -0,0 +1,5 @@ +[debug] +--enable-gdb + +[release] +--disable-gdb diff --git a/mysql-test/include/maybe_debug.inc b/mysql-test/include/maybe_debug.inc new file mode 100644 index 00000000000..2f6c2848f9f --- /dev/null +++ b/mysql-test/include/maybe_debug.inc @@ -0,0 +1,3 @@ +# include file for test files that can be run with and without debug +# having debug and non-debug tests. +let $have_debug=`select version() like '%debug%'`; diff --git a/mysql-test/include/wait_condition.inc b/mysql-test/include/wait_condition.inc index 5fbde6950c8..d40b0e4d448 100644 --- a/mysql-test/include/wait_condition.inc +++ b/mysql-test/include/wait_condition.inc @@ -39,7 +39,7 @@ let $wait_timeout= 0; let $wait_condition_reps= 0; while ($wait_counter) { - --error 0,ER_NO_SUCH_TABLE,ER_LOCK_WAIT_TIMEOUT,ER_UNKNOWN_COM_ERROR + --error 0,ER_NO_SUCH_TABLE,ER_LOCK_WAIT_TIMEOUT,ER_UNKNOWN_COM_ERROR,ER_LOCK_DEADLOCK let $success= `$wait_condition`; inc $wait_condition_reps; if ($success) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5ee05f3f606..048f34d6d1d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -331,7 +331,7 @@ my %mysqld_logs; my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions. my $warn_seconds = 60; -my $rebootstrap_re= '--innodb[-_](?:page[-_]size|checksum[-_]algorithm|undo[-_]tablespaces|log[-_]group[-_]home[-_]dir|data[-_]home[-_]dir)|data[-_]file[-_]path'; +my $rebootstrap_re= '--innodb[-_](?:page[-_]size|checksum[-_]algorithm|undo[-_]tablespaces|log[-_]group[-_]home[-_]dir|data[-_]home[-_]dir)|data[-_]file[-_]path|force_rebootstrap'; sub testcase_timeout ($) { my ($tinfo)= @_; diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 08fa5a79743..f385a3b20c7 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -403,8 +403,38 @@ DROP TABLE t1; # # End of 10.1 test # +select case 'foo' when time'10:00:00' then 'never' when '0' then 'bug' else 'ok' end; +case 'foo' when time'10:00:00' then 'never' when '0' then 'bug' else 'ok' end +ok +Warnings: +Warning 1292 Truncated incorrect time value: 'foo' +select 'foo' in (time'10:00:00','0'); +'foo' in (time'10:00:00','0') +0 +Warnings: +Warning 1292 Truncated incorrect time value: 'foo' +create table t1 (a time); +insert t1 values (100000), (102030), (203040); +select case 'foo' when a then 'never' when '0' then 'bug' else 'ok' end from t1; +case 'foo' when a then 'never' when '0' then 'bug' else 'ok' end +ok +ok +ok +Warnings: +Warning 1292 Truncated incorrect time value: 'foo' +select 'foo' in (a,'0') from t1; +'foo' in (a,'0') +0 +0 +0 +Warnings: +Warning 1292 Truncated incorrect time value: 'foo' +drop table t1; +select case '20:10:05' when date'2020-10-10' then 'never' when time'20:10:5' then 'ok' else 'bug' end; +case '20:10:05' when date'2020-10-10' then 'never' when time'20:10:5' then 'ok' else 'bug' end +ok # -# Start of 10.3 tests +# End of 10.2 test # # # MDEV-11554 Wrong result for CASE on a mixture of signed and unsigned expressions @@ -511,3 +541,6 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' DROP TABLE t1; +# +# End of 10.3 test +# diff --git a/mysql-test/r/check_constraint.result b/mysql-test/r/check_constraint.result index 525140d96e7..70d64cd6ff7 100644 --- a/mysql-test/r/check_constraint.result +++ b/mysql-test/r/check_constraint.result @@ -152,3 +152,7 @@ a 1 NULL drop table t1; +create table t1 (id int auto_increment primary key, datecol datetime, check (datecol>'0001-01-01 00:00:00')); +insert into t1 (datecol) values (now()); +insert into t1 (datecol) values (now()); +drop table t1; diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 53334512b20..534a386fe12 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -1425,3 +1425,40 @@ a DEALLOCATE PREPARE stmt; DROP TABLE t1; DROP VIEW v1,v2; +# +# MDEV-15478: Lost name of a explicitly named CTE column used in +# the non-recursive CTE defined with UNION +# +CREATE TABLE t1 (x int, y int); +INSERT INTO t1 VALUES (1,2),(2,7),(3,3); +WITH cte(a) AS (SELECT 1 UNION SELECT 2) SELECT * FROM cte; +a +1 +2 +WITH cte(a) AS (SELECT 1 UNION SELECT 2) SELECT a FROM cte; +a +1 +2 +WITH cte(a) AS (SELECT 1 UNION ALL SELECT 1) SELECT a FROM cte; +a +1 +1 +WITH cte(a) AS (SELECT x from t1 UNION SELECT 4) SELECT a FROM cte; +a +1 +2 +3 +4 +WITH cte(a) AS (SELECT 4 UNION SELECT x FROM t1 UNION SELECT 5) +SELECT a FROM cte; +a +4 +1 +2 +3 +5 +WITH cte(a,b) AS (SELECT 4,5 UNION SELECT 4,3) SELECT a,b FROM cte; +a b +4 5 +4 3 +DROP TABLE t1; diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index 085b8b22f67..d5906cb74dd 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -8241,6 +8241,19 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,`test`.`t1`.`d` AS `d` from `test`.`t1` where coalesce(`test`.`t1`.`c`,0) = '3 ' and coalesce(`test`.`t1`.`d`,0) = '3 ' DROP TABLE t1; # +# MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple +# +SET NAMES latin1; +SELECT CONVERT(1, CHAR) IN ('100', 10, '101'); +CONVERT(1, CHAR) IN ('100', 10, '101') +0 +SELECT CONVERT(1, CHAR) IN ('100', 10, '1'); +CONVERT(1, CHAR) IN ('100', 10, '1') +1 +SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); +CONVERT(1, CHAR) IN ('100', '10', '1') +1 +# # End of 10.1 tests # # diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index dfe96d1a904..10d0efeff3c 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -10543,6 +10543,19 @@ CAST(_utf8 0xC499 AS CHAR CHARACTER SET latin1) Warnings: Warning 1977 Cannot convert 'utf8' character 0xC499 to 'latin1' # +# MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple +# +SET NAMES utf8; +SELECT CONVERT(1, CHAR) IN ('100', 10, '101'); +CONVERT(1, CHAR) IN ('100', 10, '101') +0 +SELECT CONVERT(1, CHAR) IN ('100', 10, '1'); +CONVERT(1, CHAR) IN ('100', 10, '1') +1 +SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); +CONVERT(1, CHAR) IN ('100', '10', '1') +1 +# # End of 10.1 tests # # diff --git a/mysql-test/r/fast_prefix_index_fetch_innodb.result b/mysql-test/r/fast_prefix_index_fetch_innodb.result index 92af85f7fdb..c6d96389b08 100644 --- a/mysql-test/r/fast_prefix_index_fetch_innodb.result +++ b/mysql-test/r/fast_prefix_index_fetch_innodb.result @@ -30,73 +30,372 @@ id fake_id bigfield 33 1033 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy 128 1128 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz # Baseline sanity check: 0, 0. +select "no-op query"; no-op query no-op query -cluster_lookups_matched -1 -cluster_lookups_avoided_matched -1 +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 # Eligible for optimization. +select id, bigfield from prefixinno where bigfield = repeat('d', 31); id bigfield 31 ddddddddddddddddddddddddddddddd -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided 1 # Eligible for optimization, access via fake_id only. +select id, bigfield from prefixinno where fake_id = 1031; id bigfield 31 ddddddddddddddddddddddddddddddd -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided 1 # Not eligible for optimization, access via fake_id of big row. +select id, bigfield from prefixinno where fake_id = 1033; id bigfield 33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups 1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 # Not eligible for optimization. +select id, bigfield from prefixinno where bigfield = repeat('x', 32); id bigfield 32 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups 1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 # Not eligible for optimization. +select id, bigfield from prefixinno where bigfield = repeat('y', 33); id bigfield 33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups 1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 # Eligible, should not increment lookup counter. +select id, bigfield from prefixinno where bigfield = repeat('b', 8); id bigfield 8 bbbbbbbb -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided 1 # Eligible, should not increment lookup counter. +select id, bigfield from prefixinno where bigfield = repeat('c', 24); id bigfield 24 cccccccccccccccccccccccc -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided 1 # Should increment lookup counter. +select id, bigfield from prefixinno where bigfield = repeat('z', 128); id bigfield 128 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz -cluster_lookups_matched -1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups 1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 # Disable optimization, confirm we still increment counter. +set global innodb_prefix_index_cluster_optimization = OFF; +select id, bigfield from prefixinno where fake_id = 1033; id bigfield 33 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy -cluster_lookups_matched +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +drop table prefixinno; +# Multi-byte handling case +set global innodb_prefix_index_cluster_optimization = ON; +SET NAMES utf8mb4; +CREATE TABLE t1( +f1 varchar(10) CHARACTER SET UTF8MB4 COLLATE UTF8MB4_BIN, +INDEX (f1(3)))ENGINE=INNODB; +INSERT INTO t1 VALUES('a'), ('cccc'), ('až'), ('cčc'), ('ggᵷg'), ('¢¢'); +INSERT INTO t1 VALUES('தமிழ்'), ('🐱🌑'), ('🌒'), ('🌑'); +INSERT INTO t1 VALUES('😊me'), ('eu€'), ('ls¢'); +# Eligible - record length is shorter than prefix +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a'; +f1 +a +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%'; +f1 +cccc +cčc +select @cluster_lookups; +@cluster_lookups +3 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'až'; +f1 +až +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'தமிழ்'; +f1 +தமிழ் +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggᵷ%'; +f1 +ggᵷg +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '😊%'; +f1 +😊me +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'ls¢'; +f1 +ls¢ +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '¢¢%'; +f1 +¢¢ +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🐱🌑%'; +f1 +🐱🌑 +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%'; +f1 +🌑 +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +2 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌒%'; +f1 +🌒 +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +2 +DROP TABLE t1; +# Multi-byte with minimum character length > 1 bytes +CREATE TABLE t1( +f1 varchar(10) CHARACTER SET UTF16 COLLATE UTF16_BIN, +INDEX (f1(3)))ENGINE=INNODB; +INSERT INTO t1 VALUES('a'), ('cccc'), ('až'), ('cčc'), ('ggᵷg'), ('¢¢'); +INSERT INTO t1 VALUES('தமிழ்'), ('🐱🌑'), ('🌒'), ('🌑'); +INSERT INTO t1 VALUES('😊me'), ('eu€'), ('ls¢'); +# Eligible - record length is shorter than prefix +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a'; +f1 +a +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%'; +f1 +cccc +cčc +select @cluster_lookups; +@cluster_lookups +3 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'až'; +f1 +až +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'தமிழ்'; +f1 +தமிழ் +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggᵷ%'; +f1 +ggᵷg +select @cluster_lookups; +@cluster_lookups +2 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '😊%'; +f1 +😊me +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Not eligible - record length longer than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'ls¢'; +f1 +ls¢ +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX(`f1`) WHERE f1 like '¢¢%'; +f1 +¢¢ +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +# Eligible - record length shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🐱🌑%'; +f1 +🐱🌑 +select @cluster_lookups; +@cluster_lookups +2 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +# Eligible - record length is shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%'; +f1 +🌑 +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +2 +# Eligible - record length is shorter than prefix length +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌒%'; +f1 +🌒 +select @cluster_lookups; +@cluster_lookups +1 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +1 +DROP TABLE t1; +CREATE TABLE t1( +col1 INT, +col2 BLOB DEFAULT NULL, +INDEX `idx1`(col2(4), col1))ENGINE=INNODB; +INSERT INTO t1 VALUES (2, 'test'), (3, repeat('test1', 2000)); +INSERT INTO t1(col1) VALUES(1); +# Eligible - record length is shorter than prefix length +SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 is NULL; +col1 1 -cluster_lookups_avoided_matched +select @cluster_lookups; +@cluster_lookups +0 +select @cluster_lookups_avoided; +@cluster_lookups_avoided 1 -# make test suite happy by cleaning up our mess +# Not eligible - record length longer than prefix index +SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 like 'test1%'; +col1 +3 +select @cluster_lookups; +@cluster_lookups +2 +select @cluster_lookups_avoided; +@cluster_lookups_avoided +0 +DROP TABLE t1; +set global innodb_prefix_index_cluster_optimization = OFF; diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index fa45353e094..a6201a3c23f 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -102,6 +102,57 @@ select * from t1 where case a when adddate( '2012-12-12', 7 ) then true end; a drop table t1; End of 5.5 tests +# +# Start of 10.1 tests +# +# +# MDEV-14452 Precision in INTERVAL xxx DAY_MICROSECOND parsed wrong? +# +SELECT +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5' DAY_MICROSECOND) c1, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50' DAY_MICROSECOND) c2, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500' DAY_MICROSECOND) c3, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000' DAY_MICROSECOND) c4, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000' DAY_MICROSECOND) c5, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000' DAY_MICROSECOND) c6, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000' DAY_MICROSECOND) c7, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000' DAY_MICROSECOND) c8, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000' DAY_MICROSECOND) c9, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000' DAY_MICROSECOND) c10, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000' DAY_MICROSECOND) c11, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000' DAY_MICROSECOND) c12, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000' DAY_MICROSECOND) c13, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000' DAY_MICROSECOND) c14, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000000' DAY_MICROSECOND) c15, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000000' DAY_MICROSECOND) c16, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000000' DAY_MICROSECOND) c17, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000000000' DAY_MICROSECOND) c18, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000000000' DAY_MICROSECOND) c19, +DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000000000' DAY_MICROSECOND) c20 +; +c1 1000-01-01 00:00:01.500000 +c2 1000-01-01 00:00:01.500000 +c3 1000-01-01 00:00:01.500000 +c4 1000-01-01 00:00:01.500000 +c5 1000-01-01 00:00:01.500000 +c6 1000-01-01 00:00:01.500000 +c7 1000-01-01 00:00:01.500000 +c8 1000-01-01 00:00:01.500000 +c9 1000-01-01 00:00:01.500000 +c10 1000-01-01 00:00:01.500000 +c11 1000-01-01 00:00:01.500000 +c12 1000-01-01 00:00:01.500000 +c13 1000-01-01 00:00:01.500000 +c14 1000-01-01 00:00:01.500000 +c15 1000-01-01 00:00:01.500000 +c16 1000-01-01 00:00:01.500000 +c17 1000-01-01 00:00:01.500000 +c18 1000-01-01 00:00:01.500000 +c19 1000-01-01 00:00:01.500000 +c20 NULL +# +# End of 10.1 tests +# create or replace view v1 as select 3 & 20010101 + interval 2 day as x; show create view v1; View Create View character_set_client collation_connection diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 4cb0cb43815..9b41c1f9d61 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -740,7 +740,7 @@ select json_extract('{"test":8.437e-5}','$.test'); json_extract('{"test":8.437e-5}','$.test') 8.437e-5 # -# Start of 10.3 tests +# End of 10.2 tests # # # MDEV-12854 Synchronize CREATE..SELECT data type and result set metadata data type for INT functions @@ -765,3 +765,6 @@ def json_length 3 10 1 Y 32896 0 63 def json_depnth 3 10 1 N 32897 0 63 json_length json_depnth 2 3 +# +# End of 10.3 tests +# diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 477a6a4041a..2772f850ce9 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -2905,6 +2905,30 @@ NULL Warnings: Warning 1441 Datetime function: datetime field overflow # +# MDEV-13202 Assertion `ltime->neg == 0' failed in date_to_datetime +# +CREATE TABLE t1 (i INT, d DATE); +INSERT INTO t1 VALUES (1, '1970-01-01'); +SELECT MAX(NULLIF(i,1)) FROM t1 ORDER BY DATE_SUB(d,INTERVAL 17300000 HOUR); +MAX(NULLIF(i,1)) +NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow +DROP TABLE t1; +CREATE TABLE t1 (i INT, d DATE); +INSERT INTO t1 VALUES (1, '1970-01-01'); +SELECT CONCAT(DATE_SUB(d, INTERVAL 17300000 HOUR)) FROM t1; +CONCAT(DATE_SUB(d, INTERVAL 17300000 HOUR)) +NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow +DROP TABLE t1; +SELECT CONCAT(DATE_SUB(TIMESTAMP'1970-01-01 00:00:00', INTERVAL 17300000 HOUR)); +CONCAT(DATE_SUB(TIMESTAMP'1970-01-01 00:00:00', INTERVAL 17300000 HOUR)) +NULL +Warnings: +Warning 1441 Datetime function: datetime field overflow +# # End of 10.0 tests # # diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index fe36ef9d442..6c206a1699d 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -721,6 +721,20 @@ SELECT * FROM t1 JOIN t2 ON c1 = c2 HAVING c2 > 'a' ORDER BY c2 LIMIT 1; c1 c2 x x DROP TABLE t1,t2; +# +# MDEV-6736: Valgrind warnings 'Invalid read' in subselect_engine::calc_const_tables with SQ +# in WHERE and HAVING, ORDER BY, materialization+semijoin +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (3),(8); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2),(1); +SELECT a FROM t1 +WHERE 9 IN ( SELECT MIN( a ) FROM t1 ) +HAVING a <> ( SELECT COUNT(*) FROM t2 ) +ORDER BY a; +a +DROP TABLE t1,t2; End of 10.0 tests # # MDEV-10716: Assertion `real_type() != FIELD_ITEM' failed in diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index d27a136a6c4..6753349dece 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -2438,11 +2438,27 @@ CREATE TABLE t1 (b1 BIT NOT NULL); INSERT INTO t1 VALUES (0),(1); CREATE TABLE t2 (b2 BIT NOT NULL); INSERT INTO t2 VALUES (0),(1); -SET SESSION JOIN_CACHE_LEVEL = 3; +set @save_join_cache_level= @@join_cache_level; +SET @@join_cache_level = 3; SELECT t1.b1+'0' , t2.b2 + '0' FROM t1 LEFT JOIN t2 ON b1 = b2; t1.b1+'0' t2.b2 + '0' 0 0 1 1 DROP TABLE t1, t2; +set @join_cache_level= @save_join_cache_level; +# +# MDEV-14779: using left join causes incorrect results with materialization and derived tables +# +create table t1(id int); +insert into t1 values (1),(2); +create table t2(sid int, id int); +insert into t2 values (1,1),(2,2); +select * from t1 t +left join (select * from t2 where sid in (select max(sid) from t2 where 0=1 group by id)) r +on t.id=r.id ; +id sid id +1 NULL NULL +2 NULL NULL +drop table t1, t2; # end of 5.5 tests SET optimizer_switch=@save_optimizer_switch; diff --git a/mysql-test/r/join_outer_jcl6.result b/mysql-test/r/join_outer_jcl6.result index 72527040301..9ff501baf6a 100644 --- a/mysql-test/r/join_outer_jcl6.result +++ b/mysql-test/r/join_outer_jcl6.result @@ -2449,12 +2449,28 @@ CREATE TABLE t1 (b1 BIT NOT NULL); INSERT INTO t1 VALUES (0),(1); CREATE TABLE t2 (b2 BIT NOT NULL); INSERT INTO t2 VALUES (0),(1); -SET SESSION JOIN_CACHE_LEVEL = 3; +set @save_join_cache_level= @@join_cache_level; +SET @@join_cache_level = 3; SELECT t1.b1+'0' , t2.b2 + '0' FROM t1 LEFT JOIN t2 ON b1 = b2; t1.b1+'0' t2.b2 + '0' 0 0 1 1 DROP TABLE t1, t2; +set @join_cache_level= @save_join_cache_level; +# +# MDEV-14779: using left join causes incorrect results with materialization and derived tables +# +create table t1(id int); +insert into t1 values (1),(2); +create table t2(sid int, id int); +insert into t2 values (1,1),(2,2); +select * from t1 t +left join (select * from t2 where sid in (select max(sid) from t2 where 0=1 group by id)) r +on t.id=r.id ; +id sid id +1 NULL NULL +2 NULL NULL +drop table t1, t2; # end of 5.5 tests SET optimizer_switch=@save_optimizer_switch; set join_cache_level=default; diff --git a/mysql-test/r/ps_qc_innodb.result b/mysql-test/r/ps_qc_innodb.result new file mode 100644 index 00000000000..29c364348dc --- /dev/null +++ b/mysql-test/r/ps_qc_innodb.result @@ -0,0 +1,29 @@ +# +# MDEV-15492: Subquery crash similar to MDEV-10050 +# +SET @qcs.save= @@global.query_cache_size, @qct.save= @@global.query_cache_type; +SET GLOBAL query_cache_size= 512*1024*1024, query_cache_type= ON; +connect con1,localhost,root,,test; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +CREATE VIEW v AS select a from t1 join t2; +PREPARE stmt1 FROM "SELECT * FROM t1 WHERE a in (SELECT a FROM v)"; +connect con2,localhost,root,,test; +PREPARE stmt2 FROM "SELECT * FROM t1 WHERE a in (SELECT a FROM v)"; +EXECUTE stmt2; +a +connection con1; +EXECUTE stmt1; +a +INSERT INTO t2 VALUES (0); +EXECUTE stmt1; +a +START TRANSACTION; +EXECUTE stmt1; +a +disconnect con1; +disconnect con2; +connection default; +DROP VIEW v; +DROP TABLE t1, t2; +SET GLOBAL query_cache_size= @qcs.save, query_cache_type= @qct.save; diff --git a/mysql-test/r/shutdown.result b/mysql-test/r/shutdown.result index be2eb16470c..7a69f58ffd9 100644 --- a/mysql-test/r/shutdown.result +++ b/mysql-test/r/shutdown.result @@ -13,4 +13,4 @@ drop user user1@localhost; # # MDEV-8491 - On shutdown, report the user and the host executed that. # -FOUND 2 /mysqld(\.exe)? \(root\[root\] @ localhost \[(::1)?\]\): Normal shutdown/ in mysqld.1.err +FOUND 2 /mysqld(\.exe)? \(initiated by: root\[root\] @ localhost \[(::1)?\]\): Normal shutdown/ in mysqld.1.err diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index d3f46429cf7..25290650e9b 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2489,6 +2489,17 @@ FROM t2 WHERE b <= 'quux' GROUP BY field; field COUNT(DISTINCT c) 0 1 drop table t1,t2; +# +# MDEV-15555: select from DUAL where false yielding wrong result when in a IN +# +explain +SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); +2 IN (SELECT 2 from DUAL WHERE 1 != 1) +0 SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; # diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index 6b5db62093e..4d425d0fe5c 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -2757,6 +2757,21 @@ a b sq 4 2 1 drop table t1, t2; # +# MDEV-15235: Assertion `length > 0' failed in create_ref_for_key +# +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (f CHAR(1)); +INSERT INTO t2 VALUES ('a'),('b'); +explain +SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 ); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 +SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 ); +f +DROP TABLE t1, t2; +# # MDEV-9489: Assertion `0' failed in Protocol::end_statement() on # UNION ALL # diff --git a/mysql-test/r/type_temporal_innodb.result b/mysql-test/r/type_temporal_innodb.result index ce2b3a4e53f..b869822722d 100644 --- a/mysql-test/r/type_temporal_innodb.result +++ b/mysql-test/r/type_temporal_innodb.result @@ -154,3 +154,9 @@ SELECT 1 FROM t1 WHERE (SELECT a FROM t1 group by c) = b; Warnings: Warning 1292 Incorrect datetime value: '' DROP TABLE t1; +CREATE TABLE t1 (d DATE) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('2012-12-21'); +SELECT * FROM t1 WHERE LEAST( UTC_TIME(), d ); +d +2012-12-21 +DROP TABLE t1; diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index 3f34ae6c09b..5cdd3b00924 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -822,7 +822,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and <cache>(octet_length(TIME'10:20:30')) = 30 + rand() -# Old mode, TIMESTAMP literal, zon-zero YYYYMMDD, no propagation +# Old mode, TIMESTAMP literal, non-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30'; a 34:20:30 @@ -860,7 +860,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = TIME'10:20:30' and <cache>(octet_length(TIME'10:20:30')) = 30 + rand() -# Old mode, TIMESTAMP-alike literal, zon-zero YYYYMMDD, no propagation +# Old mode, TIMESTAMP-alike literal, non-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a='0000-00-01 10:20:30'; a 34:20:30 @@ -1215,6 +1215,37 @@ MAX(a) MAX(COALESCE(a)) 10:20:30 10:20:30 DROP TABLE t1; # +# MDEV-15321: different results when using value of optimizer_use_condition_selectivity=4 and =1 +# +SET @save_old_mode=@@old_mode; +SET @@old_mode=zero_date_time_cast; +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('0000-00-00 10:20:30'),('0000-00-00 10:20:31'); +INSERT INTO t1 VALUES ('0000-00-01 10:20:30'),('0000-00-01 10:20:31'); +INSERT INTO t1 VALUES ('31 10:20:30'),('32 10:20:30'),('33 10:20:30'),('34 10:20:30'); +SET @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +SET @@optimizer_use_condition_selectivity=1; +SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +a +34:20:30 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 8 +SET @@optimizer_use_condition_selectivity=4; +SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +a +34:20:30 +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where +Warnings: +Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = '0000-00-01 10:20:30' and octet_length(`test`.`t1`.`a`) = 8 +drop table t1; +SET @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +set @@old_mode= @save_old_mode; +# # End of 10.1 tests # # diff --git a/mysql-test/suite.pm b/mysql-test/suite.pm index c8201b0a554..0baa8a41639 100644 --- a/mysql-test/suite.pm +++ b/mysql-test/suite.pm @@ -26,6 +26,9 @@ sub skip_combinations { die "unknown value max-binlog-stmt-cache-size=$longsysvar" unless $val_map{$longsysvar}; $skip{'include/word_size.combinations'} = [ $val_map{$longsysvar} ]; + $skip{'include/maybe_debug.combinations'} = + [ defined $::mysqld_variables{'debug-dbug'} ? 'release' : 'debug' ]; + # as a special case, disable certain include files as a whole $skip{'include/not_embedded.inc'} = 'Not run for embedded server' if $::opt_embedded_server; diff --git a/mysql-test/suite/encryption/r/encrypt_and_grep.result b/mysql-test/suite/encryption/r/encrypt_and_grep.result index cbc05dc7cc6..e5ba46d10d2 100644 --- a/mysql-test/suite/encryption/r/encrypt_and_grep.result +++ b/mysql-test/suite/encryption/r/encrypt_and_grep.result @@ -13,12 +13,12 @@ NAME test/t3 SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; NAME -mysql/innodb_table_stats +innodb_system mysql/innodb_index_stats +mysql/innodb_table_stats mysql/transaction_registry test/t1 test/t2 -innodb_system # t1 yes on expecting NOT FOUND NOT FOUND /foobarsecret/ in t1.ibd # t2 ... on expecting NOT FOUND @@ -32,12 +32,12 @@ SET GLOBAL innodb_encrypt_tables = off; # Wait max 10 min for key encryption threads to decrypt all spaces SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; NAME -mysql/innodb_table_stats +innodb_system mysql/innodb_index_stats +mysql/innodb_table_stats mysql/transaction_registry test/t2 test/t3 -innodb_system SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; NAME test/t1 @@ -57,12 +57,12 @@ NAME test/t3 SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; NAME -mysql/innodb_table_stats +innodb_system mysql/innodb_index_stats +mysql/innodb_table_stats mysql/transaction_registry test/t1 test/t2 -innodb_system # t1 yes on expecting NOT FOUND NOT FOUND /foobarsecret/ in t1.ibd # t2 ... on expecting NOT FOUND diff --git a/mysql-test/suite/encryption/r/innodb-discard-import.result b/mysql-test/suite/encryption/r/innodb-discard-import.result index 69641be92f1..91314a77177 100644 --- a/mysql-test/suite/encryption/r/innodb-discard-import.result +++ b/mysql-test/suite/encryption/r/innodb-discard-import.result @@ -129,6 +129,6 @@ NOT FOUND /barfoo/ in t2.ibd # t3 yes on expecting NOT FOUND NOT FOUND /tmpres/ in t3.ibd # t4 yes on expecting NOT FOUND -# MDEV-15527 FIXME: Enable this test! +NOT FOUND /mysql/ in t4.ibd DROP PROCEDURE innodb_insert_proc; DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/encryption/r/innodb-spatial-index.result b/mysql-test/suite/encryption/r/innodb-spatial-index.result index e8e133c61a1..7cc6d86e48d 100644 --- a/mysql-test/suite/encryption/r/innodb-spatial-index.result +++ b/mysql-test/suite/encryption/r/innodb-spatial-index.result @@ -36,12 +36,12 @@ INSERT INTO t2 values(1, 'secret', ST_GeomFromText('POINT(903994614 180726515)') # Success! SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION > 0; NAME -mysql/innodb_table_stats +innodb_system mysql/innodb_index_stats +mysql/innodb_table_stats mysql/transaction_registry test/t1 test/t2 -innodb_system SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; NAME DROP TABLE t1, t2; diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result index ee3774bcee0..559430e0210 100644 --- a/mysql-test/suite/encryption/r/innodb_encryption.result +++ b/mysql-test/suite/encryption/r/innodb_encryption.result @@ -8,25 +8,23 @@ innodb_encryption_rotation_iops 100 innodb_encryption_threads 4 SET GLOBAL innodb_encrypt_tables = ON; # Wait max 10 min for key encryption threads to encrypt all spaces -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -mysql/innodb_table_stats -mysql/innodb_index_stats -mysql/transaction_registry innodb_system # Success! # Now turn off encryption and wait for threads to decrypt everything SET GLOBAL innodb_encrypt_tables = off; # Wait max 10 min for key encryption threads to encrypt all spaces -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -mysql/innodb_table_stats -mysql/innodb_index_stats -mysql/transaction_registry innodb_system -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME # Success! # Shutdown innodb_encryption_threads @@ -35,25 +33,23 @@ SET GLOBAL innodb_encryption_threads=0; # since threads are off tables should remain unencrypted SET GLOBAL innodb_encrypt_tables = on; # Wait 15s to check that nothing gets encrypted -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -mysql/innodb_table_stats -mysql/innodb_index_stats -mysql/transaction_registry innodb_system -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME # Success! # Startup innodb_encryption_threads SET GLOBAL innodb_encryption_threads=@start_global_value; # Wait max 10 min for key encryption threads to encrypt all spaces -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -mysql/innodb_table_stats -mysql/innodb_index_stats -mysql/transaction_registry innodb_system # Success! # Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0 @@ -64,11 +60,10 @@ innodb_encrypt_tables OFF innodb_encryption_rotate_key_age 15 innodb_encryption_rotation_iops 100 innodb_encryption_threads 0 -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME -mysql/innodb_table_stats -mysql/innodb_index_stats -mysql/transaction_registry innodb_system -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME diff --git a/mysql-test/suite/encryption/t/encrypt_and_grep.test b/mysql-test/suite/encryption/t/encrypt_and_grep.test index 9f26f0a5b24..5fec86304b4 100644 --- a/mysql-test/suite/encryption/t/encrypt_and_grep.test +++ b/mysql-test/suite/encryption/t/encrypt_and_grep.test @@ -30,7 +30,9 @@ insert t3 values (repeat('dummysecret', 12)); --let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 --source include/wait_condition.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/shutdown_mysqld.inc @@ -64,7 +66,9 @@ SET GLOBAL innodb_encrypt_tables = off; --let $wait_condition=SELECT COUNT(*) = $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND CURRENT_KEY_VERSION = 0; --source include/wait_condition.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/shutdown_mysqld.inc @@ -97,7 +101,9 @@ SET GLOBAL innodb_encrypt_tables = on; --let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; --source include/wait_condition.inc +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/shutdown_mysqld.inc diff --git a/mysql-test/suite/encryption/t/innodb-discard-import.test b/mysql-test/suite/encryption/t/innodb-discard-import.test index 9e78df813f9..e105cf82b67 100644 --- a/mysql-test/suite/encryption/t/innodb-discard-import.test +++ b/mysql-test/suite/encryption/t/innodb-discard-import.test @@ -111,8 +111,7 @@ SELECT COUNT(*) FROM t4; --let SEARCH_PATTERN=mysql --echo # t4 yes on expecting NOT FOUND -- let SEARCH_FILE=$t4_IBD ---echo # MDEV-15527 FIXME: Enable this test! -#-- source include/search_pattern_in_file.inc +-- source include/search_pattern_in_file.inc DROP PROCEDURE innodb_insert_proc; DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/suite/encryption/t/innodb-spatial-index.test b/mysql-test/suite/encryption/t/innodb-spatial-index.test index 8eb6a803765..28b35379a6b 100644 --- a/mysql-test/suite/encryption/t/innodb-spatial-index.test +++ b/mysql-test/suite/encryption/t/innodb-spatial-index.test @@ -69,7 +69,9 @@ INSERT INTO t2 values(1, 'secret', ST_GeomFromText('POINT(903994614 180726515)') --echo # Success! +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION > 0; +--sorted_result SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; DROP TABLE t1, t2; diff --git a/mysql-test/suite/encryption/t/innodb_encryption.test b/mysql-test/suite/encryption/t/innodb_encryption.test index d183a2914bd..a1abfb51462 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption.test +++ b/mysql-test/suite/encryption/t/innodb_encryption.test @@ -21,8 +21,12 @@ SET GLOBAL innodb_encrypt_tables = ON; --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; --echo # Success! @@ -34,8 +38,12 @@ SET GLOBAL innodb_encrypt_tables = off; --let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; --echo # Success! @@ -51,8 +59,12 @@ SET GLOBAL innodb_encrypt_tables = on; --let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; --echo # Success! @@ -64,8 +76,12 @@ SET GLOBAL innodb_encryption_threads=@start_global_value; --let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; --echo # Success! --echo # Restart mysqld --innodb_encrypt_tables=0 --innodb_encryption_threads=0 @@ -74,5 +90,9 @@ SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_ SHOW VARIABLES LIKE 'innodb_encrypt%'; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; -SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; diff --git a/mysql-test/suite/encryption/t/innodb_scrub_background.test b/mysql-test/suite/encryption/t/innodb_scrub_background.test index c705ee51006..3843e9d16eb 100644 --- a/mysql-test/suite/encryption/t/innodb_scrub_background.test +++ b/mysql-test/suite/encryption/t/innodb_scrub_background.test @@ -96,7 +96,7 @@ SET GLOBAL innodb_encryption_threads=5; let $cnt=600; while ($cnt) { - let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING WHERE LAST_SCRUB_COMPLETED IS NULL AND ( NAME in ('test/t1', 'test/t2', 'test/t3') OR SPACE = 0 )`; + let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_SCRUBBING WHERE LAST_SCRUB_COMPLETED IS NULL AND (NAME LIKE 'test/%' OR SPACE = 0)`; if ($success) { let $cnt=0; diff --git a/mysql-test/suite/engines/iuds/r/update_time.result b/mysql-test/suite/engines/iuds/r/update_time.result index 48ddb82d521..131780059dd 100644 --- a/mysql-test/suite/engines/iuds/r/update_time.result +++ b/mysql-test/suite/engines/iuds/r/update_time.result @@ -1215,7 +1215,7 @@ c1 c2 838:59:59 838:59:59 UPDATE IGNORE t1 SET t1.c2='99999.99999' WHERE c1 BETWEEN 080000 AND 100000; Warnings: -Warning 1265 Data truncated for column 'c2' at row 1 +Warning 1265 Data truncated for column 'c2' at row N SELECT * FROM t1; c1 c2 -12:12:12 12:12:12 diff --git a/mysql-test/suite/engines/iuds/t/update_time.test b/mysql-test/suite/engines/iuds/t/update_time.test index 5ce69b46986..bdfe81d3c7c 100644 --- a/mysql-test/suite/engines/iuds/t/update_time.test +++ b/mysql-test/suite/engines/iuds/t/update_time.test @@ -172,6 +172,7 @@ SELECT * FROM t1; # Update using range # EXPLAIN SELECT * FROM t1 WHERE c1 BETWEEN 080000 AND 100000; +--replace_regex /(Data truncated for column 'c2' at row) [1-9][0-9]*/\1 N/ UPDATE IGNORE t1 SET t1.c2='99999.99999' WHERE c1 BETWEEN 080000 AND 100000; --sorted_result SELECT * FROM t1; diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 8db0073d268..9b7e442a290 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -9,18 +9,14 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -MW-336 : MDEV-13549 Galera test failures galera_gra_log : MDEV-13549 Galera test failures -galera_flush_local : MDEV-13549 Galera test failures galera_flush : MDEV-13549 Galera test failures -MW-329 : MDEV-13549 Galera test failures galera_account_management : MariaDB 10.0 does not support ALTER USER galera_binlog_row_image : MariaDB 10.0 does not support binlog_row_image galera_binlog_rows_query_log_events: MariaDB does not support binlog_rows_query_log_events GAL-419 : MDEV-13549 Galera test failures galera_toi_ddl_fk_insert : MDEV-13549 Galera test failures galera_var_notify_cmd : MDEV-13549 Galera test failures -galera_var_slave_threads : MDEV-13549 Galera test failures mysql-wsrep#90 : MDEV-13549 Galera test failures galera_as_master_gtid : Requires MySQL GTID galera_as_master_gtid_change_master : Requires MySQL GTID @@ -34,7 +30,6 @@ galera_ist_mysqldump : MDEV-13549 Galera test failures mysql-wsrep#31 : MDEV-13549 Galera test failures galera_migrate : MariaDB 10.0 does not support START SLAVE USER galera_concurrent_ctas : MDEV-13549 Galera test failures -galera_bf_abort_for_update : MDEV-13549 Galera test failures galera_wsrep_desync_wsrep_on : MDEV-13549 Galera test failures galera_ssl_upgrade : MDEV-13549 Galera test failures mysql-wsrep#33 : MDEV-13549 Galera test failures @@ -47,7 +42,6 @@ lp1376747 : MDEV-13549 Galera test failures galera_toi_ddl_nonconflicting : MDEV-13549 Galera test failures galera_parallel_simple : MDEV-13549 Galera test failures galera_admin : MDEV-13549 Galera test failures -galera_var_max_ws_rows : MDEV-13549 Galera test failures 10.1 MW-286 : MDEV-13549 Galera test failures 10.1 galera_as_master: MDEV-13549 Galera test failures 10.1 galera_pc_ignore_sb : MDEV-13549 Galera test failures 10.1 @@ -65,3 +59,4 @@ galera_ist_progress: MDEV-15236 galera_ist_progress fails when trying to read tr galera_gtid : MDEV-13549 Galera test failures 10.1 galera_gtid_slave : MDEV-13549 Galera test failures 10.1 galera_unicode_identifiers : MDEV-13549 Galera test failures 10.1 +galera.galera_gcs_fc_limit : MDEV-13549 Galera test failures 10.1 diff --git a/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc b/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc index cbd2c1c817a..16af5742b9b 100644 --- a/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc +++ b/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc @@ -4,6 +4,9 @@ --echo Setting SST method to mysqldump ... +call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'"); +call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); + --connection node_1 # We need a user with a password to perform SST, otherwise we hit LP #1378253 CREATE USER 'sst'; @@ -19,6 +22,6 @@ SET GLOBAL wsrep_sst_auth = 'sst:'; --disable_query_log # Set wsrep_sst_receive_address to the SQL port ---eval SET GLOBAL wsrep_sst_receive_address = '127.0.0.2:$NODE_MYPORT_2'; +--eval SET GLOBAL wsrep_sst_receive_address = '127.0.0.1:$NODE_MYPORT_2'; --enable_query_log SET GLOBAL wsrep_sst_method = 'mysqldump'; diff --git a/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc b/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc index b8dd0fda987..72e80505870 100644 --- a/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc +++ b/mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc @@ -1,3 +1,5 @@ +source include/maybe_debug.inc; +if ($have_debug) { --echo Performing State Transfer on a server that has been killed and restarted --echo while a DDL was in progress on it @@ -121,3 +123,4 @@ COMMIT; SET AUTOCOMMIT=ON; SET GLOBAL debug_dbug = $debug_orig; +} diff --git a/mysql-test/suite/galera/include/galera_wsrep_recover.inc b/mysql-test/suite/galera/include/galera_wsrep_recover.inc index 090ffe5f5df..d2956ea99e6 100644 --- a/mysql-test/suite/galera/include/galera_wsrep_recover.inc +++ b/mysql-test/suite/galera/include/galera_wsrep_recover.inc @@ -1,5 +1,5 @@ --echo Performing --wsrep-recover ... ---exec $MYSQLD --defaults-group-suffix=.$galera_wsrep_recover_server_id --defaults-file=$MYSQLTEST_VARDIR/my.cnf --innodb --wsrep-recover > $MYSQL_TMP_DIR/galera_wsrep_recover.log 2>&1 +--exec $MYSQLD --defaults-group-suffix=.$galera_wsrep_recover_server_id --defaults-file=$MYSQLTEST_VARDIR/my.cnf --log-error=$MYSQL_TMP_DIR/galera_wsrep_recover.log --innodb --wsrep-recover > $MYSQL_TMP_DIR/galera_wsrep_recover.log 2>&1 --perl use strict; diff --git a/mysql-test/suite/galera/include/have_mariabackup.inc b/mysql-test/suite/galera/include/have_mariabackup.inc new file mode 100644 index 00000000000..0dd693f2c63 --- /dev/null +++ b/mysql-test/suite/galera/include/have_mariabackup.inc @@ -0,0 +1,4 @@ +# +# suite.pm will make sure that all tests including this file +# will be skipped as needed +# diff --git a/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc b/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc new file mode 100644 index 00000000000..726fc6e2b18 --- /dev/null +++ b/mysql-test/suite/galera/include/have_wsrep_replicate_myisam.inc @@ -0,0 +1,4 @@ +--require suite/galera/r/have_wsrep_replicate_myisam.require +disable_query_log; +SHOW VARIABLES LIKE 'wsrep_replicate_myisam'; +enable_query_log; diff --git a/mysql-test/suite/galera/include/have_xtrabackup.inc b/mysql-test/suite/galera/include/have_xtrabackup.inc new file mode 100644 index 00000000000..0dd693f2c63 --- /dev/null +++ b/mysql-test/suite/galera/include/have_xtrabackup.inc @@ -0,0 +1,4 @@ +# +# suite.pm will make sure that all tests including this file +# will be skipped as needed +# diff --git a/mysql-test/suite/galera/r/MW-329.result b/mysql-test/suite/galera/r/MW-329.result index af57bc4b056..a3cb7277a9c 100644 --- a/mysql-test/suite/galera/r/MW-329.result +++ b/mysql-test/suite/galera/r/MW-329.result @@ -27,3 +27,4 @@ connection node_1; DROP PROCEDURE proc_insert; DROP TABLE t1; CALL mtr.add_suppression("conflict state 3 after post commit"); +set global innodb_status_output=Default; diff --git a/mysql-test/suite/galera/r/MW-336.result b/mysql-test/suite/galera/r/MW-336.result index 9bdb61c1a9c..0bf8d9d3909 100644 --- a/mysql-test/suite/galera/r/MW-336.result +++ b/mysql-test/suite/galera/r/MW-336.result @@ -1,16 +1,14 @@ CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB; +connection node_1; SET GLOBAL wsrep_slave_threads = 10; SET GLOBAL wsrep_slave_threads = 1; +connection node_2; INSERT INTO t1 VALUES (1); +connection node_1; SET GLOBAL wsrep_slave_threads = 10; -SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; -COUNT(*) = 11 -1 SET GLOBAL wsrep_slave_threads = 20; -SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; -COUNT(*) = 21 -1 SET GLOBAL wsrep_slave_threads = 1; +connection node_2; INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); @@ -20,10 +18,12 @@ INSERT INTO t1 VALUES (6); INSERT INTO t1 VALUES (7); INSERT INTO t1 VALUES (8); INSERT INTO t1 VALUES (9); +connection node_1; SET GLOBAL wsrep_slave_threads = 10; SET GLOBAL wsrep_slave_threads = 0; Warnings: Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' +connection node_2; INSERT INTO t1 VALUES (10); INSERT INTO t1 VALUES (11); INSERT INTO t1 VALUES (12); @@ -35,8 +35,6 @@ INSERT INTO t1 VALUES (17); INSERT INTO t1 VALUES (18); INSERT INTO t1 VALUES (19); INSERT INTO t1 VALUES (20); -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; -COUNT(*) = 2 -1 +connection node_1; SET GLOBAL wsrep_slave_threads = 1; DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_for_update.result b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result index 3978a3df193..ec8bddb087a 100644 --- a/mysql-test/suite/galera/r/galera_bf_abort_for_update.result +++ b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result @@ -1,10 +1,29 @@ -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 VALUES (1); -INSERT INTO t1 VALUES (1); +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 10); +connection node_1; +BEGIN; SELECT * FROM t1 FOR UPDATE; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -wsrep_local_aborts_increment +f1 f2 +1 10 +connection node_2; +UPDATE t1 SET f1 = 2; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1; +COMMIT; +ERROR 40001: Deadlock: wsrep aborted transaction +wsrep_local_bf_aborts_diff +1 +connection node_1; +BEGIN; +SELECT * FROM t1 FOR UPDATE; +f1 f2 +2 10 +connection node_2; +UPDATE t1 SET f2 = 20; +connection node_1a; +connection node_1; +COMMIT; +ERROR 40001: Deadlock: wsrep aborted transaction +wsrep_local_bf_aborts_diff 1 DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result index d3004735a0a..5c5fdabf432 100644 --- a/mysql-test/suite/galera/r/galera_defaults.result +++ b/mysql-test/suite/galera/r/galera_defaults.result @@ -1,6 +1,6 @@ SELECT COUNT(*) = 43 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%'; COUNT(*) = 43 -1 +0 SELECT VARIABLE_NAME, VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%' @@ -40,6 +40,7 @@ WSREP_NOTIFY_CMD WSREP_ON ON WSREP_OSU_METHOD TOI WSREP_RECOVER OFF +WSREP_REJECT_QUERIES NONE WSREP_REPLICATE_MYISAM OFF WSREP_RESTART_SLAVE OFF WSREP_RETRY_AUTOCOMMIT 1 diff --git a/mysql-test/suite/galera/r/galera_flush_local.result b/mysql-test/suite/galera/r/galera_flush_local.result index 3fdd541b513..a8e798a693d 100644 --- a/mysql-test/suite/galera/r/galera_flush_local.result +++ b/mysql-test/suite/galera/r/galera_flush_local.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1, t2, x1, x2; +connection node_1; CREATE TABLE t1 (f1 INTEGER); CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER); CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM; @@ -7,6 +8,8 @@ INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4; INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +connection node_2; +connection node_1; FLUSH LOCAL DES_KEY_FILE; FLUSH LOCAL HOSTS; FLUSH LOCAL QUERY CACHE; @@ -54,6 +57,7 @@ REPAIR LOCAL TABLE x1, x2; Table Op Msg_type Msg_text test.x1 repair status OK test.x2 repair status OK +connection node_2; wsrep_last_committed_diff 1 SELECT COUNT(*) = 10 FROM t1; @@ -68,6 +72,7 @@ COUNT(*) = 10000 SELECT COUNT(*) = 10 FROM x2; COUNT(*) = 10 1 +connection node_1; DROP TABLE t1, t2, x1, x2; CREATE TABLE t1 (f1 INTEGER); CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER); @@ -77,6 +82,8 @@ INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4; INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +connection node_2; +connection node_1; set wsrep_on=0; FLUSH DES_KEY_FILE; FLUSH HOSTS; @@ -125,6 +132,7 @@ REPAIR TABLE x1, x2; Table Op Msg_type Msg_text test.x1 repair status OK test.x2 repair status OK +connection node_2; wsrep_last_committed_diff 1 wsrep_last_committed_diff2 @@ -141,5 +149,6 @@ COUNT(*) = 10000 SELECT COUNT(*) = 10 FROM x2; COUNT(*) = 10 1 +connection node_1; set wsrep_on=1; DROP TABLE t1, t2, x1, x2; diff --git a/mysql-test/suite/galera/r/galera_schema_dirty_reads.result b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result new file mode 100644 index 00000000000..edf20da92c6 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result @@ -0,0 +1,13 @@ +USE information_schema; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; +VARIABLE_NAME VARIABLE_VALUE +WSREP_DIRTY_READS OFF +SET GLOBAL wsrep_reject_queries=ALL; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; +VARIABLE_NAME VARIABLE_VALUE +WSREP_DIRTY_READS OFF +SET GLOBAL wsrep_reject_queries=NONE; +SET SESSION wsrep_dirty_reads=TRUE; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; +VARIABLE_NAME VARIABLE_VALUE +WSREP_DIRTY_READS ON diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_mariabackup,debug.rdiff new file mode 100644 index 00000000000..8b091eb370a --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mariabackup,debug.rdiff @@ -0,0 +1,116 @@ +--- galera_sst_mariabackup.result ++++ galera_sst_mariabackup,debug.reject +@@ -286,5 +286,113 @@ + DROP TABLE t1; + COMMIT; + SET AUTOCOMMIT=ON; ++Performing State Transfer on a server that has been killed and restarted ++while a DDL was in progress on it ++connection node_1; ++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++connection node_2; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++COMMIT; ++SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; ++connection node_1; ++ALTER TABLE t1 ADD COLUMN f2 INTEGER; ++connection node_2; ++SET wsrep_sync_wait = 0; ++Killing server ... ++connection node_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++COMMIT; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++connection node_2; ++Performing --wsrep-recover ... ++connection node_2; ++Starting server ... ++Using --wsrep-start-position when starting mysqld ... ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++COMMIT; ++connection node_1; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++COMMIT; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++COMMIT; ++connection node_1a_galera_st_kill_slave_ddl; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++ROLLBACK; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++COMMIT; ++SET AUTOCOMMIT=ON; ++connection node_1; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++DROP TABLE t1; ++COMMIT; ++SET AUTOCOMMIT=ON; ++SET GLOBAL debug_dbug = $debug_orig; + disconnect node_2; + disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup.result b/mysql-test/suite/galera/r/galera_sst_mariabackup.result new file mode 100644 index 00000000000..fdb5883b590 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mariabackup.result @@ -0,0 +1,290 @@ +connection node_1; +connection node_2; +Performing State Transfer on a server that has been shut down cleanly and restarted +connection node_1; +CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +COMMIT; +connection node_2; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +COMMIT; +Shutting down server ... +connection node_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +COMMIT; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_shutdown_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; +Starting server ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +COMMIT; +connection node_1; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +COMMIT; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +COMMIT; +connection node_1a_galera_st_shutdown_slave; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +ROLLBACK; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +COMMIT; +SET AUTOCOMMIT=ON; +connection node_1; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +DROP TABLE t1; +COMMIT; +SET AUTOCOMMIT=ON; +Performing State Transfer on a server that starts from a clean var directory +This is accomplished by shutting down node #2 and removing its var directory before restarting it +connection node_1; +CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +COMMIT; +connection node_2; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +COMMIT; +Shutting down server ... +connection node_1; +Cleaning var directory ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +COMMIT; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; +Starting server ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +COMMIT; +connection node_1; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +COMMIT; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +COMMIT; +connection node_1a_galera_st_clean_slave; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +ROLLBACK; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +COMMIT; +SET AUTOCOMMIT=ON; +connection node_1; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +DROP TABLE t1; +COMMIT; +SET AUTOCOMMIT=ON; +Performing State Transfer on a server that has been killed and restarted +connection node_1; +CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +INSERT INTO t1 VALUES ('node1_committed_before'); +COMMIT; +connection node_2; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +INSERT INTO t1 VALUES ('node2_committed_before'); +COMMIT; +Killing server ... +connection node_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +INSERT INTO t1 VALUES ('node1_committed_during'); +COMMIT; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_kill_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; +Performing --wsrep-recover ... +Starting server ... +Using --wsrep-start-position when starting mysqld ... +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +INSERT INTO t1 VALUES ('node2_committed_after'); +COMMIT; +connection node_1; +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +COMMIT; +SET AUTOCOMMIT=OFF; +START TRANSACTION; +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +INSERT INTO t1 VALUES ('node1_committed_after'); +COMMIT; +connection node_1a_galera_st_kill_slave; +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +ROLLBACK; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +COMMIT; +SET AUTOCOMMIT=ON; +connection node_1; +SELECT COUNT(*) = 35 FROM t1; +COUNT(*) = 35 +1 +SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; +COUNT(*) = 0 +1 +DROP TABLE t1; +COMMIT; +SET AUTOCOMMIT=ON; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff new file mode 100644 index 00000000000..3eadee615ed --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff @@ -0,0 +1,117 @@ +--- galera_sst_mysqldump.result ++++ galera_sst_mysqldump,debug.reject +@@ -388,6 +388,114 @@ + DROP TABLE t1; + COMMIT; + SET AUTOCOMMIT=ON; ++Performing State Transfer on a server that has been killed and restarted ++while a DDL was in progress on it ++connection node_1; ++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++connection node_2; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++COMMIT; ++SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; ++connection node_1; ++ALTER TABLE t1 ADD COLUMN f2 INTEGER; ++connection node_2; ++SET wsrep_sync_wait = 0; ++Killing server ... ++connection node_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++COMMIT; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++connection node_2; ++Performing --wsrep-recover ... ++connection node_2; ++Starting server ... ++Using --wsrep-start-position when starting mysqld ... ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++COMMIT; ++connection node_1; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++COMMIT; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++COMMIT; ++connection node_1a_galera_st_kill_slave_ddl; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++ROLLBACK; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++COMMIT; ++SET AUTOCOMMIT=ON; ++connection node_1; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++DROP TABLE t1; ++COMMIT; ++SET AUTOCOMMIT=ON; ++SET GLOBAL debug_dbug = $debug_orig; + connection node_1; + CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query"); + DROP USER sst; diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump.result b/mysql-test/suite/galera/r/galera_sst_mysqldump.result index 304ce165f3e..5c530c32ce6 100644 --- a/mysql-test/suite/galera/r/galera_sst_mysqldump.result +++ b/mysql-test/suite/galera/r/galera_sst_mysqldump.result @@ -1,9 +1,16 @@ Setting SST method to mysqldump ... +call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'"); +call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); +connection node_1; CREATE USER 'sst'; GRANT ALL PRIVILEGES ON *.* TO 'sst'; SET GLOBAL wsrep_sst_auth = 'sst:'; +connection node_2; SET GLOBAL wsrep_sst_method = 'mysqldump'; +connection node_1; +connection node_2; Performing State Transfer on a server that has been temporarily disconnected +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -13,6 +20,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -23,6 +31,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Unloading wsrep provider ... SET GLOBAL wsrep_provider = 'none'; +connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -37,6 +46,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_disconnect_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -44,6 +54,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Loading wsrep provider ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -53,6 +64,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -67,6 +79,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_disconnect_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -81,6 +94,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -91,6 +105,7 @@ DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; Performing State Transfer on a server that has been shut down cleanly and restarted +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -100,6 +115,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -109,6 +125,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Shutting down server ... +connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -123,6 +140,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_shutdown_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -130,6 +148,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Starting server ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -139,6 +158,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -153,6 +173,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_shutdown_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -167,6 +188,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -178,6 +200,7 @@ COMMIT; SET AUTOCOMMIT=ON; Performing State Transfer on a server that starts from a clean var directory This is accomplished by shutting down node #2 and removing its var directory before restarting it +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -187,6 +210,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -196,6 +220,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Shutting down server ... +connection node_1; Cleaning var directory ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -211,6 +236,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -218,6 +244,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Starting server ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -227,6 +254,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -241,6 +269,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_clean_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -255,6 +284,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -265,6 +295,7 @@ DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; Performing State Transfer on a server that has been killed and restarted +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -274,6 +305,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -283,6 +315,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Killing server ... +connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -297,6 +330,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_kill_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -304,6 +338,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Performing --wsrep-recover ... Starting server ... Using --wsrep-start-position when starting mysqld ... @@ -315,6 +350,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -329,6 +365,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_kill_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -343,6 +380,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -352,104 +390,10 @@ COUNT(*) = 0 DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; -Performing State Transfer on a server that has been killed and restarted -while a DDL was in progress on it -CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -START TRANSACTION; -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -COMMIT; -SET GLOBAL debug = 'd,sync.alter_opened_table'; -ALTER TABLE t1 ADD COLUMN f2 INTEGER; -SET wsrep_sync_wait = 0; -Killing server ... -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -COMMIT; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -Performing --wsrep-recover ... -Starting server ... -Using --wsrep-start-position when starting mysqld ... -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -COMMIT; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -COMMIT; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -COMMIT; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -ROLLBACK; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -COMMIT; -SET AUTOCOMMIT=ON; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -DROP TABLE t1; -COMMIT; -SET AUTOCOMMIT=ON; +connection node_1; CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query"); DROP USER sst; +connection node_2; CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query"); CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found"); CALL mtr.add_suppression("Can't open and lock time zone table"); diff --git a/mysql-test/suite/galera/r/galera_sst_rsync,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_rsync,debug.rdiff new file mode 100644 index 00000000000..94dd8c2e502 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_rsync,debug.rdiff @@ -0,0 +1,114 @@ +--- galera_sst_rsync.result ++++ galera_sst_rsync,debug.reject +@@ -284,3 +284,111 @@ + DROP TABLE t1; + COMMIT; + SET AUTOCOMMIT=ON; ++Performing State Transfer on a server that has been killed and restarted ++while a DDL was in progress on it ++connection node_1; ++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++connection node_2; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++COMMIT; ++SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; ++connection node_1; ++ALTER TABLE t1 ADD COLUMN f2 INTEGER; ++connection node_2; ++SET wsrep_sync_wait = 0; ++Killing server ... ++connection node_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++COMMIT; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++connection node_2; ++Performing --wsrep-recover ... ++connection node_2; ++Starting server ... ++Using --wsrep-start-position when starting mysqld ... ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++COMMIT; ++connection node_1; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++COMMIT; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++COMMIT; ++connection node_1a_galera_st_kill_slave_ddl; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++ROLLBACK; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++COMMIT; ++SET AUTOCOMMIT=ON; ++connection node_1; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++DROP TABLE t1; ++COMMIT; ++SET AUTOCOMMIT=ON; ++SET GLOBAL debug_dbug = $debug_orig; diff --git a/mysql-test/suite/galera/r/galera_sst_rsync.result b/mysql-test/suite/galera/r/galera_sst_rsync.result index b16a496554b..ff85a7d6c0f 100644 --- a/mysql-test/suite/galera/r/galera_sst_rsync.result +++ b/mysql-test/suite/galera/r/galera_sst_rsync.result @@ -1,3 +1,5 @@ +connection node_1; +connection node_2; Performing State Transfer on a server that has been shut down cleanly and restarted connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; @@ -284,111 +286,3 @@ COUNT(*) = 0 DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; -Performing State Transfer on a server that has been killed and restarted -while a DDL was in progress on it -connection node_1; -CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -connection node_2; -START TRANSACTION; -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -COMMIT; -SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; -connection node_1; -ALTER TABLE t1 ADD COLUMN f2 INTEGER; -connection node_2; -SET wsrep_sync_wait = 0; -Killing server ... -connection node_1; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -COMMIT; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -connection node_2; -Performing --wsrep-recover ... -connection node_2; -Starting server ... -Using --wsrep-start-position when starting mysqld ... -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -COMMIT; -connection node_1; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -COMMIT; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -COMMIT; -connection node_1a_galera_st_kill_slave_ddl; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -ROLLBACK; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -COMMIT; -SET AUTOCOMMIT=ON; -connection node_1; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -DROP TABLE t1; -COMMIT; -SET AUTOCOMMIT=ON; -SET GLOBAL debug_dbug = $debug_orig; diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2,debug.rdiff new file mode 100644 index 00000000000..8b091eb370a --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2,debug.rdiff @@ -0,0 +1,116 @@ +--- galera_sst_mariabackup.result ++++ galera_sst_mariabackup,debug.reject +@@ -286,5 +286,113 @@ + DROP TABLE t1; + COMMIT; + SET AUTOCOMMIT=ON; ++Performing State Transfer on a server that has been killed and restarted ++while a DDL was in progress on it ++connection node_1; ++CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++INSERT INTO t1 VALUES ('node1_committed_before'); ++connection node_2; ++START TRANSACTION; ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++INSERT INTO t1 VALUES ('node2_committed_before'); ++COMMIT; ++SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; ++connection node_1; ++ALTER TABLE t1 ADD COLUMN f2 INTEGER; ++connection node_2; ++SET wsrep_sync_wait = 0; ++Killing server ... ++connection node_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_during'); ++COMMIT; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++connect node_1a_galera_st_kill_slave_ddl, 127.0.0.1, root, , test, $NODE_MYPORT_1; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++connection node_2; ++Performing --wsrep-recover ... ++connection node_2; ++Starting server ... ++Using --wsrep-start-position when starting mysqld ... ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node2_committed_after'); ++COMMIT; ++connection node_1; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); ++COMMIT; ++SET AUTOCOMMIT=OFF; ++START TRANSACTION; ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++INSERT INTO t1 (f1) VALUES ('node1_committed_after'); ++COMMIT; ++connection node_1a_galera_st_kill_slave_ddl; ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); ++ROLLBACK; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++COMMIT; ++SET AUTOCOMMIT=ON; ++connection node_1; ++SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; ++COUNT(*) = 2 ++1 ++SELECT COUNT(*) = 35 FROM t1; ++COUNT(*) = 35 ++1 ++SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; ++COUNT(*) = 0 ++1 ++DROP TABLE t1; ++COMMIT; ++SET AUTOCOMMIT=ON; ++SET GLOBAL debug_dbug = $debug_orig; + disconnect node_2; + disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result index df2d9190a4b..fdb5883b590 100644 --- a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result +++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result @@ -1,4 +1,7 @@ +connection node_1; +connection node_2; Performing State Transfer on a server that has been shut down cleanly and restarted +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -8,6 +11,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -17,6 +21,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Shutting down server ... +connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -31,6 +36,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_shutdown_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -38,6 +44,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Starting server ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -47,6 +54,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -61,6 +69,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_shutdown_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -75,6 +84,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -86,6 +96,7 @@ COMMIT; SET AUTOCOMMIT=ON; Performing State Transfer on a server that starts from a clean var directory This is accomplished by shutting down node #2 and removing its var directory before restarting it +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -95,6 +106,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -104,6 +116,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Shutting down server ... +connection node_1; Cleaning var directory ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -119,6 +132,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_clean_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -126,6 +140,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Starting server ... SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -135,6 +150,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -149,6 +165,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_clean_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -163,6 +180,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -173,6 +191,7 @@ DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; Performing State Transfer on a server that has been killed and restarted +connection node_1; CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -182,6 +201,7 @@ INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); INSERT INTO t1 VALUES ('node1_committed_before'); COMMIT; +connection node_2; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node2_committed_before'); @@ -191,6 +211,7 @@ INSERT INTO t1 VALUES ('node2_committed_before'); INSERT INTO t1 VALUES ('node2_committed_before'); COMMIT; Killing server ... +connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_committed_during'); @@ -205,6 +226,7 @@ INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); +connect node_1a_galera_st_kill_slave, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -212,6 +234,7 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); +connection node_2; Performing --wsrep-recover ... Starting server ... Using --wsrep-start-position when starting mysqld ... @@ -223,6 +246,7 @@ INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); INSERT INTO t1 VALUES ('node2_committed_after'); COMMIT; +connection node_1; INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); INSERT INTO t1 VALUES ('node1_to_be_committed_after'); @@ -237,6 +261,7 @@ INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); INSERT INTO t1 VALUES ('node1_committed_after'); COMMIT; +connection node_1a_galera_st_kill_slave; INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after'); @@ -251,6 +276,7 @@ COUNT(*) = 0 1 COMMIT; SET AUTOCOMMIT=ON; +connection node_1; SELECT COUNT(*) = 35 FROM t1; COUNT(*) = 35 1 @@ -260,100 +286,5 @@ COUNT(*) = 0 DROP TABLE t1; COMMIT; SET AUTOCOMMIT=ON; -Performing State Transfer on a server that has been killed and restarted -while a DDL was in progress on it -CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -INSERT INTO t1 VALUES ('node1_committed_before'); -START TRANSACTION; -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -INSERT INTO t1 VALUES ('node2_committed_before'); -COMMIT; -SET GLOBAL debug_dbug = 'd,sync.alter_opened_table'; -ALTER TABLE t1 ADD COLUMN f2 INTEGER; -SET wsrep_sync_wait = 0; -Killing server ... -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -INSERT INTO t1 (f1) VALUES ('node1_committed_during'); -COMMIT; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -Performing --wsrep-recover ... -Starting server ... -Using --wsrep-start-position when starting mysqld ... -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -INSERT INTO t1 (f1) VALUES ('node2_committed_after'); -COMMIT; -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_committed_after'); -COMMIT; -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -INSERT INTO t1 (f1) VALUES ('node1_committed_after'); -COMMIT; -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -INSERT INTO t1 (f1) VALUES ('node1_to_be_rollbacked_after'); -ROLLBACK; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -COMMIT; -SET AUTOCOMMIT=ON; -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1'; -COUNT(*) = 2 -1 -SELECT COUNT(*) = 35 FROM t1; -COUNT(*) = 35 -1 -SELECT COUNT(*) = 0 FROM (SELECT COUNT(*) AS c, f1 FROM t1 GROUP BY f1 HAVING c NOT IN (5, 10)) AS a1; -COUNT(*) = 0 -1 -DROP TABLE t1; -COMMIT; -SET AUTOCOMMIT=ON; -SET GLOBAL debug_dbug = $debug_orig; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result index 81265f44397..378d8ca84f5 100644 --- a/mysql-test/suite/galera/r/galera_var_cluster_address.result +++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result @@ -4,7 +4,8 @@ connection node_2; SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; -ERROR 08S01: WSREP has not yet prepared node for application use +COUNT(*) > 0 +1 SHOW STATUS LIKE 'wsrep_ready'; Variable_name Value wsrep_ready OFF diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index beb47be1747..020efb7b8f1 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -36,11 +36,12 @@ SELECT 1; 1 1 USE information_schema; -ERROR 08S01: WSREP has not yet prepared node for application use SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads"; -ERROR 08S01: WSREP has not yet prepared node for application use +VARIABLE_NAME VARIABLE_VALUE +WSREP_DIRTY_READS OFF SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history; -ERROR 08S01: WSREP has not yet prepared node for application use +COUNT(*) >= 10 +1 connection node_1; USE test; SELECT * FROM t1; diff --git a/mysql-test/suite/galera/r/galera_var_reject_queries.result b/mysql-test/suite/galera/r/galera_var_reject_queries.result new file mode 100644 index 00000000000..98380238fcb --- /dev/null +++ b/mysql-test/suite/galera/r/galera_var_reject_queries.result @@ -0,0 +1,27 @@ +CREATE TABLE t1 (f1 INTEGER); +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1; +SET SESSION wsrep_reject_queries = ALL; +ERROR HY000: Variable 'wsrep_reject_queries' is a GLOBAL variable and should be set with SET GLOBAL +SET GLOBAL wsrep_reject_queries = ALL; +SELECT * FROM t1; +ERROR 08S01: WSREP has not yet prepared node for application use +SET GLOBAL wsrep_reject_queries = ALL_KILL; +ERROR HY000: Lost connection to MySQL server during query +connection node_1a; +SELECT * FROM t1; +Got one of the listed errors +connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SELECT * FROM t1; +ERROR 08S01: WSREP has not yet prepared node for application use +connection node_2; +SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +VARIABLE_VALUE = 2 +1 +INSERT INTO t1 VALUES (1); +connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET GLOBAL wsrep_reject_queries = NONE; +SELECT COUNT(*) = 1 FROM t1; +COUNT(*) = 1 +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_var_slave_threads.result b/mysql-test/suite/galera/r/galera_var_slave_threads.result index 102f7cb6386..79fe64f2783 100644 --- a/mysql-test/suite/galera/r/galera_var_slave_threads.result +++ b/mysql-test/suite/galera/r/galera_var_slave_threads.result @@ -1,8 +1,8 @@ -CALL mtr.add_suppression("WSREP: Refusing exit for the last slave thread."); connection node_1; CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB; CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB; connection node_2; +CALL mtr.add_suppression("WSREP: Refusing exit for the last slave thread."); SET GLOBAL wsrep_slave_threads = 0; Warnings: Warning 1292 Truncated incorrect wsrep_slave_threads value: '0' @@ -13,10 +13,6 @@ SELECT @@wsrep_slave_threads = 1; @@wsrep_slave_threads = 1 1 SET GLOBAL wsrep_slave_threads = 1; -SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; -COUNT(*) -2 SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; COUNT(*) 1 @@ -24,16 +20,6 @@ SET GLOBAL wsrep_slave_threads = 64; connection node_1; INSERT INTO t1 VALUES (1); connection node_2; -SELECT COUNT(*) FROM t1; -COUNT(*) -1 -SELECT COUNT(*) - @@wsrep_slave_threads FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; -COUNT(*) - @@wsrep_slave_threads -1 -SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; -COUNT(*) -1 SET GLOBAL wsrep_slave_threads = 1; connection node_1; INSERT INTO t2 VALUES (DEFAULT); @@ -104,10 +90,6 @@ connection node_2; SELECT COUNT(*) FROM t2; COUNT(*) 64 -SELECT COUNT(*) - @@wsrep_slave_threads FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; -COUNT(*) - @@wsrep_slave_threads -1 SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; COUNT(*) 1 @@ -122,5 +104,13 @@ CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB; connection node_2; SET GLOBAL wsrep_slave_threads = 4; SET GLOBAL wsrep_slave_threads = 1; +connection node_1; +INSERT INTO t1 VALUES (DEFAULT); +INSERT INTO t1 VALUES (DEFAULT); +INSERT INTO t1 VALUES (DEFAULT); DROP TABLE t1; +connection node_2; +SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; +COUNT(*) = 1 +1 # End of tests diff --git a/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require b/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require new file mode 100644 index 00000000000..c55610fd049 --- /dev/null +++ b/mysql-test/suite/galera/r/have_wsrep_replicate_myisam.require @@ -0,0 +1,2 @@ +Variable_name Value +wsrep_replicate_myisam ON diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm index bad0484be16..4e6927b3213 100644 --- a/mysql-test/suite/galera/suite.pm +++ b/mysql-test/suite/galera/suite.pm @@ -1,4 +1,4 @@ -package My::Suite::GALERA; +package My::Suite::Galera; use File::Basename; use My::Find; @@ -27,6 +27,10 @@ return "No scritps" unless $cpath; my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir; return "No my_print_defaults" unless $epath; +my ($bpath) = grep { -f "$_/mariabackup"; } "$::bindir/extra/mariabackup", $::path_client_bindir; + +sub which($) { return `sh -c "command -v $_[0]"` } + push @::global_suppressions, ( qr(WSREP: wsrep_sst_receive_address is set to '127.0.0.1), @@ -79,10 +83,30 @@ push @::global_suppressions, qr|WSREP: JOIN message from member .* in non-primary configuration. Ignored.|, ); - $ENV{PATH}="$epath:$ENV{PATH}"; $ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath; $ENV{PATH}="$cpath:$ENV{PATH}" unless $cpath eq $spath; +$ENV{PATH}="$bpath:$ENV{PATH}" unless $bpath eq $spath; -bless { }; +if (which(socat)) { + $ENV{MTR_GALERA_TFMT}='socat'; +} elsif (which(nc)) { + $ENV{MTR_GALERA_TFMT}='nc'; +} + +sub skip_combinations { + my %skip = (); + $skip{'include/have_xtrabackup.inc'} = 'Need innobackupex' + unless which(innobackupex); + $skip{'include/have_xtrabackup.inc'} = 'Need socat or nc' + unless $ENV{MTR_GALERA_TFMT}; + $skip{'include/have_mariabackup.inc'} = 'Need mariabackup' + unless which(mariabackup); + $skip{'include/have_mariabackup.inc'} = 'Need ss' + unless which(ss); + $skip{'include/have_mariabackup.inc'} = 'Need socat or nc' + unless $ENV{MTR_GALERA_TFMT}; + %skip; +} +bless { }; diff --git a/mysql-test/suite/galera/t/MW-286.test b/mysql-test/suite/galera/t/MW-286.test index 08deb317fbe..1b2e322f078 100644 --- a/mysql-test/suite/galera/t/MW-286.test +++ b/mysql-test/suite/galera/t/MW-286.test @@ -25,7 +25,6 @@ SET wsrep_on = FALSE; --error ER_QUERY_INTERRUPTED ALTER TABLE t1 ADD PRIMARY KEY (f1); -SET SESSION wsrep_sync_wait = 0; SET wsrep_on = TRUE; SET GLOBAL wsrep_desync = FALSE; diff --git a/mysql-test/suite/galera/t/MW-329.test b/mysql-test/suite/galera/t/MW-329.test index b3b4e8e921f..5baa4d14966 100644 --- a/mysql-test/suite/galera/t/MW-329.test +++ b/mysql-test/suite/galera/t/MW-329.test @@ -85,3 +85,5 @@ DROP TABLE t1; # Due to MW-330, Multiple "conflict state 3 after post commit" warnings if table is dropped while SP is running CALL mtr.add_suppression("conflict state 3 after post commit"); + +set global innodb_status_output=Default;
\ No newline at end of file diff --git a/mysql-test/suite/galera/t/MW-336.test b/mysql-test/suite/galera/t/MW-336.test index 79d8951a822..8cd363aa019 100644 --- a/mysql-test/suite/galera/t/MW-336.test +++ b/mysql-test/suite/galera/t/MW-336.test @@ -10,20 +10,20 @@ CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB; --connection node_1 SET GLOBAL wsrep_slave_threads = 10; SET GLOBAL wsrep_slave_threads = 1; +--let $wait_condition = SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc --connection node_2 INSERT INTO t1 VALUES (1); --connection node_1 ---sleep 0.5 SET GLOBAL wsrep_slave_threads = 10; ---sleep 0.5 -SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; +--let $wait_condition = SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc SET GLOBAL wsrep_slave_threads = 20; ---sleep 0.5 -SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; - +--let $wait_condition = SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc SET GLOBAL wsrep_slave_threads = 1; @@ -40,6 +40,9 @@ INSERT INTO t1 VALUES (9); --connection node_1 +--let $wait_condition = SELECT COUNT(*) = 12 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc + SET GLOBAL wsrep_slave_threads = 10; SET GLOBAL wsrep_slave_threads = 0; @@ -57,8 +60,8 @@ INSERT INTO t1 VALUES (19); INSERT INTO t1 VALUES (20); --connection node_1 ---sleep 0.5 -SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user'; +--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc SET GLOBAL wsrep_slave_threads = 1; DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test index 30ce9bc4ceb..cd7621bfa6e 100644 --- a/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test +++ b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test @@ -6,6 +6,7 @@ --source include/big_test.inc --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_xtrabackup.inc --connection node_1 --let $connection_id = `SELECT CONNECTION_ID()` diff --git a/mysql-test/suite/galera/t/galera_bf_abort_for_update.test b/mysql-test/suite/galera/t/galera_bf_abort_for_update.test index 24c29778e5d..13e48f8f3ce 100644 --- a/mysql-test/suite/galera/t/galera_bf_abort_for_update.test +++ b/mysql-test/suite/galera/t/galera_bf_abort_for_update.test @@ -5,25 +5,52 @@ # Test a local transaction being aborted by a slave one while it is running a SELECT FOR UPDATE # -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INT) ENGINE=InnoDB; ---connection node_2 ---let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` -SET AUTOCOMMIT=OFF; -START TRANSACTION; -INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (1, 10); + +# Test updating the PK --connection node_1 -INSERT INTO t1 VALUES (1); +--let $wsrep_local_bf_aborts_before = `SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'wsrep_local_bf_aborts'` +BEGIN; +SELECT * FROM t1 FOR UPDATE; --connection node_2 +UPDATE t1 SET f1 = 2; + +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--let $wait_condition = SELECT COUNT(*) FROM t1 WHERE f1 = 2 +--source include/wait_condition.inc + +--connection node_1 --error ER_LOCK_DEADLOCK +COMMIT; + +--disable_query_log +--eval SELECT variable_value - $wsrep_local_bf_aborts_before AS wsrep_local_bf_aborts_diff FROM information_schema.global_status WHERE variable_name = 'wsrep_local_bf_aborts' +--enable_query_log + +# Test updating non-indexed column + +--connection node_1 +--let $wsrep_local_bf_aborts_before = `SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'wsrep_local_bf_aborts'` +BEGIN; SELECT * FROM t1 FOR UPDATE; ---let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` +--connection node_2 +UPDATE t1 SET f2 = 20; + +--connection node_1a +--let $wait_condition = SELECT COUNT(*) FROM t1 WHERE f2 = 20 +--source include/wait_condition.inc + +--connection node_1 +--error ER_LOCK_DEADLOCK +COMMIT; --disable_query_log ---eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--eval SELECT variable_value - $wsrep_local_bf_aborts_before AS wsrep_local_bf_aborts_diff FROM information_schema.global_status WHERE variable_name = 'wsrep_local_bf_aborts' --enable_query_log DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_concurrent_ctas.test b/mysql-test/suite/galera/t/galera_concurrent_ctas.test index f0dcf8e4900..6c4e8be68a7 100644 --- a/mysql-test/suite/galera/t/galera_concurrent_ctas.test +++ b/mysql-test/suite/galera/t/galera_concurrent_ctas.test @@ -43,9 +43,9 @@ let $run=10; while($run) { --error 0,1 - exec $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_1 test - < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql & - $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_2 test + exec $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_1 test \ + < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql & \ + $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_2 test \ < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql; dec $run; } diff --git a/mysql-test/suite/galera/t/galera_flush_local.opt b/mysql-test/suite/galera/t/galera_flush_local.opt index 5a1fb6748d9..a084db15c5d 100644 --- a/mysql-test/suite/galera/t/galera_flush_local.opt +++ b/mysql-test/suite/galera/t/galera_flush_local.opt @@ -1 +1,3 @@ ---query_cache_type=1 --query_cache_size=1000000 +--query_cache_type=1 +--query_cache_size=1000000 +--wsrep_replicate_myisam=ON diff --git a/mysql-test/suite/galera/t/galera_flush_local.test b/mysql-test/suite/galera/t/galera_flush_local.test index 768f4ea4f1b..24acd9ec4ff 100644 --- a/mysql-test/suite/galera/t/galera_flush_local.test +++ b/mysql-test/suite/galera/t/galera_flush_local.test @@ -5,6 +5,7 @@ --source include/galera_cluster.inc --source include/have_innodb.inc --source include/have_query_cache.inc +--source include/have_wsrep_replicate_myisam.inc --disable_warnings DROP TABLE IF EXISTS t1, t2, x1, x2; diff --git a/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test index 8b399e77794..c44b0642342 100644 --- a/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test +++ b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test @@ -1,6 +1,7 @@ --source include/big_test.inc --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_xtrabackup.inc --source suite/galera/include/galera_st_disconnect_slave.inc --source suite/galera/include/galera_st_shutdown_slave.inc diff --git a/mysql-test/suite/galera/t/galera_schema_dirty_reads.test b/mysql-test/suite/galera/t/galera_schema_dirty_reads.test new file mode 100644 index 00000000000..93e24244611 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_schema_dirty_reads.test @@ -0,0 +1,13 @@ +# +# Dirty reads from INFORMATION_SCHEMA tables. +# +--source include/galera_cluster.inc +--source include/have_innodb.inc +--disable_info +USE information_schema; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; +SET GLOBAL wsrep_reject_queries=ALL; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; +SET GLOBAL wsrep_reject_queries=NONE; +SET SESSION wsrep_dirty_reads=TRUE; +SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads"; diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf new file mode 100644 index 00000000000..336296e9bfe --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup.cnf @@ -0,0 +1,16 @@ +!include ../galera_2nodes.cnf + +[mysqld] +wsrep_sst_method=mariabackup +wsrep_sst_auth="root:" +wsrep_debug=ON + +[mysqld.1] +wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true' + +[mysqld.2] +wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' + +[sst] +transferfmt=@ENV.MTR_GALERA_TFMT +streamfmt=xbstream diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup.test b/mysql-test/suite/galera/t/galera_sst_mariabackup.test new file mode 100644 index 00000000000..0e7ac487700 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup.test @@ -0,0 +1,19 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_mariabackup.inc + +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +--source suite/galera/include/galera_st_shutdown_slave.inc +--source suite/galera/include/galera_st_clean_slave.inc + +--source suite/galera/include/galera_st_kill_slave.inc +--source suite/galera/include/galera_st_kill_slave_ddl.inc + +# Restore original auto_increment_offset values. +--source include/auto_increment_offset_restore.inc + +--source include/galera_end.inc diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump.test b/mysql-test/suite/galera/t/galera_sst_mysqldump.test index 0b7171597dd..390e9815b20 100644 --- a/mysql-test/suite/galera/t/galera_sst_mysqldump.test +++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.test @@ -1,9 +1,11 @@ ---source include/big_test.inc --source include/galera_cluster.inc ---source include/have_innodb.inc --source suite/galera/include/galera_sst_set_mysqldump.inc +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + --source suite/galera/include/galera_st_disconnect_slave.inc # We set the required mysqldump SST options here so that they are used every time the server is restarted during the test @@ -15,4 +17,5 @@ --source suite/galera/include/galera_st_kill_slave.inc --source suite/galera/include/galera_st_kill_slave_ddl.inc +--source include/auto_increment_offset_restore.inc --source suite/galera/include/galera_sst_restore.inc diff --git a/mysql-test/suite/galera/t/galera_sst_rsync.test b/mysql-test/suite/galera/t/galera_sst_rsync.test index c6823795e59..f796356cac7 100644 --- a/mysql-test/suite/galera/t/galera_sst_rsync.test +++ b/mysql-test/suite/galera/t/galera_sst_rsync.test @@ -1,9 +1,12 @@ ---source include/big_test.inc --source include/galera_cluster.inc ---source include/have_innodb.inc + +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc --source suite/galera/include/galera_st_shutdown_slave.inc --source suite/galera/include/galera_st_clean_slave.inc --source suite/galera/include/galera_st_kill_slave.inc --source suite/galera/include/galera_st_kill_slave_ddl.inc +--source include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf index 31bd1af07c2..1e29673c0ff 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf @@ -22,3 +22,4 @@ parallel=2 encrypt=1 encrypt-algo=AES256 encrypt-key=4FA92C5873672E20FB163A0BCB2BB4A4 +transferfmt=@ENV.MTR_GALERA_TFMT diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test index 4573f176482..db2b706b6b8 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test @@ -3,9 +3,9 @@ # Initial SST happens via xtrabackup, so there is not much to do in the body of the test # ---source include/big_test.inc --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_xtrabackup.inc SELECT 1; diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf index 47cb3e02292..0025b259ec5 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf @@ -11,3 +11,5 @@ wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore [mysqld.2] wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true' +[sst] +transferfmt=@ENV.MTR_GALERA_TFMT diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test index aac6822170a..f1fd0f3ddf3 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test @@ -1,6 +1,6 @@ ---source include/big_test.inc --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_xtrabackup.inc # Save original auto_increment_offset values. --let $node_1=node_1 diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf index 969516f5f3b..63d05104a37 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf @@ -9,3 +9,4 @@ wsrep_debug=ON tkey=@ENV.MYSQL_TEST_DIR/std_data/galera-key.pem tcert=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem encrypt=3 +transferfmt=@ENV.MTR_GALERA_TFMT diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test index 24d9589d111..2f685ca7184 100644 --- a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test +++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test @@ -6,6 +6,7 @@ --source include/big_test.inc --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_xtrabackup.inc SELECT 1; diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test index 03706bbbb12..6d99d35cdac 100644 --- a/mysql-test/suite/galera/t/galera_var_cluster_address.test +++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test @@ -24,7 +24,6 @@ SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; ---error ER_UNKNOWN_COM_ERROR SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; # Must return 'OFF' diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index cba8488b879..138b7c1c703 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -49,13 +49,10 @@ SELECT i, variable_name, variable_value FROM t1, information_schema.session_vari SELECT 1; ---error ER_UNKNOWN_COM_ERROR USE information_schema; ---error ER_UNKNOWN_COM_ERROR SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads"; ---error ER_UNKNOWN_COM_ERROR SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history; --disable_query_log diff --git a/mysql-test/suite/galera/t/galera_var_reject_queries.test b/mysql-test/suite/galera/t/galera_var_reject_queries.test new file mode 100644 index 00000000000..6859855c35f --- /dev/null +++ b/mysql-test/suite/galera/t/galera_var_reject_queries.test @@ -0,0 +1,44 @@ +# +# Test wsrep_reject_queries +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +CREATE TABLE t1 (f1 INTEGER); + +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 + +--connection node_1 +--error ER_GLOBAL_VARIABLE +SET SESSION wsrep_reject_queries = ALL; + +SET GLOBAL wsrep_reject_queries = ALL; + +--error ER_UNKNOWN_COM_ERROR +SELECT * FROM t1; + +# Lost connection +--error 2013 +SET GLOBAL wsrep_reject_queries = ALL_KILL; + +--connection node_1a +--error ER_CONNECTION_KILLED,2013,2006 +SELECT * FROM t1; + +--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--error ER_UNKNOWN_COM_ERROR +SELECT * FROM t1; + +# Confirm that replication continues + +--connection node_2 +SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +INSERT INTO t1 VALUES (1); + +--connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET GLOBAL wsrep_reject_queries = NONE; + +SELECT COUNT(*) = 1 FROM t1; + +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.test b/mysql-test/suite/galera/t/galera_var_slave_threads.test index 1c4dd8eba3a..3896b1d48cf 100644 --- a/mysql-test/suite/galera/t/galera_var_slave_threads.test +++ b/mysql-test/suite/galera/t/galera_var_slave_threads.test @@ -6,7 +6,6 @@ --source include/galera_cluster.inc --source include/have_innodb.inc -CALL mtr.add_suppression("WSREP: Refusing exit for the last slave thread."); --let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads` --connection node_1 @@ -14,7 +13,7 @@ CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB; CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB; --connection node_2 - +CALL mtr.add_suppression("WSREP: Refusing exit for the last slave thread."); # Setting wsrep_slave_threads to zero triggers a warning SET GLOBAL wsrep_slave_threads = 0; SHOW WARNINGS; @@ -22,8 +21,6 @@ SELECT @@wsrep_slave_threads = 1; SET GLOBAL wsrep_slave_threads = 1; # There is a separate wsrep_aborter thread at all times -SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; # @@ -31,17 +28,13 @@ SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' A # SET GLOBAL wsrep_slave_threads = 64; ---sleep 0.5 --connection node_1 INSERT INTO t1 VALUES (1); --connection node_2 -SELECT COUNT(*) FROM t1; - -SELECT COUNT(*) - @@wsrep_slave_threads FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; -SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; +--let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%'); +--source include/wait_condition.inc # # Reduce the number of slave threads. The change is not immediate -- a thread will only exit after a replication event @@ -62,8 +55,8 @@ while ($count) --connection node_2 SELECT COUNT(*) FROM t2; -SELECT COUNT(*) - @@wsrep_slave_threads FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE USER = 'system user' AND STATE NOT LIKE 'InnoDB%'; +--let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%') +--source include/wait_condition.inc SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; @@ -81,7 +74,23 @@ CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB; --connection node_2 SET GLOBAL wsrep_slave_threads = 4; +--let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%') +--source include/wait_condition.inc + SET GLOBAL wsrep_slave_threads = 1; + +--connection node_1 +INSERT INTO t1 VALUES (DEFAULT); +INSERT INTO t1 VALUES (DEFAULT); +INSERT INTO t1 VALUES (DEFAULT); DROP TABLE t1; +--connection node_2 +# +# make sure that we are left with exactly one applier thread before we leaving the test +# +--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%') +--source include/wait_condition.inc +SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%'; + --echo # End of tests diff --git a/mysql-test/suite/innodb/r/default_row_format_compatibility.result b/mysql-test/suite/innodb/r/default_row_format_compatibility.result index dedafc72808..765e25c776e 100644 --- a/mysql-test/suite/innodb/r/default_row_format_compatibility.result +++ b/mysql-test/suite/innodb/r/default_row_format_compatibility.result @@ -36,6 +36,9 @@ SHOW TABLE STATUS LIKE 'tab'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary tab InnoDB # Compact # # # # # # NULL # NULL NULL latin1_swedish_ci NULL 0 N ALTER TABLE tab DISCARD TABLESPACE; +call mtr.add_suppression("InnoDB: Tried to read .* bytes at offset 0"); +ALTER TABLE tab IMPORT TABLESPACE; +ERROR HY000: Internal error: Cannot reset LSNs in table `test`.`tab` : I/O error ALTER TABLE tab IMPORT TABLESPACE; SELECT * FROM tab; a diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index 54ad4e8a927..df27769b810 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/r/innodb-index.result @@ -1848,3 +1848,20 @@ create table t1(o1 int, o2 int, o3 int, primary key(o1,o2,o3)) engine = innodb; insert into t1 values(1,1,2),(2,2,1); alter table t1 drop primary key, add primary key(o1), lock=none; drop table t1; +# +# MDEV-15325 Incomplete validation of missing tablespace during recovery +# +CREATE TABLE t1(f1 INT PRIMARY KEY)ENGINE=InnoDB; +CREATE TABLE t2(f1 INT PRIMARY KEY)ENGINE=InnoDB; +# Kill the server +# Wrong space_id in a dirty file and a missing file +SELECT * FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS +# Restore t1 and t2 +SELECT * FROM t1; +f1 +SELECT * FROM t2; +f1 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/r/purge_secondary.result b/mysql-test/suite/innodb/r/purge_secondary.result index 2312434a2bd..8f20f5baacb 100644 --- a/mysql-test/suite/innodb/r/purge_secondary.result +++ b/mysql-test/suite/innodb/r/purge_secondary.result @@ -99,7 +99,7 @@ l LINESTRING NOT NULL DEFAULT ST_linefromtext('linestring(448 -689, 9716 9648,9720 9650,9721 9648,9723 9648,9726 4648,12726 4653,12731 4655, 12734 4660,12730 4661,12733 4664,12733 4665,12735 4670,12737 4674,12741 4674, 12738 4675,12740 4675,12737 4675,12742 4678,12743 4681,12746 4677)'), -INDEX(b,c), SPATIAL INDEX(l) +INDEX(b,c), SPATIAL INDEX `sidx`(l) ) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); SELECT LENGTH(l) FROM t1; @@ -139,6 +139,27 @@ SELECT OTHER_INDEX_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS WHERE NAME='test/t1'; OTHER_INDEX_SIZE 1 +ALTER TABLE t1 DROP INDEX `sidx`; +INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="buffer_LRU_batch_flush_total_pages" AND COUNT > 0; +NAME SUBSYSTEM +buffer_LRU_batch_flush_total_pages buffer +SELECT (variable_value > 0) FROM information_schema.global_status +WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; +(variable_value > 0) +1 +SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="buffer_LRU_batch_evict_total_pages" AND COUNT > 0; +NAME SUBSYSTEM +buffer_LRU_batch_evict_total_pages buffer # Note: The OTHER_INDEX_SIZE does not cover any SPATIAL INDEX. # To test that all indexes were emptied, replace DROP TABLE # with the following, and examine the root pages in t1.ibd: diff --git a/mysql-test/suite/innodb/t/default_row_format_compatibility.test b/mysql-test/suite/innodb/t/default_row_format_compatibility.test index db93f3c4520..98f44956f79 100644 --- a/mysql-test/suite/innodb/t/default_row_format_compatibility.test +++ b/mysql-test/suite/innodb/t/default_row_format_compatibility.test @@ -78,7 +78,14 @@ SHOW TABLE STATUS LIKE 'tab'; ALTER TABLE tab DISCARD TABLESPACE; # Move the *ibd,*.cfg file into orginal location +--copy_file $MYSQLD_DATADIR/tab.cfg $MYSQLD_DATADIR/test/tab.ibd --move_file $MYSQLD_DATADIR/tab.cfg $MYSQLD_DATADIR/test/tab.cfg + +call mtr.add_suppression("InnoDB: Tried to read .* bytes at offset 0"); + +--error ER_INTERNAL_ERROR +ALTER TABLE tab IMPORT TABLESPACE; +--remove_file $MYSQLD_DATADIR/test/tab.ibd --move_file $MYSQLD_DATADIR/tab.ibd $MYSQLD_DATADIR/test/tab.ibd # Check import is successful (because same row_format) diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test index 721808c038c..8b9d2068499 100644 --- a/mysql-test/suite/innodb/t/innodb-index.test +++ b/mysql-test/suite/innodb/t/innodb-index.test @@ -1076,3 +1076,51 @@ drop table t1; # no skip sort cases --source suite/innodb/include/alter_table_pk_no_sort.inc + +--echo # +--echo # MDEV-15325 Incomplete validation of missing tablespace during recovery +--echo # + +--source include/no_checkpoint_start.inc +CREATE TABLE t1(f1 INT PRIMARY KEY)ENGINE=InnoDB; + +CREATE TABLE t2(f1 INT PRIMARY KEY)ENGINE=InnoDB; + +--let CLEANUP_IF_CHECKPOINT=DROP TABLE t1, t2; +--source include/no_checkpoint_end.inc + +let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let $check_no_innodb=SELECT * FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); + +--echo # Wrong space_id in a dirty file and a missing file + +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t0.ibd +--move_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_DATADIR/test/t1.ibd + +--source include/start_mysqld.inc +--eval $check_no_innodb +--source include/shutdown_mysqld.inc + +--echo # Restore t1 and t2 + +--move_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd +--move_file $MYSQLD_DATADIR/test/t0.ibd $MYSQLD_DATADIR/test/t1.ibd + +--source include/start_mysqld.inc + +SELECT * FROM t1; +SELECT * FROM t2; + +DROP TABLE t1, t2; + +--disable_query_log + +call mtr.add_suppression("InnoDB: Tablespace .* was not found at .*t[12].ibd."); +call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore this and to permanently lose all changes to the tablespace"); +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error"); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); + +--enable_query_log diff --git a/mysql-test/suite/innodb/t/purge_secondary.opt b/mysql-test/suite/innodb/t/purge_secondary.opt index 99bf0e5a28b..e98e639d5f4 100644 --- a/mysql-test/suite/innodb/t/purge_secondary.opt +++ b/mysql-test/suite/innodb/t/purge_secondary.opt @@ -1 +1,3 @@ --innodb-sys-tablestats +--innodb_buffer_pool_size=5M +--innodb_monitor_enable=module_buffer diff --git a/mysql-test/suite/innodb/t/purge_secondary.test b/mysql-test/suite/innodb/t/purge_secondary.test index 47cfaec41ca..bf702b6b737 100644 --- a/mysql-test/suite/innodb/t/purge_secondary.test +++ b/mysql-test/suite/innodb/t/purge_secondary.test @@ -103,7 +103,7 @@ CREATE TABLE t1 ( 9716 9648,9720 9650,9721 9648,9723 9648,9726 4648,12726 4653,12731 4655, 12734 4660,12730 4661,12733 4664,12733 4665,12735 4670,12737 4674,12741 4674, 12738 4675,12740 4675,12737 4675,12742 4678,12743 4681,12746 4677)'), - INDEX(b,c), SPATIAL INDEX(l) + INDEX(b,c), SPATIAL INDEX `sidx`(l) ) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); SELECT LENGTH(l) FROM t1; @@ -120,6 +120,27 @@ ANALYZE TABLE t1; SELECT OTHER_INDEX_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS WHERE NAME='test/t1'; +# Work around MDEV-13942, Dropping the spatial index to avoid the possible hang +ALTER TABLE t1 DROP INDEX `sidx`; + +INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT NULL FROM t1; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; + +SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="buffer_LRU_batch_flush_total_pages" AND COUNT > 0; + +SELECT (variable_value > 0) FROM information_schema.global_status +WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; + +SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="buffer_LRU_batch_evict_total_pages" AND COUNT > 0; + --echo # Note: The OTHER_INDEX_SIZE does not cover any SPATIAL INDEX. --echo # To test that all indexes were emptied, replace DROP TABLE --echo # with the following, and examine the root pages in t1.ibd: diff --git a/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations b/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations new file mode 100644 index 00000000000..dbfe4e6c63a --- /dev/null +++ b/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations @@ -0,0 +1,2 @@ +[2] +innodb-undo-tablespaces=2 diff --git a/mysql-test/suite/mariabackup/undo_space_id.opt b/mysql-test/suite/mariabackup/undo_space_id.opt new file mode 100644 index 00000000000..16135129d5b --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_space_id.opt @@ -0,0 +1,2 @@ +--debug=d,innodb_undo_upgrade,force_rebootstrap +--innodb_undo_tablespaces=2 diff --git a/mysql-test/suite/mariabackup/undo_space_id.result b/mysql-test/suite/mariabackup/undo_space_id.result new file mode 100644 index 00000000000..96d3e2a58f4 --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_space_id.result @@ -0,0 +1,13 @@ +# Create 2 UNDO TABLESPACE(UNDO003, UNDO004) +CREATE TABLE t1(a varchar(60)) ENGINE INNODB; +start transaction; +INSERT INTO t1 VALUES(1); +# xtrabackup backup +# Display undo log files from target directory +undo003 +undo004 +# xtrabackup prepare +# Display undo log files from targer directory +undo003 +undo004 +DROP TABLE t1; diff --git a/mysql-test/suite/mariabackup/undo_space_id.test b/mysql-test/suite/mariabackup/undo_space_id.test new file mode 100644 index 00000000000..8adeb18e5a7 --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_space_id.test @@ -0,0 +1,25 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +--echo # Create 2 UNDO TABLESPACE(UNDO003, UNDO004) + +let $basedir=$MYSQLTEST_VARDIR/tmp/backup; + +CREATE TABLE t1(a varchar(60)) ENGINE INNODB; +start transaction; +INSERT INTO t1 VALUES(1); + +--echo # xtrabackup backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; +--enable_result_log +--echo # Display undo log files from target directory +list_files $basedir undo*; + +--echo # xtrabackup prepare +exec $XTRABACKUP --prepare --apply-log-only --target-dir=$basedir; +--echo # Display undo log files from targer directory +list_files $basedir undo*; + +DROP TABLE t1; +rmdir $basedir; diff --git a/mysql-test/suite/mariabackup/unsupported_redo.result b/mysql-test/suite/mariabackup/unsupported_redo.result new file mode 100644 index 00000000000..29f043fc643 --- /dev/null +++ b/mysql-test/suite/mariabackup/unsupported_redo.result @@ -0,0 +1,36 @@ +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation"); +call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); +call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t21` because it could not be opened"); +call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: "); +call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist"); +CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +# Fails during full backup +DROP TABLE t1; +CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; +INSERT INTO t1(a) select 1 union select 2 union select 3; +# Create full backup , modify table, then fails during creation of +# incremental/differential backup +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +DROP TABLE t1; +CREATE TABLE t1(i INT) ENGINE INNODB; +INSERT INTO t1 VALUES(1); +CREATE TABLE t21(i INT) ENGINE INNODB; +INSERT INTO t21 VALUES(1); +CREATE TABLE t2(i int) ENGINE INNODB; +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +ALTER TABLE t21 FORCE, ALGORITHM=INPLACE; +# Create partial backup (excluding table t21), Ignore the +# unsupported redo log for the table t21. +t1.ibd +t2.ibd +# Prepare the full backup +t1.ibd +t2.ibd +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t21; diff --git a/mysql-test/suite/mariabackup/unsupported_redo.test b/mysql-test/suite/mariabackup/unsupported_redo.test new file mode 100644 index 00000000000..f54f97b6c8b --- /dev/null +++ b/mysql-test/suite/mariabackup/unsupported_redo.test @@ -0,0 +1,86 @@ +--source include/have_innodb.inc +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation"); +call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); +call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t21` because it could not be opened"); +call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: "); +call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist"); + +let $basedir=$MYSQLTEST_VARDIR/tmp/backup; +let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1; + +CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; + +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +--source include/restart_mysqld.inc + +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; + +# Below mariabackup operation may complete successfully if checkpoint happens +# after the alter table command. + +echo # Fails during full backup; +--disable_result_log +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; +--enable_result_log + +DROP TABLE t1; +rmdir $basedir; + +CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; + +INSERT INTO t1(a) select 1 union select 2 union select 3; + +--echo # Create full backup , modify table, then fails during creation of +--echo # incremental/differential backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; +--enable_result_log + +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +--source include/restart_mysqld.inc +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; + +--disable_result_log +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir; +--enable_result_log + +DROP TABLE t1; +rmdir $basedir; +rmdir $incremental_dir; + +CREATE TABLE t1(i INT) ENGINE INNODB; +INSERT INTO t1 VALUES(1); +CREATE TABLE t21(i INT) ENGINE INNODB; +INSERT INTO t21 VALUES(1); + +let $MYSQLD_DATADIR= `select @@datadir`; +let $targetdir=$MYSQLTEST_VARDIR/tmp/bk; + +CREATE TABLE t2(i int) ENGINE INNODB; + +SET GLOBAL INNODB_FAST_SHUTDOWN = 0; +--source include/restart_mysqld.inc +ALTER TABLE t21 FORCE, ALGORITHM=INPLACE; + +--echo # Create partial backup (excluding table t21), Ignore the +--echo # unsupported redo log for the table t21. + +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup "--tables-exclude=test.t21" --target-dir=$targetdir; +--enable_result_log +--list_files $targetdir/test *.ibd + +--echo # Prepare the full backup +--disable_result_log +exec $XTRABACKUP --prepare --target-dir=$targetdir; +--enable_result_log +--list_files $targetdir/test *.ibd + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t21; +rmdir $targetdir; diff --git a/mysql-test/suite/rpl/r/rpl_parallel_retry.result b/mysql-test/suite/rpl/r/rpl_parallel_retry.result index c4c56489aa4..66428c94086 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_retry.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_retry.result @@ -120,6 +120,7 @@ connection server_2; SET sql_log_bin=0; CALL mtr.add_suppression("Slave worker thread retried transaction 10 time\\(s\\) in vain, giving up"); CALL mtr.add_suppression("Slave: Deadlock found when trying to get lock; try restarting transaction"); +CALL mtr.add_suppression("Slave worker thread retried transaction .* in vain, giving up"); SET sql_log_bin=1; SET @old_dbug= @@GLOBAL.debug_dbug; SET GLOBAL debug_dbug="+d,rpl_parallel_simulate_temp_err_gtid_0_x_100,rpl_parallel_simulate_infinite_temp_err_gtid_0_x_100"; @@ -340,4 +341,60 @@ include/start_slave.inc connection server_1; DROP TABLE t1, t2, t3, t4; DROP function foo; +connection server_2; +connection server_1; +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; +connection server_2; +include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @@GLOBAL.slave_parallel_threads=5; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET @@GLOBAL.slave_parallel_mode='aggressive'; +SET @old_lock_wait_timeout=@@GLOBAL.innodb_lock_wait_timeout; +SET @@GLOBAL.innodb_lock_wait_timeout=2; +SET @old_slave_transaction_retries=@@GLOBAL.slave_transaction_retries; +SET @@GLOBAL.slave_transaction_retries=1; +# Spoilers on the slave side causing temporary errors +connect spoiler_21,127.0.0.1,root,,test,$SLAVE_MYPORT; +BEGIN; +INSERT INTO t1 SET a=1,b=2; +connect spoiler_22,127.0.0.1,root,,test,$SLAVE_MYPORT; +BEGIN; +INSERT INTO t1 SET a=2,b=2; +# Master payload +connection server_1; +SET @@SESSION.GTID_SEQ_NO=1000; +INSERT INTO t1 SET a=1,b=1; +SET @@SESSION.GTID_SEQ_NO=1001; +INSERT INTO t1 SET a=2,b=1; +# Start slave whose both appliers is destined to being blocked +connection server_2; +SET @old_dbug= @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="+d,rpl_parallel_simulate_wait_at_retry"; +include/start_slave.inc +# Make sure the 2nd seqno_1001 worker has gotten to waiting +# Signal to the 1st to proceed after it has reached termination state +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1000'; +connection spoiler_21; +ROLLBACK; +# Release the 2nd worker to proceed +connection spoiler_22; +ROLLBACK; +connection server_2; +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1001'; +# observe how it all ends +# Wait for the workers to go home and check the result of applying +# which is OK +connection server_2; +include/stop_slave.inc +SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads; +SET @@GLOBAL.slave_parallel_mode=@old_parallel_mode; +SET @@GLOBAL.innodb_lock_wait_timeout=@old_lock_wait_timeout; +SET @@GLOBAL.slave_transaction_retries=@old_slave_transaction_retries; +SET @@GLOBAL.debug_dbug=@old_dbug; +SET debug_sync='RESET'; +include/start_slave.inc +connection server_1; +DROP TABLE t1; +connection server_2; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_parallel_retry.test b/mysql-test/suite/rpl/t/rpl_parallel_retry.test index b3a8ea45cf0..96863f9021d 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_retry.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_retry.test @@ -128,6 +128,7 @@ SELECT * FROM t1 ORDER BY a; SET sql_log_bin=0; CALL mtr.add_suppression("Slave worker thread retried transaction 10 time\\(s\\) in vain, giving up"); CALL mtr.add_suppression("Slave: Deadlock found when trying to get lock; try restarting transaction"); +CALL mtr.add_suppression("Slave worker thread retried transaction .* in vain, giving up"); SET sql_log_bin=1; SET @old_dbug= @@GLOBAL.debug_dbug; @@ -371,7 +372,7 @@ SELECT * FROM t3 ORDER BY a; SET binlog_format=@old_format; -# Clean up. +# Clean up of the above part. --connection server_2 --source include/stop_slave.inc SET GLOBAL slave_parallel_threads=@old_parallel_threads; @@ -381,4 +382,102 @@ SET GLOBAL slave_parallel_threads=@old_parallel_threads; DROP TABLE t1, t2, t3, t4; DROP function foo; +--sync_slave_with_master server_2 + +# +# MDEV-12746 rpl.rpl_parallel_optimistic_nobinlog fails committing out of order at retry +# + +--connection server_1 +CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; + + +# Replicate create-t1 and prepare to re-start slave in optimistic mode +--sync_slave_with_master server_2 +--source include/stop_slave.inc +SET @old_parallel_threads=@@GLOBAL.slave_parallel_threads; +SET @@GLOBAL.slave_parallel_threads=5; +SET @old_parallel_mode=@@GLOBAL.slave_parallel_mode; +SET @@GLOBAL.slave_parallel_mode='aggressive'; +SET @old_lock_wait_timeout=@@GLOBAL.innodb_lock_wait_timeout; +SET @@GLOBAL.innodb_lock_wait_timeout=2; +SET @old_slave_transaction_retries=@@GLOBAL.slave_transaction_retries; +SET @@GLOBAL.slave_transaction_retries=1; + +--echo # Spoilers on the slave side causing temporary errors +--connect (spoiler_21,127.0.0.1,root,,test,$SLAVE_MYPORT) +BEGIN; + INSERT INTO t1 SET a=1,b=2; + +--connect (spoiler_22,127.0.0.1,root,,test,$SLAVE_MYPORT) +BEGIN; + INSERT INTO t1 SET a=2,b=2; + +--echo # Master payload +--connection server_1 +SET @@SESSION.GTID_SEQ_NO=1000; +INSERT INTO t1 SET a=1,b=1; +SET @@SESSION.GTID_SEQ_NO=1001; +INSERT INTO t1 SET a=2,b=1; + +--echo # Start slave whose both appliers is destined to being blocked +--connection server_2 +SET @old_dbug= @@GLOBAL.debug_dbug; +SET @@GLOBAL.debug_dbug="+d,rpl_parallel_simulate_wait_at_retry"; +--source include/start_slave.inc + +--echo # Make sure the 2nd seqno_1001 worker has gotten to waiting +--let $wait_condition= SELECT count(*) FROM information_schema.processlist WHERE state LIKE '%debug sync point: now%'; +--source include/wait_condition.inc + + +--echo # Signal to the 1st to proceed after it has reached termination state +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1000'; +--connection spoiler_21 +ROLLBACK; + +--echo # Release the 2nd worker to proceed +--connection spoiler_22 +ROLLBACK; +--connection server_2 +SET @@DEBUG_SYNC='now SIGNAL proceed_by_1001'; + +--echo # observe how it all ends +if (`SELECT count(*) = 1 FROM t1 WHERE a = 1`) +{ + --echo "*** Unexpected commit by the first Worker ***" + SELECT * from t1; + --die +} + +--echo # Wait for the workers to go home and check the result of applying +--let $wait_condition=SELECT count(*) = 0 FROM information_schema.processlist WHERE command = 'Slave_worker' +--source include/wait_condition.inc +if (`SELECT count(*) = 1 FROM t1 WHERE a = 2`) +{ + --echo + --echo "*** Error: congrats, you hit MDEV-12746 issue. ***" + --echo + --die +} +--echo # which is OK + +# +# Clean up +# +--connection server_2 +--source include/stop_slave.inc +SET @@GLOBAL.slave_parallel_threads=@old_parallel_threads; +SET @@GLOBAL.slave_parallel_mode=@old_parallel_mode; +SET @@GLOBAL.innodb_lock_wait_timeout=@old_lock_wait_timeout; +SET @@GLOBAL.slave_transaction_retries=@old_slave_transaction_retries; +SET @@GLOBAL.debug_dbug=@old_dbug; +SET debug_sync='RESET'; +--source include/start_slave.inc + +--connection server_1 +DROP TABLE t1; + +--sync_slave_with_master server_2 + --source include/rpl_end.inc diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index 0c206975c29..db932ae8223 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -421,6 +421,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST OFF,ON READ_ONLY YES COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME WSREP_REJECT_QUERIES +SESSION_VALUE NULL +GLOBAL_VALUE NONE +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE NONE +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE ENUM +VARIABLE_COMMENT Variable to set to reject queries +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST NONE,ALL,ALL_KILL +READ_ONLY NO +COMMAND_LINE_ARGUMENT OPTIONAL VARIABLE_NAME WSREP_REPLICATE_MYISAM SESSION_VALUE NULL GLOBAL_VALUE OFF diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result index 6db52eb8150..3e1fb6cad79 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result @@ -30,10 +30,6 @@ SELECT @@global.wsrep_sst_receive_address; 192.168.2.254 # invalid values -SET @@global.wsrep_sst_receive_address='127.0.0.1:4444'; -ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1:4444' -SET @@global.wsrep_sst_receive_address='127.0.0.1'; -ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1' SELECT @@global.wsrep_sst_receive_address; @@global.wsrep_sst_receive_address 192.168.2.254 diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test index 9e50cbf8947..59f69c14dfb 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test @@ -27,10 +27,6 @@ SELECT @@global.wsrep_sst_receive_address; --echo --echo # invalid values ---error ER_WRONG_VALUE_FOR_VAR -SET @@global.wsrep_sst_receive_address='127.0.0.1:4444'; ---error ER_WRONG_VALUE_FOR_VAR -SET @@global.wsrep_sst_receive_address='127.0.0.1'; SELECT @@global.wsrep_sst_receive_address; --error ER_WRONG_VALUE_FOR_VAR SET @@global.wsrep_sst_receive_address=NULL; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 018f5fa946b..d7dac112b3b 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -288,8 +288,27 @@ DROP TABLE t1; --echo # End of 10.1 test --echo # +# +# caching of first argument in CASE/IN for temporal types +# +# + +# should not convert all values to time +select case 'foo' when time'10:00:00' then 'never' when '0' then 'bug' else 'ok' end; +select 'foo' in (time'10:00:00','0'); + +create table t1 (a time); +insert t1 values (100000), (102030), (203040); +# only one warning, TIME('foo') should be cached +select case 'foo' when a then 'never' when '0' then 'bug' else 'ok' end from t1; +select 'foo' in (a,'0') from t1; +drop table t1; + +# first comparison should be as date, second as time +select case '20:10:05' when date'2020-10-10' then 'never' when time'20:10:5' then 'ok' else 'bug' end; + --echo # ---echo # Start of 10.3 tests +--echo # End of 10.2 test --echo # --echo # @@ -370,3 +389,7 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a'; DROP TABLE t1; + +--echo # +--echo # End of 10.3 test +--echo # diff --git a/mysql-test/t/check_constraint.test b/mysql-test/t/check_constraint.test index f72ce38087e..9a77736acd7 100644 --- a/mysql-test/t/check_constraint.test +++ b/mysql-test/t/check_constraint.test @@ -103,3 +103,11 @@ insert t1 values (2); insert t1 values (NULL); select * from t1; drop table t1; + +# +# MDEV-15141 Check constraint validation on a datetime field crashes the process +# +create table t1 (id int auto_increment primary key, datecol datetime, check (datecol>'0001-01-01 00:00:00')); +insert into t1 (datecol) values (now()); +insert into t1 (datecol) values (now()); +drop table t1; diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 3d073183877..5e1770496f6 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -989,3 +989,26 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1; DROP VIEW v1,v2; + +--echo # +--echo # MDEV-15478: Lost name of a explicitly named CTE column used in +--echo # the non-recursive CTE defined with UNION +--echo # + +CREATE TABLE t1 (x int, y int); +INSERT INTO t1 VALUES (1,2),(2,7),(3,3); + +WITH cte(a) AS (SELECT 1 UNION SELECT 2) SELECT * FROM cte; + +WITH cte(a) AS (SELECT 1 UNION SELECT 2) SELECT a FROM cte; + +WITH cte(a) AS (SELECT 1 UNION ALL SELECT 1) SELECT a FROM cte; + +WITH cte(a) AS (SELECT x from t1 UNION SELECT 4) SELECT a FROM cte; + +WITH cte(a) AS (SELECT 4 UNION SELECT x FROM t1 UNION SELECT 5) +SELECT a FROM cte; + +WITH cte(a,b) AS (SELECT 4,5 UNION SELECT 4,3) SELECT a,b FROM cte; + +DROP TABLE t1; diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test index 31d4ff7f802..38f147708b8 100644 --- a/mysql-test/t/ctype_latin1.test +++ b/mysql-test/t/ctype_latin1.test @@ -392,6 +392,15 @@ SELECT * FROM t1 WHERE COALESCE(c,0)='3 ' AND COALESCE(d,0)=COALESCE(c,0); DROP TABLE t1; --echo # +--echo # MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple +--echo # + +SET NAMES latin1; +SELECT CONVERT(1, CHAR) IN ('100', 10, '101'); +SELECT CONVERT(1, CHAR) IN ('100', 10, '1'); +SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); + +--echo # --echo # End of 10.1 tests --echo # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index b839042b91e..20a60d370a0 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -2034,6 +2034,16 @@ SELECT CAST(_utf8 0xC499 AS CHAR CHARACTER SET latin1); --echo # +--echo # MDEV-15005 ASAN: stack-buffer-overflow in my_strnncollsp_simple +--echo # + +SET NAMES utf8; +SELECT CONVERT(1, CHAR) IN ('100', 10, '101'); +SELECT CONVERT(1, CHAR) IN ('100', 10, '1'); +SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); + + +--echo # --echo # End of 10.1 tests --echo # diff --git a/mysql-test/t/fast_prefix_index_fetch_innodb.test b/mysql-test/t/fast_prefix_index_fetch_innodb.test index e563e65ec2a..c3b3440d82d 100644 --- a/mysql-test/t/fast_prefix_index_fetch_innodb.test +++ b/mysql-test/t/fast_prefix_index_fetch_innodb.test @@ -31,120 +31,638 @@ select * from prefixinno; let $show_count_statement = show status like 'innodb_secondary_index_triggered_cluster_reads'; let $show_opt_statement = show status like 'innodb_secondary_index_triggered_cluster_reads_avoided'; ---disable_query_log - --echo # Baseline sanity check: 0, 0. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select "no-op query"; ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Eligible for optimization. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('d', 31); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Eligible for optimization, access via fake_id only. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where fake_id = 1031; ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Not eligible for optimization, access via fake_id of big row. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where fake_id = 1033; ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Not eligible for optimization. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('x', 32); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Not eligible for optimization. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('y', 33); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Eligible, should not increment lookup counter. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('b', 8); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Eligible, should not increment lookup counter. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('c', 24); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Should increment lookup counter. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + select id, bigfield from prefixinno where bigfield = repeat('z', 128); ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; --echo # Disable optimization, confirm we still increment counter. ---let $base_count = query_get_value($show_count_statement, Value, 1) ---let $base_opt = query_get_value($show_opt_statement, Value, 1) +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + set global innodb_prefix_index_cluster_optimization = OFF; select id, bigfield from prefixinno where fake_id = 1033; ---let $count = query_get_value($show_count_statement, Value, 1) + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log eval select $count - $base_count into @cluster_lookups; -select @cluster_lookups = 1 as cluster_lookups_matched; ---let $opt = query_get_value($show_opt_statement, Value, 1) -eval select $opt - $base_opt into @cluster_lookups; -select @cluster_lookups = 0 as cluster_lookups_avoided_matched; +eval select $opt - $base_opt into @cluster_lookups_avoided; +--enable_query_log +select @cluster_lookups; +select @cluster_lookups_avoided; ---echo # make test suite happy by cleaning up our mess drop table prefixinno; + +--echo # Multi-byte handling case + +set global innodb_prefix_index_cluster_optimization = ON; +SET NAMES utf8mb4; +CREATE TABLE t1( + f1 varchar(10) CHARACTER SET UTF8MB4 COLLATE UTF8MB4_BIN, + INDEX (f1(3)))ENGINE=INNODB; + +INSERT INTO t1 VALUES('a'), ('cccc'), ('až'), ('cčc'), ('ggᵷg'), ('¢¢'); +INSERT INTO t1 VALUES('தமிழ்'), ('🐱🌑'), ('🌒'), ('🌑'); +INSERT INTO t1 VALUES('😊me'), ('eu€'), ('ls¢'); + +--echo # Eligible - record length is shorter than prefix +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'až'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'தமிழ்'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggᵷ%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '😊%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'ls¢'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '¢¢%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🐱🌑%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌒%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +DROP TABLE t1; + +--echo # Multi-byte with minimum character length > 1 bytes + +CREATE TABLE t1( + f1 varchar(10) CHARACTER SET UTF16 COLLATE UTF16_BIN, + INDEX (f1(3)))ENGINE=INNODB; + +INSERT INTO t1 VALUES('a'), ('cccc'), ('až'), ('cčc'), ('ggᵷg'), ('¢¢'); +INSERT INTO t1 VALUES('தமிழ்'), ('🐱🌑'), ('🌒'), ('🌑'); +INSERT INTO t1 VALUES('😊me'), ('eu€'), ('ls¢'); + +--echo # Eligible - record length is shorter than prefix +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'a'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'c%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'až'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'தமிழ்'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like 'ggᵷ%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '😊%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 = 'ls¢'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX(`f1`) WHERE f1 like '¢¢%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🐱🌑%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length is shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Eligible - record length is shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌒%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +DROP TABLE t1; + +CREATE TABLE t1( + col1 INT, + col2 BLOB DEFAULT NULL, + INDEX `idx1`(col2(4), col1))ENGINE=INNODB; +INSERT INTO t1 VALUES (2, 'test'), (3, repeat('test1', 2000)); +INSERT INTO t1(col1) VALUES(1); + +--echo # Eligible - record length is shorter than prefix length + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 is NULL; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +--echo # Not eligible - record length longer than prefix index + +let $base_count = query_get_value($show_count_statement, Value, 1); +let $base_opt = query_get_value($show_opt_statement, Value, 1); + +SELECT col1 FROM t1 FORCE INDEX (`idx1`) WHERE col2 like 'test1%'; + +let $count = query_get_value($show_count_statement, Value, 1); +let $opt = query_get_value($show_opt_statement, Value, 1); + +--disable_query_log +eval set @cluster_lookups = $count - $base_count; +eval set @cluster_lookups_avoided = $opt - $base_opt; +--enable_query_log + +select @cluster_lookups; +select @cluster_lookups_avoided; + +DROP TABLE t1; set global innodb_prefix_index_cluster_optimization = OFF; diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index 3106889fde6..f9287b952d2 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -100,6 +100,44 @@ drop table t1; --echo End of 5.5 tests +--echo # +--echo # Start of 10.1 tests +--echo # + +--echo # +--echo # MDEV-14452 Precision in INTERVAL xxx DAY_MICROSECOND parsed wrong? +--echo # + +--vertical_results +SELECT + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5' DAY_MICROSECOND) c1, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50' DAY_MICROSECOND) c2, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500' DAY_MICROSECOND) c3, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000' DAY_MICROSECOND) c4, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000' DAY_MICROSECOND) c5, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000' DAY_MICROSECOND) c6, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000' DAY_MICROSECOND) c7, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000' DAY_MICROSECOND) c8, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000' DAY_MICROSECOND) c9, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000' DAY_MICROSECOND) c10, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000' DAY_MICROSECOND) c11, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000' DAY_MICROSECOND) c12, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000' DAY_MICROSECOND) c13, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000' DAY_MICROSECOND) c14, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000000' DAY_MICROSECOND) c15, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000000' DAY_MICROSECOND) c16, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000000' DAY_MICROSECOND) c17, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.500000000000000000' DAY_MICROSECOND) c18, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.5000000000000000000' DAY_MICROSECOND) c19, + DATE_ADD('1000-01-01 00:00:00', INTERVAL '0 00:00:01.50000000000000000000' DAY_MICROSECOND) c20 +; +--horizontal_results + + +--echo # +--echo # End of 10.1 tests +--echo # + # # how + interval is printed # diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 32c1b54b1e4..2669408fdce 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -398,7 +398,7 @@ drop table t1; select json_extract('{"test":8.437e-5}','$.test'); --echo # ---echo # Start of 10.3 tests +--echo # End of 10.2 tests --echo # --echo # @@ -420,3 +420,7 @@ SELECT --enable_ps_protocol --disable_metadata + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index ad81a336544..5417cb20a92 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1763,6 +1763,22 @@ SELECT ADDDATE(DATE'0000-01-01', INTERVAL '3652423:0:0:315569433559' DAY_SECOND) SELECT ADDDATE(DATE'0000-01-01', INTERVAL '0:87658175:0:315569433559' DAY_SECOND); SELECT ADDDATE(DATE'0000-01-01', INTERVAL '0:0:5259490559:315569433599' DAY_SECOND); +--echo # +--echo # MDEV-13202 Assertion `ltime->neg == 0' failed in date_to_datetime +--echo # + +CREATE TABLE t1 (i INT, d DATE); +INSERT INTO t1 VALUES (1, '1970-01-01'); +SELECT MAX(NULLIF(i,1)) FROM t1 ORDER BY DATE_SUB(d,INTERVAL 17300000 HOUR); +DROP TABLE t1; + +CREATE TABLE t1 (i INT, d DATE); +INSERT INTO t1 VALUES (1, '1970-01-01'); +SELECT CONCAT(DATE_SUB(d, INTERVAL 17300000 HOUR)) FROM t1; +DROP TABLE t1; + +SELECT CONCAT(DATE_SUB(TIMESTAMP'1970-01-01 00:00:00', INTERVAL 17300000 HOUR)); + --echo # --echo # End of 10.0 tests diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 3675a09d82f..c9231fef3be 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -759,6 +759,24 @@ SELECT * FROM t1 JOIN t2 ON c1 = c2 HAVING c2 > 'a' ORDER BY c2 LIMIT 1; DROP TABLE t1,t2; +--echo # +--echo # MDEV-6736: Valgrind warnings 'Invalid read' in subselect_engine::calc_const_tables with SQ +--echo # in WHERE and HAVING, ORDER BY, materialization+semijoin +--echo # + +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (3),(8); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (2),(1); + +SELECT a FROM t1 +WHERE 9 IN ( SELECT MIN( a ) FROM t1 ) +HAVING a <> ( SELECT COUNT(*) FROM t2 ) +ORDER BY a; + +DROP TABLE t1,t2; + --echo End of 10.0 tests --echo # diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index acbe19b5e87..34b0551a32e 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -1972,9 +1972,25 @@ INSERT INTO t1 VALUES (0),(1); CREATE TABLE t2 (b2 BIT NOT NULL); INSERT INTO t2 VALUES (0),(1); -SET SESSION JOIN_CACHE_LEVEL = 3; +set @save_join_cache_level= @@join_cache_level; +SET @@join_cache_level = 3; SELECT t1.b1+'0' , t2.b2 + '0' FROM t1 LEFT JOIN t2 ON b1 = b2; DROP TABLE t1, t2; +set @join_cache_level= @save_join_cache_level; + +--echo # +--echo # MDEV-14779: using left join causes incorrect results with materialization and derived tables +--echo # + +create table t1(id int); +insert into t1 values (1),(2); +create table t2(sid int, id int); +insert into t2 values (1,1),(2,2); + +select * from t1 t + left join (select * from t2 where sid in (select max(sid) from t2 where 0=1 group by id)) r + on t.id=r.id ; +drop table t1, t2; --echo # end of 5.5 tests diff --git a/mysql-test/t/ps_qc_innodb.test b/mysql-test/t/ps_qc_innodb.test new file mode 100644 index 00000000000..e09a2bf4070 --- /dev/null +++ b/mysql-test/t/ps_qc_innodb.test @@ -0,0 +1,35 @@ +--source include/have_query_cache.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-15492: Subquery crash similar to MDEV-10050 +--echo # + +SET @qcs.save= @@global.query_cache_size, @qct.save= @@global.query_cache_type; +SET GLOBAL query_cache_size= 512*1024*1024, query_cache_type= ON; + +--connect (con1,localhost,root,,test) +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (b INT) ENGINE=InnoDB; +CREATE VIEW v AS select a from t1 join t2; + +PREPARE stmt1 FROM "SELECT * FROM t1 WHERE a in (SELECT a FROM v)"; + +--connect (con2,localhost,root,,test) +PREPARE stmt2 FROM "SELECT * FROM t1 WHERE a in (SELECT a FROM v)"; +EXECUTE stmt2; + +--connection con1 +EXECUTE stmt1; +INSERT INTO t2 VALUES (0); +EXECUTE stmt1; +START TRANSACTION; +EXECUTE stmt1; + +# Cleanup +--disconnect con1 +--disconnect con2 +--connection default +DROP VIEW v; +DROP TABLE t1, t2; +SET GLOBAL query_cache_size= @qcs.save, query_cache_type= @qct.save; diff --git a/mysql-test/t/shutdown.test b/mysql-test/t/shutdown.test index 775628e441d..e423725177b 100644 --- a/mysql-test/t/shutdown.test +++ b/mysql-test/t/shutdown.test @@ -34,5 +34,5 @@ drop user user1@localhost; --echo # MDEV-8491 - On shutdown, report the user and the host executed that. --echo # --let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err ---let SEARCH_PATTERN=mysqld(\.exe)? \(root\[root\] @ localhost \[(::1)?\]\): Normal shutdown +--let SEARCH_PATTERN=mysqld(\.exe)? \(initiated by: root\[root\] @ localhost \[(::1)?\]\): Normal shutdown --source include/search_pattern_in_file.inc diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index d4ccbcf6f66..77ea117b15f 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2032,6 +2032,14 @@ SELECT ( SELECT COUNT(*) FROM t1 WHERE a = c ) AS field, COUNT(DISTINCT c) FROM t2 WHERE b <= 'quux' GROUP BY field; drop table t1,t2; +--echo # +--echo # MDEV-15555: select from DUAL where false yielding wrong result when in a IN +--echo # + +explain +SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); +SELECT 2 IN (SELECT 2 from DUAL WHERE 1 != 1); + SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; diff --git a/mysql-test/t/subselect_mat.test b/mysql-test/t/subselect_mat.test index 9c7c9683d0b..bf5de741ea0 100644 --- a/mysql-test/t/subselect_mat.test +++ b/mysql-test/t/subselect_mat.test @@ -256,6 +256,19 @@ FROM t1; drop table t1, t2; --echo # +--echo # MDEV-15235: Assertion `length > 0' failed in create_ref_for_key +--echo # + +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (f CHAR(1)); +INSERT INTO t2 VALUES ('a'),('b'); +explain +SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 ); +SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 ); +DROP TABLE t1, t2; + +--echo # --echo # MDEV-9489: Assertion `0' failed in Protocol::end_statement() on --echo # UNION ALL --echo # diff --git a/mysql-test/t/type_temporal_innodb.test b/mysql-test/t/type_temporal_innodb.test index 1ab68961eaa..81f2f586c51 100644 --- a/mysql-test/t/type_temporal_innodb.test +++ b/mysql-test/t/type_temporal_innodb.test @@ -58,3 +58,11 @@ SELECT * FROM t1 IGNORE KEY (b) WHERE b=''; SELECT * FROM t1 WHERE a=b; SELECT 1 FROM t1 WHERE (SELECT a FROM t1 group by c) = b; DROP TABLE t1; + +# +# MDEV-15570 Assertion `Item_cache_temporal::field_type() != MYSQL_TYPE_TIME' failed in Item_cache_temporal::val_datetime_packed +# +CREATE TABLE t1 (d DATE) ENGINE=InnoDB; +INSERT INTO t1 VALUES ('2012-12-21'); +SELECT * FROM t1 WHERE LEAST( UTC_TIME(), d ); +DROP TABLE t1; diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 6fffd948dc5..d8bb66fcd5c 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -506,7 +506,7 @@ SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 10:20:30' AND LENGTH(a)=8; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-00 10:20:30' AND LENGTH(a)=30+RAND(); ---echo # Old mode, TIMESTAMP literal, zon-zero YYYYMMDD, no propagation +--echo # Old mode, TIMESTAMP literal, non-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30'; SELECT * FROM t1 WHERE a=TIMESTAMP'0000-00-01 10:20:30' AND LENGTH(a)=8; EXPLAIN EXTENDED @@ -522,7 +522,7 @@ SELECT * FROM t1 WHERE a='0000-00-00 10:20:30' AND LENGTH(a)=8; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-00 10:20:30' AND LENGTH(a)=30+RAND(); ---echo # Old mode, TIMESTAMP-alike literal, zon-zero YYYYMMDD, no propagation +--echo # Old mode, TIMESTAMP-alike literal, non-zero YYYYMMDD, no propagation SELECT * FROM t1 WHERE a='0000-00-01 10:20:30'; SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; EXPLAIN EXTENDED @@ -724,6 +724,29 @@ SELECT MAX(a), MAX(COALESCE(a)) FROM t1; DROP TABLE t1; --echo # +--echo # MDEV-15321: different results when using value of optimizer_use_condition_selectivity=4 and =1 +--echo # + +SET @save_old_mode=@@old_mode; +SET @@old_mode=zero_date_time_cast; +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('0000-00-00 10:20:30'),('0000-00-00 10:20:31'); +INSERT INTO t1 VALUES ('0000-00-01 10:20:30'),('0000-00-01 10:20:31'); +INSERT INTO t1 VALUES ('31 10:20:30'),('32 10:20:30'),('33 10:20:30'),('34 10:20:30'); + +SET @save_optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity; +SET @@optimizer_use_condition_selectivity=1; +SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; + +SET @@optimizer_use_condition_selectivity=4; +SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='0000-00-01 10:20:30' AND LENGTH(a)=8; +drop table t1; +SET @@optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity; +set @@old_mode= @save_old_mode; + +--echo # --echo # End of 10.1 tests --echo # diff --git a/mysys/my_default.c b/mysys/my_default.c index dc8523576c6..b7819ef99f0 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -631,7 +631,7 @@ int my_load_defaults(const char *conf_file, const char **groups, if (!my_getopt_is_args_separator((*argv)[i])) /* skip arguments separator */ printf("%s ", (*argv)[i]); puts(""); - exit(0); + DBUG_RETURN(4); } if (default_directories) @@ -641,7 +641,7 @@ int my_load_defaults(const char *conf_file, const char **groups, err: fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); - return 2; + DBUG_RETURN(2); } diff --git a/plugin/auth_pam/mapper/pam_user_map.c b/plugin/auth_pam/mapper/pam_user_map.c index e62be946c4a..c03ea12be74 100644 --- a/plugin/auth_pam/mapper/pam_user_map.c +++ b/plugin/auth_pam/mapper/pam_user_map.c @@ -22,14 +22,24 @@ top: accounting @group_ro: readonly ========================================================= +If something doesn't work as expected you can get verbose +comments with the 'debug' option like this +========================================================= +auth required pam_user_map.so debug +========================================================= +These comments are written to the syslog as 'authpriv.debug' +and usually end up in /var/log/secure file. */ #include <stdlib.h> #include <stdio.h> +#include <ctype.h> +#include <string.h> #include <syslog.h> #include <grp.h> #include <pwd.h> +#include <security/pam_ext.h> #include <security/pam_modules.h> #define FILENAME "/etc/security/user_map.conf" @@ -90,9 +100,42 @@ static int user_in_group(const gid_t *user_groups, int ng,const char *group) } +static void print_groups(pam_handle_t *pamh, const gid_t *user_groups, int ng) +{ + char buf[256]; + char *c_buf= buf, *buf_end= buf+sizeof(buf)-2; + struct group *gr; + int cg; + + for (cg=0; cg < ng; cg++) + { + char *c; + if (c_buf == buf_end) + break; + *(c_buf++)= ','; + if (!(gr= getgrgid(user_groups[cg])) || + !(c= gr->gr_name)) + continue; + while (*c) + { + if (c_buf == buf_end) + break; + *(c_buf++)= *(c++); + } + } + c_buf[0]= c_buf[1]= 0; + pam_syslog(pamh, LOG_DEBUG, "User belongs to %d %s [%s].\n", + ng, (ng == 1) ? "group" : "groups", buf+1); +} + + +static const char debug_keyword[]= "debug"; +#define SYSLOG_DEBUG if (mode_debug) pam_syslog + int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { + int mode_debug= 0; int pam_err, line= 0; const char *username; char buf[256]; @@ -101,6 +144,14 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, gid_t *groups= group_buffer; int n_groups= -1; + for (; argc > 0; argc--) + { + if (strcasecmp(argv[argc-1], debug_keyword) == 0) + mode_debug= 1; + } + + SYSLOG_DEBUG(pamh, LOG_DEBUG, "Opening file '%s'.\n", FILENAME); + f= fopen(FILENAME, "r"); if (f == NULL) { @@ -110,12 +161,18 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, pam_err = pam_get_item(pamh, PAM_USER, (const void**)&username); if (pam_err != PAM_SUCCESS) + { + pam_syslog(pamh, LOG_ERR, "Cannot get username.\n"); goto ret; + } + + SYSLOG_DEBUG(pamh, LOG_DEBUG, "Incoming username '%s'.\n", username); while (fgets(buf, sizeof(buf), f) != NULL) { char *s= buf, *from, *to, *end_from, *end_to; int check_group; + int cmp_result; line++; @@ -124,7 +181,11 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, if ((check_group= *s == '@')) { if (n_groups < 0) + { n_groups= populate_user_groups(username, &groups); + if (mode_debug) + print_groups(pamh, groups, n_groups); + } s++; } from= s; @@ -139,14 +200,30 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, if (end_to == to) goto syntax_error; *end_from= *end_to= 0; - if (check_group ? - user_in_group(groups, n_groups, from) : - (strcmp(username, from) == 0)) + + if (check_group) + { + cmp_result= user_in_group(groups, n_groups, from); + SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if user is in group '%s': %s\n", + from, cmp_result ? "YES":"NO"); + } + else + { + cmp_result= (strcmp(username, from) == 0); + SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if username '%s': %s\n", + from, cmp_result ? "YES":"NO"); + } + if (cmp_result) { pam_err= pam_set_item(pamh, PAM_USER, to); + SYSLOG_DEBUG(pamh, LOG_DEBUG, + (pam_err == PAM_SUCCESS) ? "User mapped as '%s'\n" : + "Couldn't map as '%s'\n", to); goto ret; } } + + SYSLOG_DEBUG(pamh, LOG_DEBUG, "User not found in the list.\n"); pam_err= PAM_AUTH_ERR; goto ret; @@ -162,6 +239,7 @@ ret: return pam_err; } + int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { diff --git a/plugin/disks/CMakeLists.txt b/plugin/disks/CMakeLists.txt new file mode 100644 index 00000000000..446c64d0fdd --- /dev/null +++ b/plugin/disks/CMakeLists.txt @@ -0,0 +1,5 @@ +IF("${CMAKE_SYSTEM}" MATCHES "Linux") + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql) + MYSQL_ADD_PLUGIN(DISKS information_schema_disks.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED) +ENDIF() + diff --git a/plugin/disks/README.txt b/plugin/disks/README.txt new file mode 100644 index 00000000000..b49db3c03b5 --- /dev/null +++ b/plugin/disks/README.txt @@ -0,0 +1,86 @@ +Information Schema Disks +------------------------ +This is a proof-of-concept information schema plugin that allows the +disk space situation to be monitored. When installed, it can be used +as follows: + + > select * from information_schema.disks; + +-----------+-----------------------+-----------+----------+-----------+ + | Disk | Path | Total | Used | Available | + +-----------+-----------------------+-----------+----------+-----------+ + | /dev/sda3 | / | 47929956 | 30666304 | 14805864 | + | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 | + | /dev/sda4 | /home | 174679768 | 80335392 | 85448120 | + | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Pictures | 961301832 | 83764 | 912363644 | + | /dev/sda3 | /var/lib/docker/aufs | 47929956 | 30666304 | 14805864 | + +-----------+-----------------------+-----------+----------+-----------+ + 9 rows in set (0.00 sec) + +- 'Disk' is the name of the disk itself. +- 'Path' is the mount point of the disk. +- 'Total' is the total space in KiB. +- 'Used' is the used amount of space in KiB, and +- 'Available' is the amount of space in KiB available to non-root users. + +Note that as the amount of space available to root may be more that what +is available to non-root users, 'available' + 'used' may be less than 'total'. + +All paths to which a particular disk has been mounted are reported. The +rationale is that someone might want to take different action e.g. depending +on which disk is relevant for a particular path. This leads to the same disk +being reported multiple times. An alternative to this would be to have two +tables; disks and mounts. + + > select * from information_schema.disks; + +-----------+-----------+----------+-----------+ + | Disk | Total | Used | Available | + +-----------+-----------+----------+-----------+ + | /dev/sda3 | 47929956 | 30666304 | 14805864 | + | /dev/sda1 | 191551 | 3461 | 188090 | + | /dev/sda4 | 174679768 | 80335392 | 85448120 | + | /dev/sdb1 | 961301832 | 83764 | 912363644 | + +-----------+-----------+----------+-----------+ + + > select * from information_schema.mounts; + +-----------------------+-----------+ + | Path | Disk | + +-----------------------+-----------+ + | / | /dev/sda3 | + | /boot/efi | /dev/sda1 | + | /home | /dev/sda4 | + | /mnt/hdd | /dev/sdb1 | + | /home/wikman/Music | /dev/sdb1 | + ... + + +Installation +------------ + +- Use "install plugin" or "install soname" command: + + MariaDB [(none)]> install plugin disks soname 'disks.so'; + + or + + MariaDB [(none)]> install soname 'disks.so'; + +Usage +----- +The plugin appears as the table 'disks' in 'information_schema'. + + MariaDB [(none)]> select * from information_schema.disks; + +-----------+-----------------------+-----------+----------+-----------+ + | Disk | Path | Total | Used | Available | + +-----------+-----------------------+-----------+----------+-----------+ + | /dev/sda3 | / | 47929956 | 30666308 | 14805860 | + | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 | + | /dev/sda4 | /home | 174679768 | 80348148 | 85435364 | + | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 | + ... + diff --git a/plugin/disks/information_schema_disks.cc b/plugin/disks/information_schema_disks.cc new file mode 100644 index 00000000000..d2287631386 --- /dev/null +++ b/plugin/disks/information_schema_disks.cc @@ -0,0 +1,156 @@ +/* + Copyright (c) 2017, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include <my_global.h> +#include <sys/statvfs.h> +#include <sys/types.h> +#include <mntent.h> +#include <sql_class.h> +#include <table.h> + +bool schema_table_store_record(THD *thd, TABLE *table); + +namespace +{ + +struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; + +ST_FIELD_INFO disks_table_fields[]= +{ + { "Disk", PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 }, + { "Path", PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 }, + { "Total", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Total amount available + { "Used", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Amount of space used + { "Available", 32, MYSQL_TYPE_LONG, 0, 0 ,0 ,0 }, // Amount available to users other than root. + { 0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0 } +}; + +int disks_table_add_row(THD* pThd, + TABLE* pTable, + const char* zDisk, + const char* zPath, + const struct statvfs& info) +{ + // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html + // + // f_frsize Fundamental file system block size. + // f_blocks Total number of blocks on file system in units of f_frsize. + // f_bfree Total number of free blocks. + // f_bavail Number of free blocks available to non-privileged process. + + size_t total = (info.f_frsize * info.f_blocks) / 1024; + size_t used = (info.f_frsize * (info.f_blocks - info.f_bfree)) / 1024; + size_t avail = (info.f_frsize * info.f_bavail) / 1024; + + pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info); + pTable->field[1]->store(zPath, strlen(zPath), system_charset_info); + pTable->field[2]->store(total); + pTable->field[3]->store(used); + pTable->field[4]->store(avail); + + // 0 means success. + return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0; +} + +int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath) +{ + int rv = 0; + + struct statvfs info; + + if (statvfs(zPath, &info) == 0) // We ignore failures. + { + rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info); + } + + return rv; +} + +int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond) +{ + int rv = 1; + TABLE* pTable = pTables->table; + + FILE* pFile = setmntent("/etc/mtab", "r"); + + if (pFile) + { + const size_t BUFFER_SIZE = 4096; // 4K should be sufficient. + + char* pBuffer = new (std::nothrow) char [BUFFER_SIZE]; + + if (pBuffer) + { + rv = 0; + + struct mntent ent; + struct mntent* pEnt; + + while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE))) + { + // We only report the ones that refer to physical disks. + if (pEnt->mnt_fsname[0] == '/') + { + rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir); + } + } + + delete [] pBuffer; + } + else + { + rv = 1; + } + + endmntent(pFile); + } + + return rv; +} + +int disks_table_init(void *ptr) +{ + ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr; + + pSchema_table->fields_info = disks_table_fields; + pSchema_table->fill_table = disks_fill_table; + return 0; +} + +} + +extern "C" +{ + +maria_declare_plugin(disks) +{ + MYSQL_INFORMATION_SCHEMA_PLUGIN, + &disks_table_info, /* type-specific descriptor */ + "DISKS", /* table name */ + "Johan Wikman", /* author */ + "Disk space information", /* description */ + PLUGIN_LICENSE_GPL, /* license type */ + disks_table_init, /* init function */ + NULL, /* deinit function */ + 0x0100, /* version = 1.0 */ + NULL, /* no status variables */ + NULL, /* no system variables */ + "1.0", /* String version representation */ + MariaDB_PLUGIN_MATURITY_BETA /* Maturity (see include/mysql/plugin.h)*/ +} +mysql_declare_plugin_end; + +} diff --git a/plugin/disks/mysql-test/disks/disks.result b/plugin/disks/mysql-test/disks/disks.result new file mode 100644 index 00000000000..65b1127d479 --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks.result @@ -0,0 +1,12 @@ +show create table information_schema.disks; +Table Create Table +DISKS CREATE TEMPORARY TABLE `DISKS` ( + `Disk` varchar(4096) NOT NULL DEFAULT '', + `Path` varchar(4096) NOT NULL DEFAULT '', + `Total` int(32) NOT NULL DEFAULT 0, + `Used` int(32) NOT NULL DEFAULT 0, + `Available` int(32) NOT NULL DEFAULT 0 +) ENGINE=MEMORY DEFAULT CHARSET=utf8 +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +sum(Total) > sum(Available) sum(Total)>sum(Used) +1 1 diff --git a/plugin/disks/mysql-test/disks/disks.test b/plugin/disks/mysql-test/disks/disks.test new file mode 100644 index 00000000000..13a0762ae01 --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks.test @@ -0,0 +1,2 @@ +show create table information_schema.disks; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; diff --git a/plugin/disks/mysql-test/disks/suite.opt b/plugin/disks/mysql-test/disks/suite.opt new file mode 100644 index 00000000000..afbbe2b0163 --- /dev/null +++ b/plugin/disks/mysql-test/disks/suite.opt @@ -0,0 +1 @@ +--plugin-load-add=$DISKS_SO diff --git a/plugin/disks/mysql-test/disks/suite.pm b/plugin/disks/mysql-test/disks/suite.pm new file mode 100644 index 00000000000..c64ef3b3133 --- /dev/null +++ b/plugin/disks/mysql-test/disks/suite.pm @@ -0,0 +1,10 @@ +package My::Suite::Disks; + +@ISA = qw(My::Suite); + +return "No Disks plugin" unless $ENV{DISKS_SO}; + +sub is_default { 1 } + +bless { }; + diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 7b7cbab06ca..aee2f0b7f64 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -176,12 +176,26 @@ get_transfer() wsrep_log_info "Using netcat as streamer" if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then if nc -h 2>&1 | grep -q ncat;then + # Ncat tcmd="nc -l ${TSST_PORT}" - else + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat tcmd="nc -dl ${TSST_PORT}" + else + # traditional netcat + tcmd="nc -l -p ${TSST_PORT}" fi else - tcmd="nc ${REMOTEIP} ${TSST_PORT}" + if nc -h 2>&1 | grep -q ncat;then + # Ncat + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + else + # traditional netcat + tcmd="nc -q0 ${REMOTEIP} ${TSST_PORT}" + fi fi else tfmt='socat' diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index d28a1c161ce..cfe4838fbc4 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -119,11 +119,11 @@ MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF "\ # Check if binary logging is enabled on the joiner node. # Note: SELECT cannot be used at this point. -LOG_BIN=$(echo "SHOW VARIABLES LIKE 'log_bin'" | $MYSQL |\ +LOG_BIN=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'log_bin'" | $MYSQL |\ tail -1 | awk -F ' ' '{ print $2 }') # Check the joiner node's server version. -SERVER_VERSION=$(echo "SHOW VARIABLES LIKE 'version'" | $MYSQL |\ +SERVER_VERSION=$(echo "set statement wsrep_sync_wait=0 for SHOW VARIABLES LIKE 'version'" | $MYSQL |\ tail -1 | awk -F ' ' '{ print $2 }') RESET_MASTER="" diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index e7313e4e188..79442d415e9 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -265,13 +265,26 @@ get_transfer() wsrep_log_info "Using netcat as streamer" if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then if nc -h 2>&1 | grep -q ncat; then + # Ncat tcmd="nc $sockopt -l ${TSST_PORT}" - else + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat tcmd="nc $sockopt -dl ${TSST_PORT}" + else + # traditional netcat + tcmd="nc $sockopt -l -p ${TSST_PORT}" fi else - # netcat doesn't understand [] around IPv6 address - tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + if nc -h 2>&1 | grep -q ncat;then + # Ncat + tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat + tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + else + # traditional netcat + tcmd="nc -q0 ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + fi fi else tfmt='socat' diff --git a/scripts/wsrep_sst_xtrabackup.sh b/scripts/wsrep_sst_xtrabackup.sh index d80677e7a76..3a30f5898db 100644 --- a/scripts/wsrep_sst_xtrabackup.sh +++ b/scripts/wsrep_sst_xtrabackup.sh @@ -141,12 +141,26 @@ get_transfer() wsrep_log_info "Using netcat as streamer" if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then if nc -h 2>&1 | grep -q ncat;then + # Ncat tcmd="nc -l ${TSST_PORT}" - else + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat tcmd="nc -dl ${TSST_PORT}" + else + # traditional netcat + tcmd="nc -l -p ${TSST_PORT}" fi else - tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${TSST_PORT}" + if nc -h 2>&1 | grep -q ncat;then + # Ncat + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + elif nc -h 2>&1 | grep -q -- '-d\>';then + # Debian netcat + tcmd="nc ${REMOTEIP} ${TSST_PORT}" + else + # traditional netcat + tcmd="nc -q0 ${REMOTEIP} ${TSST_PORT}" + fi fi else tfmt='socat' diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc index 4afa2168b8d..93f6f32d473 100644 --- a/sql/ha_sequence.cc +++ b/sql/ha_sequence.cc @@ -259,8 +259,7 @@ int ha_sequence::write_row(uchar *buf) sequence->copy(&tmp_seq); rows_changed++; /* We have to do the logging while we hold the sequence mutex */ - if (table->file->check_table_binlog_row_based(1)) - error= binlog_log_row(table, 0, buf, log_func); + error= binlog_log_row(table, 0, buf, log_func); row_already_logged= 1; } diff --git a/sql/handler.cc b/sql/handler.cc index 7662d68e51f..e5362c7cf9c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5899,29 +5899,6 @@ bool handler::check_table_binlog_row_based_internal(bool binlog_row) { THD *thd= table->in_use; -#ifdef WITH_WSREP - /* only InnoDB tables will be replicated through binlog emulation */ - if (binlog_row && - ((WSREP_EMULATE_BINLOG(thd) && - table->file->partition_ht()->db_type != DB_TYPE_INNODB) || - (thd->wsrep_ignore_table == true))) - return 0; - - /* enforce wsrep_max_ws_rows */ - if (WSREP(thd) && table->s->tmp_table == NO_TMP_TABLE) - { - thd->wsrep_affected_rows++; - if (wsrep_max_ws_rows && - thd->wsrep_exec_mode != REPL_RECV && - thd->wsrep_affected_rows > wsrep_max_ws_rows) - { - trans_rollback_stmt(thd) || trans_rollback(thd); - my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0)); - return ER_ERROR_DURING_COMMIT; - } - } -#endif - return (table->s->can_do_row_logging && thd->is_current_stmt_binlog_format_row() && /* @@ -6030,12 +6007,10 @@ static int write_locked_table_maps(THD *thd) } -static int check_wsrep_max_ws_rows(); - -int binlog_log_row(TABLE* table, - const uchar *before_record, - const uchar *after_record, - Log_func *log_func) +static int binlog_log_row_internal(TABLE* table, + const uchar *before_record, + const uchar *after_record, + Log_func *log_func) { bool error= 0; THD *const thd= table->in_use; @@ -6059,17 +6034,42 @@ int binlog_log_row(TABLE* table, bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE || table->file->has_transactions(); error= (*log_func)(thd, table, has_trans, before_record, after_record); - - /* - Now that the record has been logged, increment wsrep_affected_rows and - also check whether its within the allowable limits (wsrep_max_ws_rows). - */ - if (error == 0) - error= check_wsrep_max_ws_rows(); } return error ? HA_ERR_RBR_LOGGING_FAILED : 0; } +int binlog_log_row(TABLE* table, const uchar *before_record, + const uchar *after_record, Log_func *log_func) +{ +#ifdef WITH_WSREP + THD *const thd= table->in_use; + + /* only InnoDB tables will be replicated through binlog emulation */ + if ((WSREP_EMULATE_BINLOG(thd) && + table->file->partition_ht()->db_type != DB_TYPE_INNODB) || + (thd->wsrep_ignore_table == true)) + return 0; + + /* enforce wsrep_max_ws_rows */ + if (WSREP(thd) && table->s->tmp_table == NO_TMP_TABLE) + { + thd->wsrep_affected_rows++; + if (wsrep_max_ws_rows && + thd->wsrep_exec_mode != REPL_RECV && + thd->wsrep_affected_rows > wsrep_max_ws_rows) + { + trans_rollback_stmt(thd) || trans_rollback(thd); + my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0)); + return ER_ERROR_DURING_COMMIT; + } + } +#endif + + if (!table->file->check_table_binlog_row_based(1)) + return 0; + return binlog_log_row_internal(table, before_record, after_record, log_func); +} + int handler::ha_external_lock(THD *thd, int lock_type) { @@ -6175,30 +6175,6 @@ int handler::ha_reset() } -static int check_wsrep_max_ws_rows() -{ -#ifdef WITH_WSREP - if (wsrep_max_ws_rows) - { - THD *thd= current_thd; - - if (!WSREP(thd)) - return 0; - - thd->wsrep_affected_rows++; - if (thd->wsrep_exec_mode != REPL_RECV && - thd->wsrep_affected_rows > wsrep_max_ws_rows) - { - trans_rollback_stmt(thd) || trans_rollback(thd); - my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0)); - return ER_ERROR_DURING_COMMIT; - } - } -#endif /* WITH_WSREP */ - return 0; -} - - int handler::ha_write_row(uchar *buf) { int error; @@ -6219,8 +6195,7 @@ int handler::ha_write_row(uchar *buf) if (likely(!error) && !row_already_logged) { rows_changed++; - if (table->file->check_table_binlog_row_based(1)) - error= binlog_log_row(table, 0, buf, log_func); + error= binlog_log_row(table, 0, buf, log_func); } DEBUG_SYNC_C("ha_write_row_end"); DBUG_RETURN(error); @@ -6252,8 +6227,7 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) if (likely(!error) && !row_already_logged) { rows_changed++; - if (table->file->check_table_binlog_row_based(1)) - error= binlog_log_row(table, old_data, new_data, log_func); + error= binlog_log_row(table, old_data, new_data, log_func); } return error; } @@ -6308,8 +6282,7 @@ int handler::ha_delete_row(const uchar *buf) if (likely(!error)) { rows_changed++; - if (table->file->check_table_binlog_row_based(1)) - error= binlog_log_row(table, buf, 0, log_func); + error= binlog_log_row(table, buf, 0, log_func); } return error; } diff --git a/sql/item.cc b/sql/item.cc index 215c1450a3c..b955e4372e9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -149,19 +149,21 @@ bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime, - truncate the YYYYMMDD part - add (MM*33+DD)*24 to hours - add (MM*31+DD)*24 to hours - Let's return NULL here, to disallow equal field propagation. + Let's return TRUE here, to disallow equal field propagation. Note, If we start to use this method in more pieces of the code other - than eqial field propagation, we should probably return - NULL only if some flag in fuzzydate is set. + than equal field propagation, we should probably return + TRUE only if some flag in fuzzydate is set. */ - return (null_value= true); + return true; } if (datetime_to_time_with_warn(thd, ltime, <ime2, TIME_SECOND_PART_DIGITS)) { /* - Time difference between CURRENT_DATE and ltime - did not fit into the supported TIME range + If the time difference between CURRENT_DATE and ltime + did not fit into the supported TIME range, then we set the + difference to the maximum possible value in the supported TIME range */ + DBUG_ASSERT(0); return (null_value= true); } *ltime= ltime2; @@ -10042,7 +10044,7 @@ double Item_cache_temporal::val_real() } -bool Item_cache_temporal::cache_value() +bool Item_cache_temporal::cache_value() { if (!example) return false; @@ -10071,12 +10073,11 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) if (!has_value()) { bzero((char*) ltime,sizeof(*ltime)); - return 1; + return true; } unpack_time(value, ltime, mysql_timestamp_type()); return 0; - } diff --git a/sql/item.h b/sql/item.h index 06720a33cf8..860a1fb1bde 100644 --- a/sql/item.h +++ b/sql/item.h @@ -27,6 +27,7 @@ #include "sql_const.h" /* RAND_TABLE_BIT, MAX_FIELD_NAME */ #include "field.h" /* Derivation */ #include "sql_type.h" +#include "sql_time.h" C_MODE_START #include <ma_dyncol.h> @@ -4404,7 +4405,7 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal Item_date_literal_for_invalid_dates::get_date() (unlike the regular Item_date_literal::get_date()) - does not check the result for NO_ZERO_IN_DATE and NO_ZER_DATE, + does not check the result for NO_ZERO_IN_DATE and NO_ZERO_DATE, always returns success (false), and does not produce error/warning messages. We need these _for_invalid_dates classes to be able to rewrite: @@ -6057,7 +6058,7 @@ public: virtual Item *get_item() { return example; } virtual bool cache_value()= 0; bool basic_const_item() const - { return MY_TEST(example && example->basic_const_item()); } + { return example && example->basic_const_item(); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } bool is_null() { return !has_value(); } virtual bool is_expensive() diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6e19cfcdf80..89aa307486e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -34,7 +34,6 @@ #include "sql_time.h" // make_truncated_value_warning #include "sql_base.h" // dynamic_column_error_message - /** find an temporal type (item) that others will be converted to for the purpose of comparison. @@ -42,7 +41,7 @@ this is the type that will be used in warnings like "Incorrect <<TYPE>> value". */ -Item *find_date_time_item(Item **args, uint nargs, uint col) +static Item *find_date_time_item(Item **args, uint nargs, uint col) { Item *date_arg= 0, **arg, **arg_end; for (arg= args, arg_end= args + nargs; arg != arg_end ; arg++) @@ -3067,22 +3066,12 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) /** Check if (*place) and new_value points to different Items and call THD::change_item_tree() if needed. - - This function is a workaround for implementation deficiency in - Item_func_case. The problem there is that the 'args' attribute contains - Items from different expressions. - - The function must not be used elsewhere and will be remove eventually. */ -static void change_item_tree_if_needed(THD *thd, - Item **place, - Item *new_value) +static void change_item_tree_if_needed(THD *thd, Item **place, Item *new_value) { - if (*place == new_value) - return; - - thd->change_item_tree(place, new_value); + if (new_value && *place != new_value) + thd->change_item_tree(place, new_value); } @@ -3270,10 +3259,11 @@ Item* Item_func_case_simple::propagate_equal_fields(THD *thd, for (uint i= 0; i < arg_count; i++) { /* - Even "i" values cover items that are in a comparison context: - CASE x0 WHEN x1 .. WHEN x2 .. WHEN x3 .. - Odd "i" values cover items that are not in comparison: - CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END + These arguments are in comparison. + Allow invariants of the same value during propagation. + Note, as we pass ANY_SUBST, none of the WHEN arguments will be + replaced to zero-filled constants (only IDENTITY_SUBST allows this). + Such a change for WHEN arguments would require rebuilding cmp_items. */ Item *new_item= 0; if (i == 0) // Then CASE (the switch) argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 4caf7e4622d..3d11a226d07 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -363,6 +363,7 @@ public: bool is_null(); longlong val_int(); void cleanup(); + enum Functype functype() const { return IN_OPTIMIZER_FUNC; } const char *func_name() const { return "<in_optimizer>"; } Item_cache **get_cache() { return &cache; } void keep_top_level_cache(); @@ -380,6 +381,8 @@ public: void reset_cache() { cache= NULL; } virtual void print(String *str, enum_query_type query_type); void restore_first_argument(); + Item* get_wrapped_in_subselect_item() + { return args[1]; } Item *get_copy(THD *thd) { return get_item_copy<Item_in_optimizer>(thd, this); } }; @@ -550,14 +553,13 @@ public: clone->cmp.comparators= 0; } return clone; - } - + } }; /** XOR inherits from Item_bool_func because it is not optimized yet. Later, when XOR is optimized, it needs to inherit from - Item_cond instead. See WL#5800. + Item_cond instead. See WL#5800. */ class Item_func_xor :public Item_bool_func { @@ -1195,7 +1197,7 @@ class Item_func_nullif :public Item_func_case_expression The left "a" is in a comparison and can be replaced by: - Item_func::convert_const_compared_to_int_field() - agg_item_set_converter() in set_cmp_func() - - Arg_comparator::cache_converted_constant() in set_cmp_func() + - cache_converted_constant() in set_cmp_func() Both "a"s are subject to equal fields propagation and can be replaced by: - Item_field::propagate_equal_fields(ANY_SUBST) for the left "a" @@ -1395,9 +1397,6 @@ public: /* Class to represent a vector of constant DATE/DATETIME values. - Values are obtained with help of the get_datetime_value() function. - If the left item is a constant one then its value is cached in the - lval_cache variable. */ class in_temporal :public in_longlong { @@ -1538,6 +1537,13 @@ public: { value_res= item->val_str(&value); m_null_value= item->null_value; + // Make sure to cache the result String inside "value" + if (value_res && value_res != &value) + { + if (value.copy(*value_res)) + value.set("", 0, item->collation.collation); + value_res= &value; + } } int cmp_not_null(const Value *val) { @@ -1602,9 +1608,6 @@ public: /* Compare items in the DATETIME context. - Values are obtained with help of the get_datetime_value() function. - If the left item is a constant one then its value is cached in the - lval_cache variable. */ class cmp_item_temporal: public cmp_item_scalar { @@ -3115,6 +3118,11 @@ public: void sort(Item_field_cmpfunc compare, void *arg); void fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); + void cleanup() + { + delete eval_item; + eval_item= NULL; + } void update_used_tables(); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, @@ -3405,10 +3413,6 @@ inline bool is_cond_or(Item *item) Item *and_expressions(Item *a, Item *b, Item **org_item); -longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, - enum_field_types f_type, bool *is_null); - - class Comp_creator { public: diff --git a/sql/item_func.h b/sql/item_func.h index fb775b36ca4..f33b936d8c7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -74,7 +74,8 @@ public: NOW_FUNC, NOW_UTC_FUNC, SYSDATE_FUNC, TRIG_COND_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, - NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC, JSON_EXTRACT_FUNC }; + NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC, + JSON_EXTRACT_FUNC }; enum Type type() const { return FUNC_ITEM; } virtual enum Functype functype() const { return UNKNOWN_FUNC; } Item_func(THD *thd): Item_func_or_sum(thd) @@ -3128,7 +3129,6 @@ public: Item *get_system_var(THD *thd, enum_var_type var_type, const LEX_CSTRING *name, const LEX_CSTRING *component); extern bool check_reserved_words(const LEX_CSTRING *name); -Item *find_date_time_item(Item **args, uint nargs, uint col); double my_double_round(double value, longlong dec, bool dec_unsigned, bool truncate); bool eval_const_cond(COND *cond); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a8051ccd469..6378e9b76bf 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1819,7 +1819,7 @@ Item_in_subselect::single_value_transformer(JOIN *join) Item* join_having= join->having ? join->having : join->tmp_having; if (!(join_having || select_lex->with_sum_func || select_lex->group_list.elements) && - select_lex->table_list.elements == 0 && + select_lex->table_list.elements == 0 && !join->conds && !select_lex->master_unit()->is_unit_op()) { Item *where_item= (Item*) select_lex->item_list.head(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index f612b4d6aa2..5f4a489fca1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -714,7 +714,7 @@ static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, s { const char *end=str+length; uint i; - int msec_length= 0; + size_t field_length= 0; while (str != end && !my_isdigit(cs,*str)) str++; @@ -725,7 +725,8 @@ static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, s const char *start= str; for (value= 0; str != end && my_isdigit(cs, *str); str++) value= value*10 + *str - '0'; - msec_length= 6 - (int)(str - start); + if ((field_length= (size_t)(str - start)) >= 20) + return true; values[i]= value; while (str != end && !my_isdigit(cs,*str)) str++; @@ -740,8 +741,13 @@ static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, s } } - if (transform_msec && msec_length > 0) - values[count - 1] *= (long) log_10_int[msec_length]; + if (transform_msec && field_length > 0) + { + if (field_length < 6) + values[count - 1] *= log_10_int[6 - field_length]; + else if (field_length > 6) + values[count - 1] /= log_10_int[field_length - 6]; + } return (str != end); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 60ad41eed39..0eee10d5e7a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5757,8 +5757,7 @@ int mysqld_main(int argc, char **argv) orig_argc= argc; orig_argv= argv; my_getopt_use_args_separator= TRUE; - if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv)) - return 1; + load_defaults_or_exit(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv); my_getopt_use_args_separator= FALSE; defaults_argc= argc; defaults_argv= argv; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index eff28d0c27d..a723980ad50 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -848,8 +848,10 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) Make sure that create_tmp_table will not fail due to too long keys. See MDEV-7122. This check is performed inside create_tmp_table also and we must do it so that we know the table has keys created. + Make sure that the length of the key for the temp_table is atleast + greater than 0. */ - if (total_key_length > tmp_table_max_key_length() || + if (!total_key_length || total_key_length > tmp_table_max_key_length() || elements > tmp_table_max_key_parts()) DBUG_RETURN(FALSE); @@ -979,6 +981,10 @@ bool check_for_outer_joins(List<TABLE_LIST> *join_list) void find_and_block_conversion_to_sj(Item *to_find, List_iterator_fast<Item_in_subselect> &li) { + if (to_find->type() == Item::FUNC_ITEM && + ((Item_func*)to_find)->functype() == Item_func::IN_OPTIMIZER_FUNC) + to_find= ((Item_in_optimizer*)to_find)->get_wrapped_in_subselect_item(); + if (to_find->type() != Item::SUBSELECT_ITEM || ((Item_subselect *) to_find)->substype() != Item_subselect::IN_SUBS) return; diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index b2b13c5467b..9f8a3450716 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -229,6 +229,14 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id, entry->stop_on_error_sub_id= sub_id; mysql_mutex_unlock(&entry->LOCK_parallel_entry); + DBUG_EXECUTE_IF("rpl_parallel_simulate_wait_at_retry", { + if (rgi->current_gtid.seq_no == 1000) { + DBUG_ASSERT(entry->stop_on_error_sub_id == sub_id); + debug_sync_set_action(thd, + STRING_WITH_LEN("now WAIT_FOR proceed_by_1000")); + } + }); + if (rgi->killed_for_retry == rpl_group_info::RETRY_KILL_PENDING) wait_for_pending_deadlock_kill(thd, rgi); thd->clear_error(); @@ -722,6 +730,14 @@ do_retry: rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; thd->set_killed(KILL_CONNECTION); }); + DBUG_EXECUTE_IF("rpl_parallel_simulate_wait_at_retry", { + if (rgi->current_gtid.seq_no == 1001) { + debug_sync_set_action(thd, + STRING_WITH_LEN("rpl_parallel_simulate_wait_at_retry WAIT_FOR proceed_by_1001")); + } + DEBUG_SYNC(thd, "rpl_parallel_simulate_wait_at_retry"); + }); + rgi->cleanup_context(thd, 1); wait_for_pending_deadlock_kill(thd, rgi); thd->reset_killed(); @@ -745,7 +761,26 @@ do_retry: for (;;) { mysql_mutex_lock(&entry->LOCK_parallel_entry); - register_wait_for_prior_event_group_commit(rgi, entry); + if (entry->stop_on_error_sub_id == (uint64) ULONGLONG_MAX || +#ifndef DBUG_OFF + (DBUG_EVALUATE_IF("simulate_mdev_12746", 1, 0)) || +#endif + rgi->gtid_sub_id < entry->stop_on_error_sub_id) + { + register_wait_for_prior_event_group_commit(rgi, entry); + } + else + { + /* + A failure of a preceeding "parent" transaction may not be + seen by the current one through its own worker_error. + Such induced error gets set by ourselves now. + */ + err= rgi->worker_error= 1; + my_error(ER_PRIOR_COMMIT_FAILED, MYF(0)); + mysql_mutex_unlock(&entry->LOCK_parallel_entry); + goto err; + } mysql_mutex_unlock(&entry->LOCK_parallel_entry); /* diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index c725bf39eb0..c55c1c4187c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -1807,7 +1807,7 @@ ER_NORMAL_SHUTDOWN cze "%s (%s): normální ukončení" dan "%s (%s): Normal nedlukning" nla "%s (%s): Normaal afgesloten " - eng "%s (%s): Normal shutdown" + eng "%s (initiated by: %s): Normal shutdown" est "%s (%s): MariaDB lõpetas" fre "%s (%s): Arrêt normal du serveur" ger "%s (%s): Normal heruntergefahren" @@ -1822,7 +1822,7 @@ ER_NORMAL_SHUTDOWN pol "%s (%s): Standardowe zakończenie działania" por "%s (%s): 'Shutdown' normal" rum "%s (%s): Terminare normala" - rus "%s (%s): Корректная остановка" + rus "%s (инициирована пользователем: %s): Корректная остановка" serbian "%s (%s): Normalno gašenje" slo "%s (%s): normálne ukončenie" spa "%s (%s): Apagado normal" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b3b2c8233bf..9e6eb1fc0e2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2898,15 +2898,19 @@ Item_change_list::check_and_register_item_tree_change(Item **place, void Item_change_list::rollback_item_tree_changes() { + DBUG_ENTER("THD::rollback_item_tree_changes"); I_List_iterator<Item_change_record> it(change_list); Item_change_record *change; while ((change= it++)) { + DBUG_PRINT("info", ("Rollback: %p (%p) <- %p", + *change->place, change->place, change->old_value)); *change->place= change->old_value; } /* We can forget about changes memory: it's allocated in runtime memroot */ change_list.empty(); + DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 79370510e67..61d80003046 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6114,11 +6114,15 @@ public: sent by the user (ie: stored procedure). */ #define CF_SKIP_QUESTIONS (1U << 1) - +#ifdef WITH_WSREP /** Do not check that wsrep snapshot is ready before allowing this command */ #define CF_SKIP_WSREP_CHECK (1U << 2) +#else +#define CF_SKIP_WSREP_CHECK 0 +#endif /* WITH_WSREP */ + /** Do not allow it for COM_MULTI batch */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f5fe955375d..b89d78874f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB + Copyright (c) 2008, 2018, MariaDB 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 @@ -501,6 +501,7 @@ void init_update_queries(void) server_command_flags[COM_SHUTDOWN]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_SLEEP]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_TIME]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_INIT_DB]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_END]= CF_SKIP_WSREP_CHECK; for (uint i= COM_MDB_GAP_BEG; i <= COM_MDB_GAP_END; i++) { @@ -514,6 +515,8 @@ void init_update_queries(void) server_command_flags[COM_QUERY]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_SET_OPTION]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; + server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_STMT_FETCH]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK; @@ -1168,21 +1171,21 @@ static enum enum_server_command fetch_command(THD *thd, char *packet) } -#ifndef EMBEDDED_LIBRARY - #ifdef WITH_WSREP -static bool wsrep_node_is_ready(THD *thd) +static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables) { - if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready) + for (const TABLE_LIST *table= tables; table; table= table->next_global) { - my_message(ER_UNKNOWN_COM_ERROR, - "WSREP has not yet prepared node for application use", - MYF(0)); - return false; + TABLE_CATEGORY c; + LEX_CSTRING db= table->db, tn= table->table_name; + c= get_table_category(&db, &tn); + if (c != TABLE_CATEGORY_INFORMATION && c != TABLE_CATEGORY_PERFORMANCE) + return false; } return true; } -#endif +#endif /* WITH_WSREP */ +#ifndef EMBEDDED_LIBRARY /** Read one command from connection and execute it (query or simple command). @@ -1359,8 +1362,9 @@ bool do_command(THD *thd) /* Bail out if DB snapshot has not been installed. */ - if (!(server_command_flags[command] & CF_SKIP_WSREP_CHECK) && - !wsrep_node_is_ready(thd)) + if (thd->variables.wsrep_on && !thd->wsrep_applier && + (!wsrep_ready || wsrep_reject_queries != WSREP_REJECT_NONE) && + (server_command_flags[command] & CF_SKIP_WSREP_CHECK) == 0) { thd->protocol->end_statement(); @@ -3437,20 +3441,23 @@ mysql_execute_command(THD *thd) } /* - Bail out if DB snapshot has not been installed. SET and SHOW commands, - however, are always allowed. - Select query is also allowed if it does not access any table. - We additionally allow all other commands that do not change data in - case wsrep_dirty_reads is enabled. - */ - if (lex->sql_command != SQLCOM_SET_OPTION && - !wsrep_is_show_query(lex->sql_command) && - !(thd->variables.wsrep_dirty_reads && - !is_update_query(lex->sql_command)) && - !(lex->sql_command == SQLCOM_SELECT && - !all_tables) && - !wsrep_node_is_ready(thd)) + * Bail out if DB snapshot has not been installed. We however, + * allow SET and SHOW queries and reads from information schema + * and dirty reads (if configured) + */ + if (thd->variables.wsrep_on && + !thd->wsrep_applier && + !(wsrep_ready && wsrep_reject_queries == WSREP_REJECT_NONE) && + !(thd->variables.wsrep_dirty_reads && + (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) == 0) && + !wsrep_tables_accessible_when_detached(all_tables) && + lex->sql_command != SQLCOM_SET_OPTION && + !wsrep_is_show_query(lex->sql_command)) + { + my_message(ER_UNKNOWN_COM_ERROR, + "WSREP has not yet prepared node for application use", MYF(0)); goto error; + } } #endif /* WITH_WSREP */ status_var_increment(thd->status_var.com_stat[lex->sql_command]); @@ -6059,9 +6066,6 @@ end_with_restore_list: sp_head *sp; const Sp_handler *sph= Sp_handler::handler(lex->sql_command); WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); -#ifdef WITH_WSREP - if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error; -#endif /* WITH_WSREP */ if (sph->sp_resolve_package_routine(thd, thd->lex->sphead, lex->spname, &sph, &pkgname)) return true; @@ -7840,7 +7844,6 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, thd->wsrep_conflict_state == CERT_FAILURE) { thd->reset_for_next_command(); - thd->reset_killed(); if (is_autocommit && thd->lex->sql_command != SQLCOM_SELECT && (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)) @@ -7870,17 +7873,18 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, thd->variables.wsrep_retry_autocommit, thd->query()); my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction", MYF(0)); - thd->reset_killed(); thd->wsrep_conflict_state= NO_CONFLICT; if (thd->wsrep_conflict_state != REPLAYING) thd->wsrep_retry_counter= 0; // reset } + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + thd->reset_killed(); } else { set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } - mysql_mutex_unlock(&thd->LOCK_wsrep_thd); } /* If retry is requested clean up explain structure */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 22b8640d9ee..24f3cc66c6b 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4623,6 +4623,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) Statement stmt_backup; Query_arena *old_stmt_arena; bool error= TRUE; + bool qc_executed= FALSE; char saved_cur_db_name_buf[SAFE_NAME_LEN+1]; LEX_STRING saved_cur_db_name= @@ -4745,6 +4746,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) thd->lex->sql_command= SQLCOM_SELECT; status_var_increment(thd->status_var.com_stat[SQLCOM_SELECT]); thd->update_stats(); + qc_executed= TRUE; } } @@ -4783,7 +4785,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) thd->set_statement(&stmt_backup); thd->stmt_arena= old_stmt_arena; - if (state == Query_arena::STMT_PREPARED) + if (state == Query_arena::STMT_PREPARED && !qc_executed) state= Query_arena::STMT_EXECUTED; if (error == 0 && this->lex->sql_command == SQLCOM_CALL) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 545f8111237..a64b8cbf18a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3836,6 +3836,13 @@ extern ST_SCHEMA_TABLE schema_tables[]; bool schema_table_store_record(THD *thd, TABLE *table) { int error; + + if (thd->killed) + { + thd->send_kill_message(); + return 1; + } + if ((error= table->file->ha_write_tmp_row(table->record[0]))) { TMP_TABLE_PARAM *param= table->pos_in_table_list->schema_table_param; diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 02731914d52..c748cd54415 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -1033,6 +1033,8 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, ltime->day= 0; return 0; } + else if (ltime->neg) + goto invalid_date; if (int_type != INTERVAL_DAY) ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 857c9a117f5..0149c2848c2 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -976,7 +976,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, */ if (sl == first_sl) { - if (is_recursive) + if (with_element) { if (derived->with->rename_columns_of_derived_unit(thd, this)) goto err; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index c144eb593a0..524ce974681 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2012, 2017, MariaDB Corporation. + Copyright (c) 2012, 2018, MariaDB Corporation. 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 @@ -5416,6 +5416,14 @@ static Sys_var_mybool Sys_wsrep_desync ( ON_CHECK(wsrep_desync_check), ON_UPDATE(wsrep_desync_update)); +static const char *wsrep_reject_queries_names[]= { "NONE", "ALL", "ALL_KILL", NullS }; +static Sys_var_enum Sys_wsrep_reject_queries( + "wsrep_reject_queries", "Variable to set to reject queries", + GLOBAL_VAR(wsrep_reject_queries), CMD_LINE(OPT_ARG), + wsrep_reject_queries_names, DEFAULT(WSREP_REJECT_NONE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_reject_queries_update)); + static const char *wsrep_binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; static Sys_var_enum Sys_wsrep_forced_binlog_format( diff --git a/sql/tztime.cc b/sql/tztime.cc index f7e2dcbefb8..277709ad9e9 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2677,9 +2677,7 @@ main(int argc, char **argv) char **default_argv; MY_INIT(argv[0]); - if (load_defaults("my",load_default_groups,&argc,&argv)) - exit(1); - + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; if ((handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc index bf4ce7c9d90..0b7a9ca6252 100644 --- a/sql/wsrep_check_opts.cc +++ b/sql/wsrep_check_opts.cc @@ -50,7 +50,7 @@ int wsrep_check_opts() (!strcasecmp(my_bind_addr_str, "127.0.0.1") || !strcasecmp(my_bind_addr_str, "localhost"))) { - WSREP_ERROR("wsrep_sst_method is set to 'mysqldump' yet " + WSREP_WARN("wsrep_sst_method is set to 'mysqldump' yet " "mysqld bind_address is set to '%s', which makes it " "impossible to receive state transfer from another " "node, since mysqld won't accept such connections. " @@ -58,7 +58,6 @@ int wsrep_check_opts() "set bind_address to allow mysql client connections " "from other cluster members (e.g. 0.0.0.0).", my_bind_addr_str); - return 1; } } else diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 91a77c65604..def52cb2675 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -394,7 +394,7 @@ wsrep_view_handler_cb (void* app_ctx, if (!wsrep_before_SE()) { WSREP_DEBUG("[debug]: closing client connections for PRIM"); - wsrep_close_client_connections(TRUE); + wsrep_close_client_connections(FALSE); } ssize_t const req_len= wsrep_sst_prepare (sst_req); @@ -2373,7 +2373,7 @@ extern "C" void wsrep_thd_set_query_state( void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state) { - thd->wsrep_conflict_state= state; + if (WSREP(thd)) thd->wsrep_conflict_state= state; } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 2cb35db01b7..c6b1f42ce14 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -80,6 +80,7 @@ extern const char* wsrep_notify_cmd; extern long wsrep_max_protocol_version; extern ulong wsrep_forced_binlog_format; extern my_bool wsrep_desync; +extern ulong wsrep_reject_queries; extern my_bool wsrep_replicate_myisam; extern ulong wsrep_mysql_replication_bundle; extern my_bool wsrep_restart_slave; @@ -91,6 +92,12 @@ extern bool wsrep_new_cluster; extern bool wsrep_gtid_mode; extern uint32 wsrep_gtid_domain_id; +enum enum_wsrep_reject_types { + WSREP_REJECT_NONE, /* nothing rejected */ + WSREP_REJECT_ALL, /* reject all queries, with UNKNOWN_COMMAND error */ + WSREP_REJECT_ALL_KILL /* kill existing connections and reject all queries*/ +}; + enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU, diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 41044085625..d19bcafb8d6 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -78,37 +78,14 @@ static void make_wsrep_defaults_file() } -// TODO: Improve address verification. -static bool sst_receive_address_check (const char* str) -{ - if (!strncasecmp(str, "127.0.0.1", strlen("127.0.0.1")) || - !strncasecmp(str, "localhost", strlen("localhost"))) - { - return 1; - } - - return 0; -} - bool wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var) { - char addr_buf[FN_REFLEN]; - if ((! var->save_result.string_value.str) || (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety { goto err; } - memcpy(addr_buf, var->save_result.string_value.str, - var->save_result.string_value.length); - addr_buf[var->save_result.string_value.length]= 0; - - if (sst_receive_address_check(addr_buf)) - { - goto err; - } - return 0; err: diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index ffa969a811c..d94ac240b76 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -26,6 +26,7 @@ #include <cstdio> #include <cstdlib> +ulong wsrep_reject_queries; static long wsrep_prev_slave_threads = wsrep_slave_threads; @@ -413,6 +414,27 @@ void wsrep_provider_options_init(const char* value) wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL; } +bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type) +{ + switch (wsrep_reject_queries) { + case WSREP_REJECT_NONE: + WSREP_INFO("Allowing client queries due to manual setting"); + break; + case WSREP_REJECT_ALL: + WSREP_INFO("Rejecting client queries due to manual setting"); + break; + case WSREP_REJECT_ALL_KILL: + wsrep_close_client_connections(FALSE); + WSREP_INFO("Rejecting client queries and killing connections due to manual setting"); + break; + default: + WSREP_INFO("Unknown value for wsrep_reject_queries: %lu", + wsrep_reject_queries); + return true; + } + return false; +} + static int wsrep_cluster_address_verify (const char* cluster_address_str) { /* There is no predefined address format, it depends on provider. */ diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index b9051b29843..7d3ff50f1d2 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -92,6 +92,7 @@ extern bool wsrep_desync_update UPDATE_ARGS; extern bool wsrep_max_ws_size_check CHECK_ARGS; extern bool wsrep_max_ws_size_update UPDATE_ARGS; +extern bool wsrep_reject_queries_update UPDATE_ARGS; #else /* WITH_WSREP */ diff --git a/storage/archive/archive_reader.c b/storage/archive/archive_reader.c index 1b15fa16ce4..e87bc70ade4 100644 --- a/storage/archive/archive_reader.c +++ b/storage/archive/archive_reader.c @@ -408,8 +408,7 @@ static void print_version(void) static void get_options(int *argc, char ***argv) { - if (load_defaults("my", load_default_groups, argc, argv)) - exit(1); + load_defaults_or_exit("my", load_default_groups, argc, argv); default_argv= *argv; handle_options(argc, argv, my_long_options, get_one_option); diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 33b0477842d..782d1f44bdf 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -330,18 +330,14 @@ IF(NOT TARGET connect) RETURN() ENDIF() - -IF(MSVC) - # Temporarily disable "conversion from size_t .." - IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") - ENDIF() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") - string(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -ENDIF() +IF(WIN32) + IF (libmongoc-1.0_FOUND) + SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS + "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll") + ENDIF(libmongoc-1.0_FOUND) # Install some extra files that belong to connect engine -IF(WIN32) + # install ha_connect.lib GET_TARGET_PROPERTY(CONNECT_LOCATION connect LOCATION) STRING(REPLACE "dll" "lib" CONNECT_LIB ${CONNECT_LOCATION}) @@ -353,22 +349,14 @@ IF(WIN32) DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) ENDIF(WIN32) -IF(NOT TARGET connect) - RETURN() -ENDIF() - -# Install some extra files that belong to connect engine -IF(WIN32) - # install ha_connect.lib - GET_TARGET_PROPERTY(CONNECT_LOCATION connect LOCATION) - STRING(REPLACE "dll" "lib" CONNECT_LIB ${CONNECT_LOCATION}) - IF(CMAKE_CONFIGURATION_TYPES) - STRING(REPLACE "${CMAKE_CFG_INTDIR}" "\${CMAKE_INSTALL_CONFIG_NAME}" - CONNECT_LIB ${CONNECT_LIB}) +IF(MSVC) + # Temporarily disable "conversion from size_t .." + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") ENDIF() - INSTALL(FILES ${CONNECT_LIB} - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) -ENDIF(WIN32) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + string(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +ENDIF() IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) # TODO: Find how to compile and install the java wrapper classes diff --git a/storage/connect/Client.java b/storage/connect/Client.java index aaf1b7bf2f8..afa54fa4256 100644 --- a/storage/connect/Client.java +++ b/storage/connect/Client.java @@ -1,9 +1,13 @@ + package wrappers; import java.io.BufferedReader; import java.io.Console; import java.io.IOException; import java.io.InputStreamReader; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; public class Client { static boolean DEBUG = true; @@ -58,6 +62,9 @@ public class Client { String query; System.out.println("Successfully connected to " + parms[1]); + s = jdi.GetQuoteString(); + System.out.println("Qstr = '" + s + "'"); + while ((query = getLine("Query: ", false)) != null) { n = jdi.Execute(query); System.out.println("Returned n = " + n); @@ -79,7 +86,11 @@ public class Client { private static void PrintResult(int ncol) { // Get result set meta data int i; + Date date = new Date(0); + Time time = new Time(0); + Timestamp tsp = new Timestamp(0); String columnName; + Object job; // Get the column names; column indices start from 1 for (i = 1; i <= ncol; i++) { @@ -112,6 +123,7 @@ public class Client { case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.CHAR: + case 1111: System.out.print(jdi.StringField(i, null)); break; case java.sql.Types.INTEGER: @@ -120,14 +132,17 @@ public class Client { case java.sql.Types.BIGINT: System.out.print(jdi.BigintField(i, null)); break; - case java.sql.Types.TIMESTAMP: - System.out.print(jdi.TimestampField(i, null)); - break; case java.sql.Types.TIME: - System.out.print(jdi.TimeField(i, null)); + time.setTime((long)jdi.TimeField(i, null) * 1000); + System.out.print(time); break; case java.sql.Types.DATE: - System.out.print(jdi.DateField(i, null)); + date.setTime((long)jdi.DateField(i, null) * 1000); + System.out.print(date); + break; + case java.sql.Types.TIMESTAMP: + tsp.setTime((long)jdi.TimestampField(i, null) * 1000); + System.out.print(tsp); break; case java.sql.Types.SMALLINT: System.out.print(jdi.IntField(i, null)); @@ -141,6 +156,8 @@ public class Client { case java.sql.Types.BOOLEAN: System.out.print(jdi.BooleanField(i, null)); default: + job = jdi.ObjectField(i, null); + System.out.print(job.toString()); break; } // endswitch Type diff --git a/storage/connect/JavaWrappers.jar b/storage/connect/JavaWrappers.jar Binary files differindex ef407f6a9c2..33b29e7685b 100644 --- a/storage/connect/JavaWrappers.jar +++ b/storage/connect/JavaWrappers.jar diff --git a/storage/connect/JdbcInterface.java b/storage/connect/JdbcInterface.java index a1b1360e6ea..72ee4ab0d39 100644 --- a/storage/connect/JdbcInterface.java +++ b/storage/connect/JdbcInterface.java @@ -1,10 +1,22 @@ package wrappers; -import java.math.*; -import java.sql.*; +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Date; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; import java.util.Collections; import java.util.Hashtable; import java.util.List; +import java.util.UUID; import javax.sql.DataSource; @@ -223,6 +235,24 @@ public class JdbcInterface { } // end of SetTimestampParm + public void SetUuidParm(int i, String s) { + try { + UUID uuid; + + if (s == null) + uuid = null; + else if (s.isEmpty()) + uuid = UUID.randomUUID(); + else + uuid = UUID.fromString(s); + + pstmt.setObject(i, uuid); + } catch (Exception e) { + SetErrmsg(e); + } // end try/catch + + } // end of SetUuidParm + public int SetNullParm(int i, int typ) { int rc = 0; @@ -481,6 +511,8 @@ public class JdbcInterface { System.out.println("Executing query '" + query + "'"); try { + if (rs != null) + rs.close(); rs = stmt.executeQuery(query); rsmd = rs.getMetaData(); ncol = rsmd.getColumnCount(); @@ -708,7 +740,7 @@ public class JdbcInterface { return 0; } // end of TimestampField - public Object ObjectField(int n, String name) { + public Object ObjectField(int n, String name) { if (rs == null) { System.out.println("No result set"); } else try { @@ -720,6 +752,22 @@ public class JdbcInterface { return null; } // end of ObjectField + public String UuidField(int n, String name) { + Object job; + + if (rs == null) { + System.out.println("No result set"); + } else + try { + job = (n > 0) ? rs.getObject(n) : rs.getObject(name); + return job.toString(); + } catch (SQLException se) { + SetErrmsg(se); + } // end try/catch + + return null; + } // end of UuidField + public int GetDrivers(String[] s, int mxs) { int n = 0; List<Driver> drivers = Collections.list(DriverManager.getDrivers()); diff --git a/storage/connect/PostgresqlInterface.java b/storage/connect/PostgresqlInterface.java index adce0616a1b..9f611eeb23b 100644 --- a/storage/connect/PostgresqlInterface.java +++ b/storage/connect/PostgresqlInterface.java @@ -1,9 +1,10 @@ package wrappers; -import java.sql.*; +import java.sql.SQLException; import java.util.Hashtable; import javax.sql.DataSource; + import org.postgresql.jdbc2.optional.PoolingDataSource; public class PostgresqlInterface extends JdbcInterface { @@ -19,7 +20,7 @@ public class PostgresqlInterface extends JdbcInterface { } // end of constructor - @Override + @Override public int JdbcConnect(String[] parms, int fsize, boolean scrollable) { int rc = 0; String url = parms[1]; diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp index 59a53487a7e..cd1785b48ac 100644 --- a/storage/connect/array.cpp +++ b/storage/connect/array.cpp @@ -82,7 +82,7 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp) if ((valtyp = pp->Type) != TYPE_STRING) len = 1; - if (trace) + if (trace(1)) htrc("valtyp=%d len=%d\n", valtyp, len); /*********************************************************************/ @@ -287,7 +287,7 @@ bool ARRAY::AddValue(PGLOBAL g, PSZ strp) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding string(%d): '%s'\n", Nval, strp); //Value->SetValue_psz(strp); @@ -306,7 +306,7 @@ bool ARRAY::AddValue(PGLOBAL g, void *p) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding pointer(%d): %p\n", Nval, p); Vblp->SetValue((PSZ)p, Nval++); @@ -323,7 +323,7 @@ bool ARRAY::AddValue(PGLOBAL g, short n) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding SHORT(%d): %hd\n", Nval, n); //Value->SetValue(n); @@ -342,7 +342,7 @@ bool ARRAY::AddValue(PGLOBAL g, int n) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding int(%d): %d\n", Nval, n); //Value->SetValue(n); @@ -361,7 +361,7 @@ bool ARRAY::AddValue(PGLOBAL g, double d) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding float(%d): %lf\n", Nval, d); Value->SetValue(d); @@ -380,7 +380,7 @@ bool ARRAY::AddValue(PGLOBAL g, PXOB xp) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding (%d) from xp=%p\n", Nval, xp); //AddValue(xp->GetValue()); @@ -399,7 +399,7 @@ bool ARRAY::AddValue(PGLOBAL g, PVAL vp) return true; } // endif Type - if (trace) + if (trace(1)) htrc(" adding (%d) from vp=%p\n", Nval, vp); Vblp->SetValue(vp, Nval++); @@ -990,7 +990,7 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g) len += strlen(tp); } // enfor i - if (trace) + if (trace(1)) htrc("Arraylist: len=%d\n", len); p = (char *)PlugSubAlloc(g, NULL, len); @@ -1003,7 +1003,7 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g) strcat(p, (++i == Nval) ? ")" : ","); } // enfor i - if (trace) + if (trace(1)) htrc("Arraylist: newlen=%d\n", strlen(p)); return p; diff --git a/storage/connect/blkfil.cpp b/storage/connect/blkfil.cpp index 802095f2f82..76c9d09ac93 100644 --- a/storage/connect/blkfil.cpp +++ b/storage/connect/blkfil.cpp @@ -241,7 +241,7 @@ int BLKFILARI::BlockEval(PGLOBAL) break; } // endswitch Opc - if (trace) + if (trace(1)) htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result); return Result; @@ -338,7 +338,7 @@ int BLKFILAR2::BlockEval(PGLOBAL) break; } // endswitch Opc - if (trace) + if (trace(1)) htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result); return Result; @@ -474,7 +474,7 @@ int BLKFILMR2::BlockEval(PGLOBAL) break; } // endswitch Opc - if (trace) + if (trace(1)) htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result); return Result; @@ -567,7 +567,7 @@ int BLKSPCARI::BlockEval(PGLOBAL) break; } // endswitch Opc - if (trace) + if (trace(1)) htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result); return Result; diff --git a/storage/connect/block.h b/storage/connect/block.h index 8ac7be80988..737c74c1293 100644 --- a/storage/connect/block.h +++ b/storage/connect/block.h @@ -38,8 +38,8 @@ typedef class BLOCK *PBLOCK; class DllExport BLOCK { public: void * operator new(size_t size, PGLOBAL g, void *p = NULL) { -// if (trace > 3) -// htrc("New BLOCK: size=%d g=%p p=%p\n", size, g, p); + if (trace(256)) + htrc("New BLOCK: size=%d g=%p p=%p\n", size, g, p); return (PlugSubAlloc(g, p, size)); } // end of new diff --git a/storage/connect/checklvl.h b/storage/connect/checklvl.h index 0c234dfb8b8..9029e616bb6 100644 --- a/storage/connect/checklvl.h +++ b/storage/connect/checklvl.h @@ -45,6 +45,7 @@ enum USETEMP {TMP_NO = 0, /* Never */ /***********************************************************************/ enum TYPCONV {TPC_NO = 0, /* Never */ TPC_YES = 1, /* Always */ - TPC_SKIP = 2}; /* Skip TEXT columns */ + TPC_FORCE = 2, /* Also convert BLOBs */ + TPC_SKIP = 3}; /* Skip TEXT columns */ #endif // _CHKLVL_DEFINED_ diff --git a/storage/connect/cmgoconn.cpp b/storage/connect/cmgoconn.cpp index 44fac56137f..edee1874b97 100644 --- a/storage/connect/cmgoconn.cpp +++ b/storage/connect/cmgoconn.cpp @@ -280,7 +280,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) all = true; if (Pcg->Pipe) { - if (trace) + if (trace(1)) htrc("Pipeline: %s\n", options); p = strrchr(options, ']'); @@ -330,7 +330,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) *(char*)p = ']'; // Restore Colist for discovery p = s->GetStr(); - if (trace) + if (trace(33)) htrc("New Pipeline: %s\n", p); Query = bson_new_from_json((const uint8_t *)p, -1, &Error); @@ -350,7 +350,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) } else { if (Pcg->Filter || filp) { - if (trace) { + if (trace(1)) { if (Pcg->Filter) htrc("Filter: %s\n", Pcg->Filter); @@ -377,7 +377,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) tp->SetFilter(NULL); // Not needed anymore } // endif To_Filter - if (trace) + if (trace(33)) htrc("selector: %s\n", s->GetStr()); s->Resize(s->GetLength() + 1); @@ -393,7 +393,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) if (!all) { if (options && *options) { - if (trace) + if (trace(1)) htrc("options=%s\n", options); p = options; @@ -450,10 +450,10 @@ int CMgoConn::ReadNext(PGLOBAL g) if (!Cursor && MakeCursor(g)) { rc = RC_FX; } else if (mongoc_cursor_next(Cursor, &Document)) { - if (trace > 1) { + if (trace(512)) { bson_iter_t iter; ShowDocument(&iter, Document, ""); - } else if (trace == 1) + } else if (trace(1)) htrc("%s\n", GetDocument(g)); } else if (mongoc_cursor_error(Cursor, &Error)) { @@ -589,7 +589,7 @@ int CMgoConn::Write(PGLOBAL g) if (DocWrite(g, Fpc)) return RC_FX; - if (trace) { + if (trace(2)) { char *str = bson_as_json(Fpc->Child, NULL); htrc("Inserting: %s\n", str); bson_free(str); @@ -623,7 +623,7 @@ int CMgoConn::Write(PGLOBAL g) } // endif iter if (b) { - if (trace) { + if (trace(2)) { char *str = bson_as_json(query, NULL); htrc("update query: %s\n", str); bson_free(str); diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp index 5cd6a4f2be4..a9cf43f3d96 100644 --- a/storage/connect/colblk.cpp +++ b/storage/connect/colblk.cpp @@ -76,7 +76,7 @@ COLBLK::COLBLK(PCOL col1, PTDB tdbp) //To_Orig = col1; To_Tdb = tdbp; - if (trace > 1) + if (trace(2)) htrc(" copying COLBLK %s from %p to %p\n", Name, col1, this); if (tdbp) @@ -115,7 +115,7 @@ bool COLBLK::SetFormat(PGLOBAL, FORMAT& fmt) { fmt = Format; - if (trace > 1) + if (trace(2)) htrc("COLBLK: %p format=%c(%d,%d)\n", this, *fmt.Type, fmt.Length, fmt.Prec); @@ -128,7 +128,7 @@ bool COLBLK::SetFormat(PGLOBAL, FORMAT& fmt) /***********************************************************************/ bool COLBLK::Eval(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("Col Eval: %s status=%.4X\n", Name, Status); if (!GetStatus(BUF_READ)) { @@ -165,7 +165,7 @@ bool COLBLK::InitValue(PGLOBAL g) AddStatus(BUF_READY); Value->SetNullable(Nullable); - if (trace > 1) + if (trace(2)) htrc(" colp=%p type=%d value=%p coluse=%.4X status=%.4X\n", this, Buf_Type, Value, ColUse, Status); diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 1d3b3a456d5..f9bcffd4fdc 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -93,7 +93,7 @@ void CntEndDB(PGLOBAL g) free(dbuserp); - if (trace) + if (trace(1)) htrc("CntEndDB: Freeing Dup\n"); g->Activityp->Aptr = NULL; @@ -113,14 +113,14 @@ bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname) bool rc= false; PDBUSER dbuserp= PlgGetUser(g); - if (trace) { + if (trace(1)) { printf("CntCheckDB: dbuserp=%p\n", dbuserp); } // endif trace if (!dbuserp || !handler) return true; - if (trace) + if (trace(1)) printf("cat=%p oldhandler=%p newhandler=%p\n", dbuserp->Catalog, (dbuserp->Catalog) ? ((MYCAT*)dbuserp->Catalog)->GetHandler() : NULL, handler); @@ -151,7 +151,7 @@ bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname) /*********************************************************************/ sprintf(g->Message, MSG(DATABASE_LOADED), "???"); - if (trace) + if (trace(1)) printf("msg=%s\n", g->Message); return rc; @@ -199,7 +199,7 @@ PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) PDBUSER dup = PlgGetUser(g); volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over throw - if (trace) + if (trace(1)) printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat); if (!cat) @@ -209,7 +209,7 @@ PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) // Get table object from the catalog tabp = new(g) XTAB(name); - if (trace) + if (trace(1)) printf("CntGetTDB: tabp=%p\n", tabp); // Perhaps this should be made thread safe @@ -219,13 +219,13 @@ PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) printf("CntGetTDB: %s\n", g->Message); } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); } catch (const char *msg) { strcpy(g->Message, msg); } // end catch - if (trace) + if (trace(1)) printf("Returning tdbp=%p mode=%d\n", tdbp, mode); return tdbp; @@ -244,7 +244,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, //PCOLUMN cp; PDBUSER dup= PlgGetUser(g); - if (trace) + if (trace(1)) printf("CntOpenTable: tdbp=%p mode=%d\n", tdbp, mode); if (!tdbp) { @@ -261,7 +261,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, } else for (p = c1; *p; p += n) { // Allocate only used column blocks - if (trace) + if (trace(1)) printf("Allocating column %s\n", p); g->Message[0] = 0; // To check whether ColDB made an error message @@ -326,7 +326,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, tdbp->SetSetCols(tdbp->GetColumns()); // Now do open the physical table - if (trace) + if (trace(1)) printf("Opening table %s in mode %d tdbp=%p\n", tdbp->GetName(), mode, tdbp); @@ -342,7 +342,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, } // endif del - if (trace) + if (trace(1)) printf("About to open the table: tdbp=%p\n", tdbp); if (mode != MODE_ANY && mode != MODE_ALTER) { @@ -357,7 +357,7 @@ bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, rcop = false; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); } catch (const char *msg) { strcpy(g->Message, msg); @@ -400,12 +400,13 @@ RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool reset, bool mrr) } // endfor colp } catch (int n) { - if (trace) + if (trace(1)) printf("Error %d reading columns: %s\n", n, g->Message); rc = RC_FX; } catch (const char *msg) { strcpy(g->Message, msg); + rc = RC_NF; } // end catch return rc; @@ -550,7 +551,7 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort) return rc; } // endif !USE_OPEN - if (trace) + if (trace(1)) printf("CntCloseTable: tdbp=%p mode=%d nox=%d abort=%d\n", tdbp, tdbp->GetMode(), nox, abort); @@ -580,11 +581,11 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort) tdbp->CloseDB(g); tdbp->SetAbort(false); - if (trace > 1) + if (trace(2)) printf("Table %s closed\n", tdbp->GetName()); if (!nox && tdbp->GetMode() != MODE_READ && tdbp->GetMode() != MODE_ANY) { - if (trace > 1) + if (trace(2)) printf("About to reset opt\n"); if (!tdbp->IsRemote()) { @@ -604,7 +605,7 @@ int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort) rc = RC_FX; } // end catch - if (trace > 1) + if (trace(2)) htrc("Done rc=%d\n", rc); return (rc == RC_OK || rc == RC_INFO) ? 0 : rc; @@ -923,7 +924,7 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, valp->SetBinValue((void*)p); #endif // !WORDS_BIGENDIAN - if (trace) { + if (trace(1)) { char bf[32]; printf("i=%d n=%d key=%s\n", i, n, valp->GetCharString(bf)); } // endif trace @@ -945,7 +946,7 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, xbp->SetNval(n); - if (trace) + if (trace(1)) printf("xbp=%p Nval=%d i=%d incl=%d\n", xbp, n, i, incl[i]); k[i]= xbp->Range(g, i + 1, incl[i]); @@ -954,7 +955,7 @@ int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, } // endfor i - if (trace) + if (trace(1)) printf("k1=%d k0=%d\n", k[1], k[0]); return k[1] - k[0]; diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 67481136d81..6e71e1bf2cd 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -90,7 +90,7 @@ int MAPFAM::GetFileLength(PGLOBAL g) len = (To_Fb && To_Fb->Count) ? To_Fb->Length : TXTFAM::GetFileLength(g); - if (trace) + if (trace(1)) htrc("Mapped file length=%d\n", len); return len; @@ -128,7 +128,7 @@ bool MAPFAM::OpenTableFile(PGLOBAL g) && fp->Count && fp->Mode == mode) break; - if (trace) + if (trace(1)) htrc("Mapping file, fp=%p\n", fp); } else @@ -166,7 +166,7 @@ bool MAPFAM::OpenTableFile(PGLOBAL g) sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int) rc, filename); - if (trace) + if (trace(1)) htrc("CreateFileMap: %s\n", g->Message); return (mode == MODE_READ && rc == ENOENT) @@ -227,7 +227,7 @@ bool MAPFAM::OpenTableFile(PGLOBAL g) Fpos = Mempos = Memory; Top = Memory + len; - if (trace) + if (trace(1)) htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n", fp, fp->Count, Memory, len, Top); @@ -407,7 +407,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) { int n; - if (trace) + if (trace(1)) htrc("MAP DeleteDB: irc=%d mempos=%p tobuf=%p Tpos=%p Spos=%p\n", irc, Mempos, To_Buf, Tpos, Spos); @@ -417,7 +417,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = Top; - if (trace) + if (trace(1)) htrc("Fpos placed at file top=%p\n", Fpos); } // endif irc @@ -435,7 +435,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) memmove(Tpos, Spos, n); Tpos += n; - if (trace) + if (trace(1)) htrc("move %d bytes\n", n); } // endif n @@ -443,7 +443,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) if (irc == RC_OK) { Spos = Mempos; // New start position - if (trace) + if (trace(1)) htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); } else if (To_Fb) { // Can be NULL for deleted files @@ -473,7 +473,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) return RC_FX; } // endif - if (trace) + if (trace(1)) htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc); if (!SetEndOfFile(fp->Handle)) { @@ -511,7 +511,7 @@ void MAPFAM::CloseTableFile(PGLOBAL g, bool) PlugCloseFile(g, To_Fb); //To_Fb = NULL; // To get correct file size in Cardinality - if (trace) + if (trace(1)) htrc("MAP Close: closing %s count=%d\n", To_File, (To_Fb) ? To_Fb->Count : 0); diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp index 44abd962c56..893e3da0d46 100644 --- a/storage/connect/filamdbf.cpp +++ b/storage/connect/filamdbf.cpp @@ -203,7 +203,7 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) PQRYRES qrp; PCOLRES crp; - if (trace) + if (trace(1)) htrc("DBFColumns: File %s\n", SVP(fn)); if (!info) { @@ -245,7 +245,7 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) return qrp; } // endif info - if (trace) { + if (trace(1)) { htrc("Structure of %s\n", filename); htrc("headlen=%hd reclen=%hd degree=%d\n", mainhead.Headlen(), mainhead.Reclen(), fields); @@ -271,7 +271,7 @@ PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, bool info) } else len = thisfield.Length; - if (trace) + if (trace(1)) htrc("%-11s %c %6ld %3d %2d %3d %3d\n", thisfield.Name, thisfield.Type, thisfield.Offset, len, thisfield.Decimals, thisfield.Setfield, thisfield.Mdxfield); @@ -522,14 +522,14 @@ bool DBFFAM::OpenTableFile(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); if (!(Stream = PlugOpenFile(g, filename, opmode))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (mode == MODE_READ && errno == ENOENT) ? PushWarning(g, Tdbp) : true; } // endif Stream - if (trace) + if (trace(1)) htrc("File %s is open in mode %s\n", filename, opmode); To_Fb = dbuserp->Openlist; // Keep track of File block @@ -938,7 +938,7 @@ void DBFFAM::CloseTableFile(PGLOBAL g, bool abort) rc = PlugCloseFile(g, To_Fb); fin: - if (trace) + if (trace(1)) htrc("DBF CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, mode, wrc, rc); diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp index 1d6194b154d..0a98ec5b54a 100644 --- a/storage/connect/filamfix.cpp +++ b/storage/connect/filamfix.cpp @@ -322,7 +322,7 @@ int FIXFAM::ReadBuffer(PGLOBAL g) return RC_FX; } // endif fseek - if (trace > 1) + if (trace(2)) htrc("File position is now %d\n", ftell(Stream)); if (Padded) @@ -344,7 +344,7 @@ int FIXFAM::ReadBuffer(PGLOBAL g) sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); #endif - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return RC_FX; @@ -361,7 +361,7 @@ int FIXFAM::ReadBuffer(PGLOBAL g) /***********************************************************************/ int FIXFAM::WriteBuffer(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("FIX WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n", Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum); @@ -374,7 +374,7 @@ int FIXFAM::WriteBuffer(PGLOBAL g) return RC_OK; // We write only full blocks } // endif CurNum - if (trace > 1) + if (trace(2)) htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf); // Now start the writing process. @@ -388,7 +388,7 @@ int FIXFAM::WriteBuffer(PGLOBAL g) CurNum = 0; Tdbp->SetLine(To_Buf); - if (trace > 1) + if (trace(2)) htrc("write done\n"); } else { // Mode == MODE_UPDATE @@ -431,7 +431,7 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) /* file, and at the end erase all trailing records. */ /* This will be experimented. */ /*********************************************************************/ - if (trace > 1) + if (trace(2)) htrc("DOS DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -441,7 +441,7 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = Tdbp->Cardinality(g); - if (trace > 1) + if (trace(2)) htrc("Fpos placed at file end=%d\n", Fpos); } else // Fpos is the deleted line position @@ -491,7 +491,7 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) OldBlk = -2; // To force fseek to be executed on next block } // endif moved - if (trace > 1) + if (trace(2)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { @@ -540,7 +540,7 @@ int FIXFAM::DeleteRecords(PGLOBAL g, int irc) close(h); - if (trace > 1) + if (trace(2)) htrc("done, h=%d irc=%d\n", h, irc); } // endif UseTemp @@ -572,7 +572,7 @@ bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) req = (size_t)MY_MIN(n, Dbflen); len = fread(DelBuf, Lrecl, req, Stream); - if (trace > 1) + if (trace(2)) htrc("after read req=%d len=%d\n", req, len); if (len != req) { @@ -591,13 +591,13 @@ bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) return true; } // endif - if (trace > 1) + if (trace(2)) htrc("after write pos=%d\n", ftell(Stream)); Tpos += (int)req; Spos += (int)req; - if (trace > 1) + if (trace(2)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); *b = true; @@ -648,7 +648,7 @@ void FIXFAM::CloseTableFile(PGLOBAL g, bool abort) rc = PlugCloseFile(g, To_Fb); fin: - if (trace) + if (trace(1)) htrc("FIX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, mode, wrc, rc); @@ -718,7 +718,7 @@ int BGXFAM::BigRead(PGLOBAL g __attribute__((unused)), DWORD nbr, drc, len = (DWORD)req; bool brc = ReadFile(h, inbuf, len, &nbr, NULL); - if (trace > 1) + if (trace(2)) htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr); if (!brc) { @@ -730,7 +730,7 @@ int BGXFAM::BigRead(PGLOBAL g __attribute__((unused)), (LPTSTR)buf, sizeof(buf), NULL); sprintf(g->Message, MSG(READ_ERROR), To_File, buf); - if (trace > 1) + if (trace(2)) htrc("BIGREAD: %s\n", g->Message); rc = -1; @@ -757,7 +757,7 @@ bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) DWORD nbw, drc, len = (DWORD)req; bool brc = WriteFile(h, inbuf, len, &nbw, NULL); - if (trace > 1) + if (trace(2)) htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw); if (!brc || nbw != len) { @@ -775,7 +775,7 @@ bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf); - if (trace > 1) + if (trace(2)) htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n", nbw, len, drc, g->Message); @@ -790,7 +790,7 @@ bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno)); - if (trace > 1) + if (trace(2)) htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n", nbw, len, errno, g->Message); @@ -828,7 +828,7 @@ bool BGXFAM::OpenTableFile(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("OpenTableFile: filename=%s mode=%d\n", filename, mode); #if defined(__WIN__) @@ -888,7 +888,7 @@ bool BGXFAM::OpenTableFile(PGLOBAL g) } else rc = 0; - if (trace > 1) + if (trace(2)) htrc(" rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n", rc, access, share, creation, Hfile, filename); @@ -942,7 +942,7 @@ bool BGXFAM::OpenTableFile(PGLOBAL g) } else rc = 0; - if (trace > 1) + if (trace(2)) htrc(" rc=%d oflag=%p tmode=%p handle=%p fn=%s\n", rc, oflag, tmode, Hfile, filename); @@ -1026,11 +1026,11 @@ int BGXFAM::Cardinality(PGLOBAL g) if (Hfile == INVALID_HANDLE_VALUE) { int h = open64(filename, O_RDONLY, 0); - if (trace) + if (trace(1)) htrc(" h=%d\n", h); if (h == INVALID_HANDLE_VALUE) { - if (trace) + if (trace(1)) htrc(" errno=%d ENOENT=%d\n", errno, ENOENT); if (errno != ENOENT) { @@ -1074,7 +1074,7 @@ int BGXFAM::Cardinality(PGLOBAL g) } else card = (int)(fsize / (BIGINT)Lrecl); // Fixed length file - if (trace) + if (trace(1)) htrc(" Computed max_K=%d fsize=%lf lrecl=%d\n", card, (double)fsize, Lrecl); @@ -1181,7 +1181,7 @@ int BGXFAM::ReadBuffer(PGLOBAL g) if (BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl)) return RC_FX; - if (trace > 1) + if (trace(2)) htrc("File position is now %d\n", Fpos); nbr = BigRead(g, Hfile, To_Buf, (Padded) ? Blksize : Lrecl * Nrec); @@ -1205,7 +1205,7 @@ int BGXFAM::ReadBuffer(PGLOBAL g) /***********************************************************************/ int BGXFAM::WriteBuffer(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("BIG WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n", Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum); @@ -1218,7 +1218,7 @@ int BGXFAM::WriteBuffer(PGLOBAL g) return RC_OK; // We write only full blocks } // endif CurNum - if (trace > 1) + if (trace(2)) htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf); // Now start the writing process. @@ -1229,7 +1229,7 @@ int BGXFAM::WriteBuffer(PGLOBAL g) CurNum = 0; Tdbp->SetLine(To_Buf); - if (trace > 1) + if (trace(2)) htrc("write done\n"); } else { // Mode == MODE_UPDATE @@ -1270,7 +1270,7 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) /* file, and at the end erase all trailing records. */ /* This will be experimented. */ /*********************************************************************/ - if (trace > 1) + if (trace(2)) htrc("BGX DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -1280,7 +1280,7 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = Tdbp->Cardinality(g); - if (trace > 1) + if (trace(2)) htrc("Fpos placed at file end=%d\n", Fpos); } else // Fpos is the deleted line position @@ -1318,7 +1318,7 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) return RC_FX; if (irc == RC_OK) { - if (trace) + if (trace(1)) assert(Spos == Fpos); Spos++; // New start position is on next line @@ -1330,7 +1330,7 @@ int BGXFAM::DeleteRecords(PGLOBAL g, int irc) OldBlk = -2; // To force fseek to be executed on next block } // endif moved - if (trace > 1) + if (trace(2)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else if (irc != RC_OK) { @@ -1459,7 +1459,7 @@ bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b) Tpos += (int)req; Spos += (int)req; - if (trace > 1) + if (trace(2)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); *b = true; @@ -1510,7 +1510,7 @@ void BGXFAM::CloseTableFile(PGLOBAL g, bool abort) rc = PlugCloseFile(g, To_Fb); fin: - if (trace) + if (trace(1)) htrc("BGX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, mode, wrc, rc); diff --git a/storage/connect/filamgz.cpp b/storage/connect/filamgz.cpp index 3078935e8a4..880db54c91d 100644 --- a/storage/connect/filamgz.cpp +++ b/storage/connect/filamgz.cpp @@ -203,7 +203,7 @@ bool GZFAM::AllocateBuffer(PGLOBAL g) Buflen = Lrecl + 2; // Lrecl does not include CRLF //Buflen *= ((Mode == MODE_DELETE) ? DOS_BUFF_LEN : 1); NIY - if (trace) + if (trace(1)) htrc("SubAllocating a buffer of %d bytes\n", Buflen); To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen); @@ -347,7 +347,7 @@ int GZFAM::ReadBuffer(PGLOBAL g) } else rc = Zerror(g); - if (trace > 1) + if (trace(2)) htrc(" Read: '%s' rc=%d\n", To_Buf, rc); return rc; @@ -389,7 +389,7 @@ void GZFAM::CloseTableFile(PGLOBAL, bool) { int rc = gzclose(Zfile); - if (trace) + if (trace(1)) htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc); Zfile = NULL; // So we can know whether table is open @@ -702,7 +702,7 @@ void ZBKFAM::CloseTableFile(PGLOBAL g, bool) } else rc = gzclose(Zfile); - if (trace) + if (trace(1)) htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc); Zfile = NULL; // So we can know whether table is open @@ -1382,7 +1382,7 @@ void ZLBFAM::CloseTableFile(PGLOBAL g, bool) } else rc = fclose(Stream); - if (trace) + if (trace(1)) htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n", To_File, Tdbp->GetMode(), rc); @@ -1408,7 +1408,7 @@ void ZLBFAM::Rewind(void) rewind(Stream); - if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace) + if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace(1)) htrc("fread error %d in Rewind", errno); fseek(Stream, *Zlenp + sizeof(int), SEEK_SET); diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 0f5069bae33..7c222eb3c80 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -194,12 +194,12 @@ int TXTFAM::GetFileLength(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); h= global_open(g, MSGID_OPEN_MODE_STRERROR, filename, _O_RDONLY); - if (trace) + if (trace(1)) htrc("GetFileLength: fn=%s h=%d\n", filename, h); if (h == -1) { if (errno != ENOENT) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); len = -1; @@ -249,7 +249,7 @@ int TXTFAM::Cardinality(PGLOBAL g) } // endif Padded - if (trace) + if (trace(1)) htrc(" Computed max_K=%d Filen=%d lrecl=%d\n", card, len, Lrecl); @@ -390,7 +390,7 @@ int TXTFAM::UpdateSortedRows(PGLOBAL g) return RC_OK; err: - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return RC_FX; @@ -439,7 +439,7 @@ int TXTFAM::DeleteSortedRows(PGLOBAL g) return RC_OK; err: - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return RC_FX; @@ -512,7 +512,7 @@ int DOSFAM::GetFileLength(PGLOBAL g) if ((len = _filelength(_fileno(Stream))) < 0) sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", To_File); - if (trace) + if (trace(1)) htrc("File length=%d\n", len); return len; @@ -598,14 +598,14 @@ bool DOSFAM::OpenTableFile(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); if (!(Stream = PlugOpenFile(g, filename, opmode))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (mode == MODE_READ && errno == ENOENT) ? PushWarning(g, Tdbp) : true; } // endif Stream - if (trace) + if (trace(1)) htrc("File %s open Stream=%p mode=%s\n", filename, Stream, opmode); To_Fb = dbuserp->Openlist; // Keep track of File block @@ -628,7 +628,7 @@ bool DOSFAM::AllocateBuffer(PGLOBAL g) // Lrecl does not include line ending Buflen = Lrecl + Ending + ((Bin) ? 1 : 0) + 1; // Sergei - if (trace) + if (trace(1)) htrc("SubAllocating a buffer of %d bytes\n", Buflen); To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen); @@ -768,7 +768,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) if (!Stream) return RC_EF; - if (trace > 1) + if (trace(2)) htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n", Tdbp, Tdbp->To_Line, Placed); @@ -782,7 +782,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) CurBlk = (int)Rows++; - if (trace > 1) + if (trace(2)) htrc("ReadBuffer: CurBlk=%d\n", CurBlk); /********************************************************************/ @@ -803,14 +803,14 @@ int DOSFAM::ReadBuffer(PGLOBAL g) } else Placed = false; - if (trace > 1) + if (trace(2)) htrc(" About to read: stream=%p To_Buf=%p Buflen=%d\n", Stream, To_Buf, Buflen); if (fgets(To_Buf, Buflen, Stream)) { p = To_Buf + strlen(To_Buf) - 1; - if (trace > 1) + if (trace(2)) htrc(" Read: To_Buf=%p p=%c\n", To_Buf, To_Buf, p); #if defined(__WIN__) @@ -838,7 +838,7 @@ int DOSFAM::ReadBuffer(PGLOBAL g) } else if (*p == '\n') *p = '\0'; // Eliminate ending new-line character - if (trace > 1) + if (trace(2)) htrc(" To_Buf='%s'\n", To_Buf); strcpy(Tdbp->To_Line, To_Buf); @@ -853,13 +853,13 @@ int DOSFAM::ReadBuffer(PGLOBAL g) sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0)); #endif - if (trace) + if (trace(1)) htrc("%s\n", g->Message); rc = RC_FX; } // endif's fgets - if (trace > 1) + if (trace(2)) htrc("ReadBuffer: rc=%d\n", rc); IsRead = true; @@ -895,7 +895,7 @@ int DOSFAM::WriteBuffer(PGLOBAL g) /*******************************************************************/ curpos = ftell(Stream); - if (trace) + if (trace(1)) htrc("Last : %d cur: %d\n", Fpos, curpos); if (UseTemp) { @@ -937,7 +937,7 @@ int DOSFAM::WriteBuffer(PGLOBAL g) return RC_FX; } // endif - if (trace) + if (trace(1)) htrc("write done\n"); return RC_OK; @@ -960,7 +960,7 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) /* file, and at the end erase all trailing records. */ /* This will be experimented. */ /*********************************************************************/ - if (trace) + if (trace(1)) htrc( "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, curpos, Fpos, Tpos, Spos); @@ -972,7 +972,7 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) fseek(Stream, 0, SEEK_END); Fpos = ftell(Stream); - if (trace) + if (trace(1)) htrc("Fpos placed at file end=%d\n", Fpos); } // endif irc @@ -1015,7 +1015,7 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) Spos = GetNextPos(); // New start position - if (trace) + if (trace(1)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { @@ -1058,7 +1058,7 @@ int DOSFAM::DeleteRecords(PGLOBAL g, int irc) close(h); - if (trace) + if (trace(1)) htrc("done, h=%d irc=%d\n", h, irc); } // endif !UseTemp @@ -1083,7 +1083,7 @@ bool DOSFAM::OpenTempFile(PGLOBAL g) strcat(PlugRemoveType(tempname, tempname), ".t"); if (!(T_Stream = PlugOpenFile(g, tempname, "wb"))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); rc = true; @@ -1112,7 +1112,7 @@ bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b) req = (size_t)MY_MIN(n, Dbflen); len = fread(DelBuf, 1, req, Stream); - if (trace) + if (trace(1)) htrc("after read req=%d len=%d\n", req, len); if (len != req) { @@ -1131,13 +1131,13 @@ bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b) return true; } // endif - if (trace) + if (trace(1)) htrc("after write pos=%d\n", ftell(Stream)); Tpos += (int)req; Spos += (int)req; - if (trace) + if (trace(1)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); *b = true; @@ -1217,7 +1217,7 @@ void DOSFAM::CloseTableFile(PGLOBAL g, bool abort) } else { rc = PlugCloseFile(g, To_Fb); - if (trace) + if (trace(1)) htrc("DOS Close: closing %s rc=%d\n", To_File, rc); } // endif UseTemp @@ -1453,7 +1453,7 @@ int BLKFAM::ReadBuffer(PGLOBAL g) // Calculate the length of block to read BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk]; - if (trace) + if (trace(1)) htrc("File position is now %d\n", ftell(Stream)); // Read the entire next block @@ -1487,7 +1487,7 @@ int BLKFAM::ReadBuffer(PGLOBAL g) sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); #endif - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return RC_FX; @@ -1637,7 +1637,7 @@ void BLKFAM::CloseTableFile(PGLOBAL g, bool abort) rc = PlugCloseFile(g, To_Fb); - if (trace) + if (trace(1)) htrc("BLK CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n", To_File, Tdbp->GetMode(), wrc, rc); diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp index 871613cb4b4..244acfdc5c8 100644 --- a/storage/connect/filamvct.cpp +++ b/storage/connect/filamvct.cpp @@ -336,7 +336,7 @@ int VCTFAM::Cardinality(PGLOBAL g) else sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, clen); - if (trace) + if (trace(1)) htrc(" Computed max_K=%d Filen=%d Clen=%d\n", card, len, clen); } else @@ -469,14 +469,14 @@ bool VCTFAM::OpenTableFile(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); if (!(Stream = PlugOpenFile(g, filename, opmode))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (mode == MODE_READ && errno == ENOENT) ? PushWarning(g, Tdbp) : true; } // endif Stream - if (trace) + if (trace(1)) htrc("File %s is open in mode %s\n", filename, opmode); To_Fb = dbuserp->Openlist; // Keep track of File block @@ -581,7 +581,7 @@ bool VCTFAM::InitInsert(PGLOBAL g) cp->ReadBlock(g); } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); rc = true; } catch (const char *msg) { @@ -652,7 +652,7 @@ int VCTFAM::ReadBuffer(PGLOBAL g) OldBlk = CurBlk; // Last block actually read } // endif oldblk - if (trace) + if (trace(1)) htrc(" Read: CurNum=%d CurBlk=%d rc=%d\n", CurNum, CurBlk, RC_OK); return rc; @@ -663,7 +663,7 @@ int VCTFAM::ReadBuffer(PGLOBAL g) /***********************************************************************/ int VCTFAM::WriteBuffer(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n", Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk); @@ -756,7 +756,7 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) { bool eof = false; - if (trace) + if (trace(1)) htrc("VCT DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -766,7 +766,7 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = (Block - 1) * Nrec + Last; - if (trace) + if (trace(1)) htrc("Fpos placed at file end=%d\n", Fpos); eof = UseTemp && !MaxBlk; @@ -807,7 +807,7 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) #endif Spos++; // New start position is on next line - if (trace) + if (trace(1)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { @@ -856,7 +856,7 @@ int VCTFAM::DeleteRecords(PGLOBAL g, int irc) close(h); - if (trace) + if (trace(1)) htrc("done, h=%d irc=%d\n", h, irc); } else @@ -899,7 +899,7 @@ bool VCTFAM::OpenTempFile(PGLOBAL g) opmode = "wb"; if (!(T_Stream = PlugOpenFile(g, tempname, opmode))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); rc = true; @@ -947,7 +947,7 @@ bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) len = fread(To_Buf, Clens[i], req, Stream); - if (trace) + if (trace(1)) htrc("after read req=%d len=%d\n", req, len); if (len != req) { @@ -976,7 +976,7 @@ bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // endif UseTemp - if (trace) + if (trace(1)) htrc("after write pos=%d\n", ftell(Stream)); } // endfor i @@ -1007,7 +1007,7 @@ bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // endif UseTemp - if (trace) + if (trace(1)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); } // endfor n @@ -1144,7 +1144,7 @@ void VCTFAM::CloseTableFile(PGLOBAL g, bool abort) if (!(UseTemp && T_Stream)) rc = PlugCloseFile(g, To_Fb); - if (trace) + if (trace(1)) htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n", To_File, wrc, rc); @@ -1217,7 +1217,7 @@ bool VCTFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) else // Blocked vector format len = Nrec * (colp->Deplac + Lrecl * CurBlk); - if (trace) + if (trace(1)) htrc("len=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d maxblk=%d\n", len, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk); @@ -1236,13 +1236,13 @@ bool VCTFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno)); - if (trace) + if (trace(1)) htrc(" Read error: %s\n", g->Message); return true; } // endif - if (trace) + if (trace(1)) num_read++; return false; @@ -1268,7 +1268,7 @@ bool VCTFAM::WriteBlock(PGLOBAL g, PVCTCOL colp) else // Old VCT format len = Nrec * (colp->Deplac + Lrecl * colp->ColBlk); - if (trace) + if (trace(1)) htrc("modif=%d len=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n", Modif, len, Nrec, colp->Deplac, Lrecl, colp->ColBlk); @@ -1287,7 +1287,7 @@ bool VCTFAM::WriteBlock(PGLOBAL g, PVCTCOL colp) sprintf(g->Message, MSG(WRITE_STRERROR), (UseTemp) ? To_Fbt->Fname : To_File, strerror(errno)); - if (trace) + if (trace(1)) htrc("Write error: %s\n", strerror(errno)); return true; @@ -1358,7 +1358,7 @@ bool VCMFAM::OpenTableFile(PGLOBAL g) && fp->Count && fp->Mode == mode) break; - if (trace) + if (trace(1)) htrc("Mapping VCM file, fp=%p cnt=%d\n", fp, fp->Count); } else @@ -1416,7 +1416,7 @@ bool VCMFAM::OpenTableFile(PGLOBAL g) sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int) rc, filename); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (mode == MODE_READ && rc == ENOENT) @@ -1467,7 +1467,7 @@ bool VCMFAM::OpenTableFile(PGLOBAL g) To_Fb = fp; // Useful when closing - if (trace) + if (trace(1)) htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n", fp, fp->Count, Memory, len); @@ -1551,7 +1551,7 @@ bool VCMFAM::InitInsert(PGLOBAL g) cp->ReadBlock(g); } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); rc = true; } catch (const char *msg) { @@ -1567,7 +1567,7 @@ bool VCMFAM::InitInsert(PGLOBAL g) /***********************************************************************/ int VCMFAM::WriteBuffer(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("VCM WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n", Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk); @@ -1608,7 +1608,7 @@ int VCMFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) { - if (trace) + if (trace(1)) htrc("VCM DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n", irc, To_Buf, Tpos, Spos); @@ -1618,7 +1618,7 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = (Block - 1) * Nrec + Last; - if (trace) + if (trace(1)) htrc("Fpos placed at file top=%p\n", Fpos); } else // Fpos is the Deleted line position @@ -1636,7 +1636,7 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) if (irc == RC_OK) { Spos = Fpos + 1; // New start position - if (trace) + if (trace(1)) htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); } else { @@ -1680,7 +1680,7 @@ int VCMFAM::DeleteRecords(PGLOBAL g, int irc) return RC_FX; } // endif - if (trace) + if (trace(1)) htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc); if (!SetEndOfFile(fp->Handle)) { @@ -1755,7 +1755,7 @@ bool VCMFAM::MoveIntermediateLines(PGLOBAL, bool *) Tpos += n; } // endif MaxBlk - if (trace) + if (trace(1)) htrc("move %d bytes\n", n); } // endif n @@ -1812,14 +1812,14 @@ bool VCMFAM::ReadBlock(PGLOBAL, PVCTCOL colp) /*********************************************************************/ mempos = Memcol[i] + n * CurBlk; - if (trace) + if (trace(1)) htrc("mempos=%p i=%d Nrec=%d Clen=%d CurBlk=%d\n", mempos, i, Nrec, colp->Clen, CurBlk); if (colp->GetStatus(BUF_MAPPED)) colp->Blk->SetValPointer(mempos); - if (trace) + if (trace(1)) num_read++; return false; @@ -1843,7 +1843,7 @@ bool VCMFAM::WriteBlock(PGLOBAL, PVCTCOL colp __attribute__((unused))) /*********************************************************************/ mempos = Memcol[i] + n * CurBlk; - if (trace) + if (trace(1)) htrc("modif=%d mempos=%p i=%d Nrec=%d Clen=%d colblk=%d\n", Modif, mempos, i, Nrec, colp->Clen, colp->ColBlk); @@ -2008,14 +2008,14 @@ bool VECFAM::OpenColumnFile(PGLOBAL g, PCSZ opmode, int i) sprintf(filename, Colfn, i+1); if (!(Streams[i] = PlugOpenFile(g, filename, opmode))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (Tdbp->GetMode() == MODE_READ && errno == ENOENT) ? PushWarning(g, Tdbp) : true; } // endif Streams - if (trace) + if (trace(1)) htrc("File %s is open in mode %s\n", filename, opmode); To_Fbs[i] = dup->Openlist; // Keep track of File blocks @@ -2163,7 +2163,7 @@ void VECFAM::ResetBuffer(PGLOBAL g) /***********************************************************************/ int VECFAM::WriteBuffer(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n", Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk); @@ -2205,7 +2205,7 @@ int VECFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ int VECFAM::DeleteRecords(PGLOBAL g, int irc) { - if (trace) + if (trace(1)) htrc("VEC DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -2215,7 +2215,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = Cardinality(g); - if (trace) + if (trace(1)) htrc("Fpos placed at file end=%d\n", Fpos); } else // Fpos is the Deleted line position @@ -2251,7 +2251,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) #endif Spos++; // New start position is on next line - if (trace) + if (trace(1)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { @@ -2294,7 +2294,7 @@ int VECFAM::DeleteRecords(PGLOBAL g, int irc) close(h); - if (trace) + if (trace(1)) htrc("done, h=%d irc=%d\n", h, irc); } // endfor i @@ -2332,7 +2332,7 @@ bool VECFAM::OpenTempFile(PGLOBAL g) sprintf(tempname, Tempat, i+1); if (!(T_Streams[i] = PlugOpenFile(g, tempname, "wb"))) { - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return true; @@ -2391,7 +2391,7 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *) len = fread(To_Buf, Clens[i], req, Streams[i]); - if (trace) + if (trace(1)) htrc("after read req=%d len=%d\n", req, len); if (len != req) { @@ -2410,7 +2410,7 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *) return true; } // endif - if (trace) + if (trace(1)) htrc("after write pos=%d\n", ftell(Streams[i])); } // endfor i @@ -2418,7 +2418,7 @@ bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *) Tpos += (int)req; Spos += (int)req; - if (trace) + if (trace(1)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); b = true; @@ -2541,7 +2541,7 @@ void VECFAM::CloseTableFile(PGLOBAL g, bool abort) To_Fbs[i] = NULL; } // endif Streams - if (trace) + if (trace(1)) htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n", To_File, wrc, rc); } // end of CloseTableFile @@ -2560,7 +2560,7 @@ bool VECFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) len = Nrec * colp->Clen * CurBlk; i = colp->Index - 1; - if (trace) + if (trace(1)) htrc("len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d\n", len, i, Nrec, colp->Deplac, Lrecl, CurBlk); @@ -2586,13 +2586,13 @@ bool VECFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) sprintf(g->Message, MSG(READ_ERROR), fn, strerror(errno)); - if (trace) + if (trace(1)) htrc(" Read error: %s\n", g->Message); return true; } // endif - if (trace) + if (trace(1)) num_read++; return false; @@ -2615,7 +2615,7 @@ bool VECFAM::WriteBlock(PGLOBAL g, PVCTCOL colp) len = Nrec * colp->Clen * colp->ColBlk; i = colp->Index - 1; - if (trace) + if (trace(1)) htrc("modif=%d len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n", Modif, len, i, Nrec, colp->Deplac, Lrecl, colp->ColBlk); @@ -2638,7 +2638,7 @@ bool VECFAM::WriteBlock(PGLOBAL g, PVCTCOL colp) sprintf(fn, (UseTemp) ? Tempat : Colfn, colp->Index); sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno)); - if (trace) + if (trace(1)) htrc("Write error: %s\n", strerror(errno)); return true; @@ -2782,7 +2782,7 @@ bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i) && fp->Count && fp->Mode == mode) break; - if (trace) + if (trace(1)) htrc("Mapping file, fp=%p\n", fp); } else @@ -2807,7 +2807,7 @@ bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i) if (!(*g->Message)) sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int) rc, filename); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return (mode == MODE_READ && rc == ENOENT) @@ -2858,7 +2858,7 @@ bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i) To_Fbs[i] = fp; // Useful when closing - if (trace) + if (trace(1)) htrc("fp=%p count=%d MapView=%p len=%d\n", fp, fp->Count, Memcol[i], len); @@ -2903,7 +2903,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) int i; int m, n; - if (trace) + if (trace(1)) htrc("VMP DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n", irc, To_Buf, Tpos, Spos); @@ -2913,7 +2913,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = (Block - 1) * Nrec + Last; - if (trace) + if (trace(1)) htrc("Fpos placed at file top=%p\n", Fpos); } else // Fpos is the Deleted line position @@ -2936,7 +2936,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) Tpos += n; - if (trace) + if (trace(1)) htrc("move %d bytes\n", n); } // endif n @@ -2944,7 +2944,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) if (irc == RC_OK) { Spos = Fpos + 1; // New start position - if (trace) + if (trace(1)) htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos); } else { @@ -2981,7 +2981,7 @@ int VMPFAM::DeleteRecords(PGLOBAL g, int irc) return RC_FX; } // endif - if (trace) + if (trace(1)) htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc); if (!SetEndOfFile(fp->Handle)) { @@ -3088,7 +3088,7 @@ bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req) DWORD nbr, drc, len = (DWORD)req; bool brc = ReadFile(h, inbuf, len, &nbr, NULL); - if (trace) + if (trace(1)) htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr); if (!brc || nbr != len) { @@ -3105,7 +3105,7 @@ bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(READ_ERROR), To_File, buf); - if (trace) + if (trace(1)) htrc("BIGREAD: %s\n", g->Message); rc = true; @@ -3119,7 +3119,7 @@ bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(READ_ERROR), fn, strerror(errno)); - if (trace) + if (trace(1)) htrc("BIGREAD: nbr=%d len=%d errno=%d %s\n", nbr, len, errno, g->Message); @@ -3141,7 +3141,7 @@ bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) DWORD nbw, drc, len = (DWORD)req; bool brc = WriteFile(h, inbuf, len, &nbw, NULL); - if (trace) + if (trace(1)) htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw); if (!brc || nbw != len) { @@ -3159,7 +3159,7 @@ bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf); - if (trace) + if (trace(1)) htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n", nbw, len, drc, g->Message); @@ -3174,7 +3174,7 @@ bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req) sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno)); - if (trace) + if (trace(1)) htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n", nbw, len, errno, g->Message); @@ -3224,7 +3224,7 @@ int BGVFAM::GetBlockInfo(PGLOBAL g) if (h == INVALID_HANDLE_VALUE || !_filelength(h)) { #endif // !__WIN__ // Consider this is a void table - if (trace) + if (trace(1)) htrc("Void table h=%d\n", h); Last = Nrec; @@ -3248,7 +3248,7 @@ int BGVFAM::GetBlockInfo(PGLOBAL g) Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0; Last = (vh.NumRec + Nrec - 1) % Nrec + 1; - if (trace) + if (trace(1)) htrc("Block=%d Last=%d\n", Block, Last); } // endif's @@ -3348,7 +3348,7 @@ bool BGVFAM::MakeEmptyFile(PGLOBAL g, PCSZ fn) of.QuadPart = (BIGINT)n + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1; - if (trace) + if (trace(1)) htrc("MEF: of=%lld n=%d maxblk=%d blksize=%d\n", of.QuadPart, n, MaxBlk, Blksize); @@ -3394,7 +3394,7 @@ bool BGVFAM::MakeEmptyFile(PGLOBAL g, PCSZ fn) pos = (BIGINT)n + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1; - if (trace) + if (trace(1)) htrc("MEF: pos=%lld n=%d maxblk=%d blksize=%d\n", pos, n, MaxBlk, Blksize); @@ -3439,7 +3439,7 @@ bool BGVFAM::OpenTableFile(PGLOBAL g) PlugSetPath(filename, To_File, Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("OpenTableFile: filename=%s mode=%d Last=%d\n", filename, mode, Last); @@ -3516,7 +3516,7 @@ bool BGVFAM::OpenTableFile(PGLOBAL g) strcat(g->Message, filename); } // endif Hfile - if (trace) + if (trace(1)) htrc(" rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n", rc, access, share, creation, Hfile, filename); @@ -3605,7 +3605,7 @@ bool BGVFAM::OpenTableFile(PGLOBAL g) strcat(g->Message, strerror(errno)); } // endif Hfile - if (trace) + if (trace(1)) htrc(" rc=%d oflag=%p mode=%p handle=%d fn=%s\n", rc, oflag, mode, Hfile, filename); #endif // UNIX @@ -3626,7 +3626,7 @@ bool BGVFAM::OpenTableFile(PGLOBAL g) To_Fb->Mode = mode; To_Fb->Handle = Hfile; - if (trace) + if (trace(1)) htrc("File %s is open in mode %d\n", filename, mode); if (del) @@ -3729,7 +3729,7 @@ bool BGVFAM::AllocateBuffer(PGLOBAL g) /***********************************************************************/ int BGVFAM::WriteBuffer(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("BGV WriteDB: R%d Mode=%d CurNum=%d CurBlk=%d\n", Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk); @@ -3829,7 +3829,7 @@ int BGVFAM::DeleteRecords(PGLOBAL g, int irc) /* 2 - directly move the not deleted lines inside the original */ /* file, and at the end erase all trailing records. */ /*********************************************************************/ - if (trace) + if (trace(1)) htrc("BGV DeleteDB: irc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n", irc, UseTemp, Fpos, Tpos, Spos); @@ -3839,7 +3839,7 @@ int BGVFAM::DeleteRecords(PGLOBAL g, int irc) /*******************************************************************/ Fpos = (Block - 1) * Nrec + Last; - if (trace) + if (trace(1)) htrc("Fpos placed at file end=%d\n", Fpos); eof = UseTemp && !MaxBlk; @@ -3878,7 +3878,7 @@ int BGVFAM::DeleteRecords(PGLOBAL g, int irc) #endif Spos++; // New start position is on next line - if (trace) + if (trace(1)) htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos); } else { @@ -4065,7 +4065,7 @@ bool BGVFAM::MoveIntermediateLines(PGLOBAL g, bool *b) } // endif Usetemp... - if (trace) + if (trace(1)) htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos); } // endfor n @@ -4201,7 +4201,7 @@ void BGVFAM::CloseTableFile(PGLOBAL g, bool abort) if (Hfile != INVALID_HANDLE_VALUE) rc = PlugCloseFile(g, To_Fb); - if (trace) + if (trace(1)) htrc("BGV CloseTableFile: closing %s wrc=%d rc=%d\n", To_File, wrc, rc); @@ -4247,7 +4247,7 @@ bool BGVFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac + (BIGINT)Lrecl * (BIGINT)CurBlk); - if (trace) + if (trace(1)) htrc("RB: offset=%lld Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d MaxBlk=%d\n", pos, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk); @@ -4257,7 +4257,7 @@ bool BGVFAM::ReadBlock(PGLOBAL g, PVCTCOL colp) if (BigRead(g, Hfile, colp->Blk->GetValPointer(), colp->Clen * Nrec)) return true; - if (trace) + if (trace(1)) num_read++; return false; @@ -4284,7 +4284,7 @@ bool BGVFAM::WriteBlock(PGLOBAL g, PVCTCOL colp) pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac + (BIGINT)Lrecl * (BIGINT)colp->ColBlk); - if (trace) + if (trace(1)) htrc("WB: offset=%lld Nrec=%d Deplac=%d Lrecl=%d ColBlk=%d\n", pos, Nrec, colp->Deplac, Lrecl, colp->ColBlk); diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index f94362a3d87..e76dc496246 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -699,7 +699,7 @@ bool UNZIPUTL::openEntry(PGLOBAL g) entryopen = true; } // endif rc - if (trace) + if (trace(1)) htrc("Openning entry%s %s\n", fn, (entryopen) ? "oked" : "failed"); return !entryopen; @@ -751,7 +751,7 @@ int UNZFAM::GetFileLength(PGLOBAL g) int len = (zutp && zutp->entryopen) ? (int)(Top - Memory) : TXTFAM::GetFileLength(g) * 3; - if (trace) + if (trace(1)) htrc("Zipped file length=%d\n", len); return len; diff --git a/storage/connect/filter.cpp b/storage/connect/filter.cpp index 76380f12ad6..7082b082c67 100644 --- a/storage/connect/filter.cpp +++ b/storage/connect/filter.cpp @@ -298,7 +298,7 @@ PFIL FILTER::Link(PGLOBAL g, PFIL fil2) { PFIL fil1; - if (trace) + if (trace(1)) htrc("Linking filter %p with op=%d... to filter %p with op=%d\n", this, Opc, fil2, (fil2) ? fil2->Opc : 0); @@ -352,7 +352,7 @@ int FILTER::CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &p, int &ag) char errmsg[MAX_STR] = ""; int agg, k, n = 0; - if (trace) + if (trace(1)) htrc("FILTER CheckColumn: sqlp=%p ag=%d\n", sqlp, ag); switch (Opc) { @@ -537,7 +537,7 @@ PFIL FILTER::SortJoin(PGLOBAL g) bool FILTER::FindJoinFilter(POPJOIN opj, PFIL fprec, bool teq, bool tek, bool tk2, bool tc2, bool tix, bool thx) { - if (trace) + if (trace(1)) htrc("FindJoinFilter: opj=%p fprec=%p tests=(%d,%d,%d,%d)\n", opj, fprec, teq, tek, tk2, tc2); @@ -864,7 +864,7 @@ bool FILTER::CheckLocal(PTDB tdbp) { bool local = TRUE; - if (trace) { + if (trace(1)) { if (tdbp) htrc("CheckLocal: filp=%p R%d\n", this, tdbp->GetTdb_No()); else @@ -874,7 +874,7 @@ bool FILTER::CheckLocal(PTDB tdbp) for (int i = 0; local && i < 2; i++) local = Arg(i)->CheckLocal(tdbp); - if (trace) + if (trace(1)) htrc("FCL: returning %d\n", local); return (local); @@ -980,7 +980,7 @@ bool FILTER::Convert(PGLOBAL g, bool having) { int i, comtype = TYPE_ERROR; - if (trace) + if (trace(1)) htrc("converting(?) %s %p opc=%d\n", (having) ? "having" : "filter", this, Opc); @@ -1011,7 +1011,7 @@ bool FILTER::Convert(PGLOBAL g, bool having) return TRUE; } // endswitch - if (trace) + if (trace(1)) htrc("Filter(%d): Arg type=%d\n", i, GetArgType(i)); // Set default values @@ -1056,7 +1056,7 @@ bool FILTER::Convert(PGLOBAL g, bool having) return TRUE; } // endif - if (trace) + if (trace(1)) htrc(" comtype=%d, B_T(%d)=%d Val(%d)=%p\n", comtype, i, Test[i].B_T, i, Val(i)); @@ -1064,7 +1064,7 @@ bool FILTER::Convert(PGLOBAL g, bool having) // Set or allocate the filter argument values and buffers for (i = 0; i < 2; i++) { - if (trace) + if (trace(1)) htrc(" conv type %d ? i=%d B_T=%d comtype=%d\n", GetArgType(i), i, Test[i].B_T, comtype); @@ -1141,7 +1141,7 @@ bool FILTER::Convert(PGLOBAL g, bool having) TEST: // Test for possible Eval optimization - if (trace) + if (trace(1)) htrc("Filp %p op=%d argtypes=(%d,%d)\n", this, Opc, GetArgType(0), GetArgType(1)); @@ -1230,7 +1230,7 @@ bool FILTER::Eval(PGLOBAL g) else if (Test[i].Conv) Val(i)->SetValue_pval(Arg(i)->GetValue()); - if (trace) + if (trace(1)) htrc(" Filter: op=%d type=%d %d B_T=%d %d val=%p %p\n", Opc, GetArgType(0), GetArgType(1), Test[0].B_T, Test[1].B_T, Val(0), Val(1)); @@ -1270,7 +1270,7 @@ bool FILTER::Eval(PGLOBAL g) goto FilterError; } // endswitch Type - if (trace) { + if (trace(1)) { htrc(" IN filtering: ap=%p\n", ap); if (ap) @@ -1360,7 +1360,7 @@ bool FILTER::Eval(PGLOBAL g) goto FilterError; } // endswitch Opc - if (trace) + if (trace(1)) htrc("Eval: filter %p Opc=%d result=%d\n", this, Opc, Value->GetIntValue()); @@ -1692,7 +1692,7 @@ PFIL PrepareFilter(PGLOBAL g, PFIL fp, bool having) { PFIL filp = NULL; - if (trace) + if (trace(1)) htrc("PrepareFilter: fp=%p having=%d\n", fp, having); while (fp) { @@ -1714,7 +1714,7 @@ PFIL PrepareFilter(PGLOBAL g, PFIL fp, bool having) filp->Next = NULL; } // endwhile - if (trace) + if (trace(1)) htrc(" returning filp=%p\n", filp); return filp; @@ -1740,7 +1740,7 @@ DllExport bool ApplyFilter(PGLOBAL g, PFIL filp) if (filp->Eval(g)) throw (int)TYPE_FILTER; - if (trace > 1) + if (trace(2)) htrc("PlugFilter filp=%p result=%d\n", filp, filp->GetResult()); diff --git a/storage/connect/global.h b/storage/connect/global.h index e4b00786efa..472d09408c3 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -52,7 +52,7 @@ /***********************************************************************/ /* Define access to the thread based trace value. */ /***********************************************************************/ -#define trace GetTraceValue() +#define trace(T) (bool)(GetTraceValue() & (uint)T) /***********************************************************************/ /* Miscellaneous Constants */ @@ -220,14 +220,19 @@ DllExport BOOL PlugIsAbsolutePath(LPCSTR path); DllExport bool AllocSarea(PGLOBAL, uint); DllExport void FreeSarea(PGLOBAL); DllExport BOOL PlugSubSet(PGLOBAL, void *, uint); -DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); DllExport char *PlugDup(PGLOBAL g, const char *str); DllExport void *MakePtr(void *, OFFSET); DllExport void htrc(char const *fmt, ...); -DllExport int GetTraceValue(void); +//DllExport int GetTraceValue(void); +DllExport uint GetTraceValue(void); #if defined(__cplusplus) } // extern "C" #endif +/***********************************************************************/ +/* Non exported routine declarations. */ +/***********************************************************************/ +void *PlugSubAlloc(PGLOBAL, void *, size_t); // Does throw + /*-------------------------- End of Global.H --------------------------*/ diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 4d62efd8988..eb1b564994f 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -175,9 +175,9 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.06.0005 October 14, 2017"; + char version[]= "Version 1.06.0007 March 11, 2018"; #if defined(__WIN__) - char compver[]= "Version 1.06.0005 " __DATE__ " " __TIME__; + char compver[]= "Version 1.06.0007 " __DATE__ " " __TIME__; char slash= '\\'; #else // !__WIN__ char slash= '/'; @@ -267,16 +267,38 @@ static char *strz(PGLOBAL g, LEX_CSTRING &ls) /***********************************************************************/ /* CONNECT session variables definitions. */ /***********************************************************************/ -// Tracing: 0 no, 1 yes, >1 more tracing -static MYSQL_THDVAR_INT(xtrace, - PLUGIN_VAR_RQCMDARG, "Console trace value.", - NULL, NULL, 0, 0, INT_MAX, 1); +// Tracing: 0 no, 1 yes, 2 more, 4 index... 511 all +const char *xtrace_names[] = +{ + "YES", "MORE", "INDEX", "MEMORY", "SUBALLOC", + "QUERY", "STMT", "HANDLER", "BLOCK", "MONGO", NullS +}; + +TYPELIB xtrace_typelib = +{ + array_elements(xtrace_names) - 1, "xtrace_typelib", + xtrace_names, NULL +}; + +static MYSQL_THDVAR_SET( + xtrace, // name + PLUGIN_VAR_RQCMDARG, // opt + "Trace values.", // comment + NULL, // check + NULL, // update function + 0, // def (NO) + &xtrace_typelib); // typelib // Getting exact info values static MYSQL_THDVAR_BOOL(exact_info, PLUGIN_VAR_RQCMDARG, "Getting exact info values", NULL, NULL, 0); +// Enabling cond_push +static MYSQL_THDVAR_BOOL(cond_push, PLUGIN_VAR_RQCMDARG, + "Enabling cond_push", + NULL, NULL, 1); // YES by default + /** Temporary file usage: no: Not using temporary file @@ -315,17 +337,18 @@ static MYSQL_THDVAR_UINT(work_size, static MYSQL_THDVAR_INT(conv_size, PLUGIN_VAR_RQCMDARG, // opt "Size used when converting TEXT columns.", - NULL, NULL, SZCONV, 0, 65500, 1); + NULL, NULL, SZCONV, 0, 65500, 8192); /** Type conversion: no: Unsupported types -> TYPE_ERROR yes: TEXT -> VARCHAR + force: Do it also for ODBC BINARY and BLOBs skip: skip unsupported type columns in Discovery */ const char *xconv_names[]= { - "NO", "YES", "SKIP", NullS + "NO", "YES", "FORCE", "SKIP", NullS }; TYPELIB xconv_typelib= @@ -340,7 +363,7 @@ static MYSQL_THDVAR_ENUM( "Unsupported types conversion.", // comment NULL, // check NULL, // update function - 0, // def (no) + 1, // def (yes) &xconv_typelib); // typelib // Null representation for JSON values @@ -365,12 +388,17 @@ static MYSQL_THDVAR_STR(java_wrapper, NULL, NULL, "wrappers/JdbcInterface"); #endif // JAVA_SUPPORT -#if 0 // This is apparently not acceptable for a plugin +// This is apparently not acceptable for a plugin so it is undocumented +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) // Enabling MONGO table type +#if defined(MONGO_SUPPORT) || (MYSQL_VERSION_ID > 100200) static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG, - "Enabling the MongoDB access", - NULL, NULL, MONGO_ENABLED); -#endif // 0 + "Enabling the MongoDB access", NULL, NULL, 1); +#else // !version 2,3 +static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG, + "Enabling the MongoDB access", NULL, NULL, 0); +#endif // !version 2,3 +#endif // JAVA_SUPPORT || CMGO_SUPPORT #if defined(XMSG) || defined(NEWMSG) const char *language_names[]= @@ -402,9 +430,10 @@ handlerton *connect_hton= NULL; /***********************************************************************/ /* Function to export session variable values to other source files. */ /***********************************************************************/ -extern "C" int GetTraceValue(void) - {return connect_hton ? THDVAR(current_thd, xtrace) : 0;} +uint GetTraceValue(void) + {return (uint)(connect_hton ? THDVAR(current_thd, xtrace) : 0);} bool ExactInfo(void) {return THDVAR(current_thd, exact_info);} +bool CondPushEnabled(void) {return THDVAR(current_thd, cond_push);} USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);} int GetConvSize(void) {return THDVAR(current_thd, conv_size);} TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);} @@ -420,22 +449,20 @@ void SetWorkSize(uint) push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0, "Work size too big, try setting a smaller value"); } // end of SetWorkSize -#if defined(XMSG) || defined(NEWMSG) -extern "C" const char *msglang(void) -{ - return language_names[THDVAR(current_thd, msg_lang)]; -} // end of msglang -#else // !XMSG && !NEWMSG #if defined(JAVA_SUPPORT) char *GetJavaWrapper(void) {return connect_hton ? THDVAR(current_thd, java_wrapper) : (char*)"wrappers/JdbcInterface";} #endif // JAVA_SUPPORT -#if defined(JAVA_SUPPORT) -//bool MongoEnabled(void) { return THDVAR(current_thd, enable_mongo); } -#endif // JAVA_SUPPORT +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) +bool MongoEnabled(void) {return THDVAR(current_thd, enable_mongo);} +#endif // JAVA_SUPPORT || CMGO_SUPPORT +#if defined(XMSG) || defined(NEWMSG) +extern "C" const char *msglang(void) + {return language_names[THDVAR(current_thd, msg_lang)];} +#else // !XMSG && !NEWMSG extern "C" const char *msglang(void) { #if defined(FRENCH) @@ -727,7 +754,7 @@ static int connect_init_func(void *p) connect_hton->tablefile_extensions= ha_connect_exts; connect_hton->discover_table_structure= connect_assisted_discovery; - if (trace) + if (trace(128)) sql_print_information("connect_init: hton=%p", p); DTVAL::SetTimeShift(); // Initialize time zone shift once for all @@ -819,7 +846,7 @@ static handler* connect_create_handler(handlerton *hton, { handler *h= new (mem_root) ha_connect(hton, table); - if (trace) + if (trace(128)) htrc("New CONNECT %p, table: %.*s\n", h, table ? table->table_name.length : 6, table ? table->table_name.str : "<null>"); @@ -875,7 +902,7 @@ ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg) /****************************************************************************/ ha_connect::~ha_connect(void) { - if (trace) + if (trace(128)) htrc("Delete CONNECT %p, table: %.*s, xp=%p count=%d\n", this, table ? table->s->table_name.length : 6, table ? table->s->table_name.str : "<null>", @@ -1659,7 +1686,7 @@ PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s) s= table->s; for (int n= 0; (unsigned)n < s->keynames.count; n++) { - if (trace) + if (trace(1)) htrc("Getting created index %d info\n", n + 1); // Find the index to describe @@ -2007,7 +2034,7 @@ bool ha_connect::CheckColumnList(PGLOBAL g) } // endif } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); brc = true; } catch (const char *msg) { @@ -2064,7 +2091,7 @@ int ha_connect::MakeRecord(char *buf) PCOL colp= NULL; DBUG_ENTER("ha_connect::MakeRecord"); - if (trace > 1) + if (trace(2)) htrc("Maps: read=%08X write=%08X vcol=%08X defr=%08X defw=%08X\n", *table->read_set->bitmap, *table->write_set->bitmap, (table->vcol_set) ? *table->vcol_set->bitmap : 0, @@ -2588,14 +2615,14 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) if (!cond) return NULL; - if (trace) + if (trace(1)) htrc("Cond type=%d\n", cond->type()); if (cond->type() == COND::COND_ITEM) { PFIL fp; Item_cond *cond_item= (Item_cond *)cond; - if (trace) + if (trace(1)) htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), cond_item->func_name()); @@ -2629,7 +2656,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) Item_func *condf= (Item_func *)cond; Item* *args= condf->arguments(); - if (trace) + if (trace(1)) htrc("Func type=%d argnum=%d\n", condf->functype(), condf->argument_count()); @@ -2658,11 +2685,11 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) return NULL; for (i= 0; i < condf->argument_count(); i++) { - if (trace) + if (trace(1)) htrc("Argtype(%d)=%d\n", i, args[i]->type()); if (i >= 2 && !ismul) { - if (trace) + if (trace(1)) htrc("Unexpected arg for vop=%d\n", vop); continue; @@ -2692,7 +2719,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) break; } // endswitch type - if (trace) { + if (trace(1)) { htrc("Field index=%d\n", pField->field->field_index); htrc("Field name=%s\n", pField->field->field_name.str); } // endif trace @@ -2739,7 +2766,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) return NULL; } // endswitch type - if (trace) + if (trace(1)) htrc("Value type=%hd\n", pp->Type); // Append the value to the argument list @@ -2757,7 +2784,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) filp= MakeFilter(g, colp, pop, pfirst, neg); } else { - if (trace) + if (trace(1)) htrc("Unsupported condition\n"); return NULL; @@ -2783,7 +2810,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) if (!cond) return NULL; - if (trace) + if (trace(1)) htrc("Cond type=%d\n", cond->type()); if (cond->type() == COND::COND_ITEM) { @@ -2796,7 +2823,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) else pb0= pb1= pb2= ph0= ph1= ph2= NULL; - if (trace) + if (trace(1)) htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), cond_item->func_name()); @@ -2882,7 +2909,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) filp->Bd = filp->Hv = false; - if (trace) + if (trace(1)) htrc("Func type=%d argnum=%d\n", condf->functype(), condf->argument_count()); @@ -2919,11 +2946,11 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) return NULL; for (i= 0; i < condf->argument_count(); i++) { - if (trace) + if (trace(1)) htrc("Argtype(%d)=%d\n", i, args[i]->type()); if (i >= 2 && !ismul) { - if (trace) + if (trace(1)) htrc("Unexpected arg for vop=%d\n", vop); continue; @@ -2966,7 +2993,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) } // endif's - if (trace) { + if (trace(1)) { htrc("Field index=%d\n", pField->field->field_index); htrc("Field name=%s\n", pField->field->field_name.str); htrc("Field type=%d\n", pField->field->type()); @@ -3004,7 +3031,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) if ((res= pval->val_str(&tmp)) == NULL) return NULL; // To be clarified - if (trace) + if (trace(1)) htrc("Value=%.*s\n", res->length(), res->ptr()); // IN and BETWEEN clauses should be col VOP list @@ -3145,7 +3172,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) filp->Bd = true; } else { - if (trace) + if (trace(1)) htrc("Unsupported condition\n"); return NULL; @@ -3178,7 +3205,7 @@ const COND *ha_connect::cond_push(const COND *cond) { DBUG_ENTER("ha_connect::cond_push"); - if (tdbp) { + if (tdbp && CondPushEnabled()) { PGLOBAL& g= xp->g; AMT tty= tdbp->GetAmType(); bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); @@ -3212,7 +3239,7 @@ const COND *ha_connect::cond_push(const COND *cond) if (filp->Having && strlen(filp->Having) > 255) goto fin; // Memory collapse - if (trace) + if (trace(1)) htrc("cond_push: %s\n", filp->Body); tdbp->SetCond(cond); @@ -3238,7 +3265,7 @@ const COND *ha_connect::cond_push(const COND *cond) } // endif tty } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); } catch (const char *msg) { strcpy(g->Message, msg); @@ -3291,7 +3318,7 @@ bool ha_connect::get_error_message(int error, String* buf) &my_charset_latin1, &dummy_errors); - if (trace) + if (trace(1)) htrc("GEM(%d): len=%u %s\n", error, len, g->Message); msg[len]= '\0'; @@ -3343,7 +3370,7 @@ int ha_connect::open(const char *name, int mode, uint test_if_locked) int rc= 0; DBUG_ENTER("ha_connect::open"); - if (trace) + if (trace(1)) htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked); if (!(share= get_share())) @@ -3418,7 +3445,7 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT*) rc = HA_ERR_INTERNAL_ERROR; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); rc = HA_ERR_INTERNAL_ERROR; } catch (const char *msg) { @@ -3566,7 +3593,7 @@ int ha_connect::update_row(const uchar *old_data, const uchar *new_data) PGLOBAL& g= xp->g; DBUG_ENTER("ha_connect::update_row"); - if (trace > 1) + if (trace(2)) htrc("update_row: old=%s new=%s\n", old_data, new_data); // Check values for possible change in indexed column @@ -3627,7 +3654,7 @@ int ha_connect::index_init(uint idx, bool sorted) PGLOBAL& g= xp->g; DBUG_ENTER("index_init"); - if (trace) + if (trace(1)) htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted); if (GetIndexType(GetRealType()) == 2) { @@ -3680,7 +3707,7 @@ int ha_connect::index_init(uint idx, bool sorted) rc= 0; } // endif indexing - if (trace) + if (trace(1)) htrc("index_init: rc=%d indexing=%d active_index=%d\n", rc, indexing, active_index); @@ -3727,7 +3754,7 @@ int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const key_range *kr) break; } // endswitch RC - if (trace > 1) + if (trace(2)) htrc("ReadIndexed: op=%d rc=%d\n", op, rc); table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND; @@ -3770,7 +3797,7 @@ int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len, default: DBUG_RETURN(-1); break; } // endswitch find_flag - if (trace > 1) + if (trace(2)) htrc("%p index_read: op=%d\n", this, op); if (indexing > 0) { @@ -3934,7 +3961,7 @@ int ha_connect::rnd_init(bool scan) alter= 1; } // endif xmod - if (trace) + if (trace(1)) htrc("rnd_init: this=%p scan=%d xmod=%d alter=%d\n", this, scan, xmod, alter); @@ -4040,7 +4067,7 @@ int ha_connect::rnd_next(uchar *buf) break; } // endswitch RC - if (trace > 1 && (rc || !(xp->nrd++ % 16384))) { + if (trace(2) && (rc || !(xp->nrd++ % 16384))) { ulonglong tb2= my_interval_timer(); double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL; DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n", @@ -4084,7 +4111,7 @@ void ha_connect::position(const uchar *) DBUG_ENTER("ha_connect::position"); my_store_ptr(ref, ref_length, (my_off_t)tdbp->GetRecpos()); - if (trace > 1) + if (trace(2)) htrc("position: pos=%d\n", tdbp->GetRecpos()); DBUG_VOID_RETURN; @@ -4114,7 +4141,7 @@ int ha_connect::rnd_pos(uchar *buf, uchar *pos) DBUG_ENTER("ha_connect::rnd_pos"); if (!tdbp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length))) { - if (trace) + if (trace(1)) htrc("rnd_pos: %d\n", tdbp->GetRecpos()); tdbp->SetFilter(NULL); @@ -4180,7 +4207,7 @@ int ha_connect::info(uint flag) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endif g - if (trace) + if (trace(1)) htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info); // tdbp must be available to get updated info @@ -4373,54 +4400,59 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn, bool my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); return true; } // endif path - } + + } // endif !quick + } else return false; - // check FILE_ACL - // fall through - case TAB_ODBC: - case TAB_JDBC: + // Fall through case TAB_MYSQL: - case TAB_MONGO: case TAB_DIR: - case TAB_MAC: - case TAB_WMI: case TAB_ZIP: case TAB_OEM: #ifdef NO_EMBEDDED_ACCESS_CHECKS - return false; -#endif - /* - If table or table->mdl_ticket is NULL - it's a DLL, e.g. CREATE TABLE. - if the table has an MDL_EXCLUSIVE lock - it's a DDL too, e.g. the - insert step of CREATE ... SELECT. - - Otherwise it's a DML, the table was normally opened, locked, - privilege were already checked, and table->grant.privilege is set. - With SQL SECURITY DEFINER, table->grant.privilege has definer's privileges. - - Unless we're in prelocking mode, in this case table->grant.privilege - is only checked in start_stmt(), not in external_lock(). - */ - if (!table || !table->mdl_ticket || table->mdl_ticket->get_type() == MDL_EXCLUSIVE) - return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0); - if ((!quick && thd->lex->requires_prelocking()) || table->grant.privilege & FILE_ACL) - return false; - status_var_increment(thd->status_var.access_denied_errors); - my_error(access_denied_error_code(thd->password), MYF(0), - thd->security_ctx->priv_user, thd->security_ctx->priv_host, - (thd->password ? ER(ER_YES) : ER(ER_NO))); - return true; - - // This is temporary until a solution is found + return false; + #endif + + /* + Check FILE_ACL + If table or table->mdl_ticket is NULL - it's a DLL, e.g. CREATE TABLE. + if the table has an MDL_EXCLUSIVE lock - it's a DDL too, e.g. the + insert step of CREATE ... SELECT. + + Otherwise it's a DML, the table was normally opened, locked, + privilege were already checked, and table->grant.privilege is set. + With SQL SECURITY DEFINER, table->grant.privilege has definer's privileges. + + Unless we're in prelocking mode, in this case table->grant.privilege + is only checked in start_stmt(), not in external_lock(). + */ + if (!table || !table->mdl_ticket || table->mdl_ticket->get_type() == MDL_EXCLUSIVE) + return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0); + + if ((!quick && thd->lex->requires_prelocking()) || table->grant.privilege & FILE_ACL) + return false; + + status_var_increment(thd->status_var.access_denied_errors); + my_error(access_denied_error_code(thd->password), MYF(0), + thd->security_ctx->priv_user, thd->security_ctx->priv_host, + (thd->password ? ER(ER_YES) : ER(ER_NO))); + return true; + case TAB_ODBC: + case TAB_JDBC: + case TAB_MONGO: + case TAB_MAC: + case TAB_WMI: + return false; case TAB_TBL: case TAB_XCL: case TAB_PRX: case TAB_OCCUR: case TAB_PIVOT: case TAB_VIR: - return false; + // This is temporary until a solution is found + return false; } // endswitch type my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0)); @@ -4458,7 +4490,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, #if defined(DEVELOPMENT) if (true) { #else - if (trace) { + if (trace(65)) { #endif LEX_STRING *query_string= thd_query_string(thd); htrc("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd)); @@ -4579,7 +4611,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, } // endif's newmode - if (trace) + if (trace(1)) htrc("New mode=%d\n", newmode); return newmode; @@ -4657,7 +4689,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) DBUG_ASSERT(thd == current_thd); - if (trace) + if (trace(1)) htrc("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n", this, thd, xp, g, lock_type); @@ -4850,7 +4882,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) if (cras) g->Createas= 1; // To tell created table to ignore FLAG - if (trace) { + if (trace(1)) { #if 0 htrc("xcheck=%d cras=%d\n", xcheck, cras); @@ -4883,7 +4915,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) // Delay open until used fields are known } // endif tdbp - if (trace) + if (trace(1)) htrc("external_lock: rc=%d\n", rc); DBUG_RETURN(rc); @@ -5019,7 +5051,7 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to) THD *thd= current_thd; int sqlcom= thd_sql_command(thd); - if (trace) { + if (trace(1)) { if (to) htrc("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n", this, thd, sqlcom, name, to); @@ -5130,7 +5162,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, if (index_init(inx, false)) DBUG_RETURN(HA_POS_ERROR); - if (trace) + if (trace(1)) htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing); if (indexing > 0) { @@ -5159,7 +5191,7 @@ ha_rows ha_connect::records_in_range(uint inx, key_range *min_key, else rows= HA_POS_ERROR; - if (trace) + if (trace(1)) htrc("records_in_range: rows=%llu\n", rows); DBUG_RETURN(rows); @@ -5381,7 +5413,7 @@ static int init_table_share(THD* thd, } // endif charset - if (trace) + if (trace(1)) htrc("s_init: %.*s\n", sql->length(), sql->ptr()); return table_s->init_from_sql_statement_string(thd, true, @@ -5414,7 +5446,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #endif // __WIN__ //int hdr, mxe; int port = 0, mxr = 0, rc = 0, mul = 0, lrecl = 0; - PCSZ tabtyp = NULL; +//PCSZ tabtyp = NULL; #if defined(ODBC_SUPPORT) POPARM sop= NULL; PCSZ ucnc= NULL; @@ -5478,7 +5510,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #endif // __WIN__ port= atoi(GetListOption(g, "port", topt->oplist, "0")); #if defined(ODBC_SUPPORT) - tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); +// tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1")); qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1")); @@ -5791,7 +5823,8 @@ static int connect_assisted_discovery(handlerton *, THD* thd, break; case FNC_TABLE: - qrp = JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp); +// qrp = JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp); + qrp = JDBCTables(g, shm, tab, NULL, mxr, true, sjp); break; #if 0 case FNC_DSN: @@ -6094,7 +6127,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, } // endif ok } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); rc = HA_ERR_INTERNAL_ERROR; } catch (const char *msg) { @@ -6190,7 +6223,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, table= table_arg; // Used by called functions - if (trace) + if (trace(1)) htrc("create: this=%p thd=%p xp=%p g=%p sqlcom=%d name=%s\n", this, thd, xp, g, sqlcom, GetTableName()); @@ -6573,7 +6606,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif sqlcom - if (trace) + if (trace(1)) htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas); if (options->zipped) { @@ -6944,7 +6977,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table, xcp->newsep= xcp->SetName(g, GetStringOption("optname")); tshp= NULL; - if (trace && g->Xchk) + if (trace(1) && g->Xchk) htrc( "oldsep=%d newsep=%d oldopn=%s newopn=%s oldpix=%p newpix=%p\n", xcp->oldsep, xcp->newsep, @@ -7208,10 +7241,11 @@ static struct st_mysql_sys_var* connect_system_variables[]= { MYSQL_SYSVAR(class_path), MYSQL_SYSVAR(java_wrapper), #endif // JAVA_SUPPORT -#if defined(JAVA_SUPPORT) -//MYSQL_SYSVAR(enable_mongo), -#endif // JAVA_SUPPORT -NULL +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) + MYSQL_SYSVAR(enable_mongo), +#endif // JAVA_SUPPORT || CMGO_SUPPORT + MYSQL_SYSVAR(cond_push), + NULL }; maria_declare_plugin(connect) @@ -7224,10 +7258,10 @@ maria_declare_plugin(connect) PLUGIN_LICENSE_GPL, connect_init_func, /* Plugin Init */ connect_done_func, /* Plugin Deinit */ - 0x0106, /* version number (1.05) */ + 0x0107, /* version number (1.05) */ NULL, /* status variables */ connect_system_variables, /* system variables */ - "1.06.0005", /* string version */ + "1.06.0007", /* string version */ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp index 96ae0a67a6b..c039a980bcb 100644 --- a/storage/connect/inihandl.cpp +++ b/storage/connect/inihandl.cpp @@ -293,7 +293,7 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) next_key = §ion->key; prev_key = NULL; - if (trace > 1) + if (trace(2)) htrc("New section: '%s'\n",section->name); continue; @@ -336,7 +336,7 @@ static PROFILESECTION *PROFILE_Load( FILE *file ) next_key = &key->next; prev_key = key; - if (trace > 1) + if (trace(2)) htrc("New key: name='%s', value='%s'\n", key->name,key->value?key->value:"(none)"); @@ -359,7 +359,7 @@ static BOOL PROFILE_FlushFile(void) FILE *file = NULL; struct stat buf; - if (trace > 1) + if (trace(2)) htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile); if (!CurProfile) { @@ -398,7 +398,7 @@ static BOOL PROFILE_FlushFile(void) return FALSE; } // endif !file - if (trace > 1) + if (trace(2)) htrc("Saving '%s'\n", CurProfile->filename); PROFILE_Save(file, CurProfile->section); @@ -447,7 +447,7 @@ static BOOL PROFILE_Open(LPCSTR filename) struct stat buf; PROFILE *tempProfile; - if (trace > 1) + if (trace(2)) htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); /* First time around */ @@ -468,7 +468,7 @@ static BOOL PROFILE_Open(LPCSTR filename) /* Check for a match */ for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace > 1) + if (trace(2)) htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { @@ -483,11 +483,11 @@ static BOOL PROFILE_Open(LPCSTR filename) } // endif i if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) { - if (trace > 1) + if (trace(2)) htrc("(%s): already opened (mru=%d)\n", filename, i); } else { - if (trace > 1) + if (trace(2)) htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i); } // endif stat @@ -535,11 +535,11 @@ static BOOL PROFILE_Open(LPCSTR filename) // strcpy(p, filename); // _strlwr(p); - if (trace > 1) + if (trace(2)) htrc("Opening %s\n", filename); if ((file = fopen(filename, "r"))) { - if (trace > 1) + if (trace(2)) htrc("(%s): found it\n", filename); // CurProfile->unix_name = malloc(strlen(buffer)+1); @@ -574,12 +574,12 @@ void PROFILE_Close(LPCSTR filename) struct stat buf; PROFILE *tempProfile; - if (trace > 1) + if (trace(2)) htrc("PROFILE_Close: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); /* Check for a match */ for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace > 1) + if (trace(2)) htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) { @@ -591,7 +591,7 @@ void PROFILE_Close(LPCSTR filename) CurProfile=tempProfile; } // endif i - if (trace > 1) { + if (trace(2)) { if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) htrc("(%s): already opened (mru=%d)\n", filename, i); else @@ -620,7 +620,7 @@ void PROFILE_End(void) { int i; - if (trace) + if (trace(3)) htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES); if (!CurProfile) // Sergey Vojtovich @@ -628,7 +628,7 @@ void PROFILE_End(void) /* Close all opened files and free the cache structure */ for (i = 0; i < N_CACHED_PROFILES; i++) { - if (trace) + if (trace(3)) htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i); // CurProfile = MRUProfile[i]; Sergey Vojtovich @@ -894,7 +894,7 @@ static int PROFILE_GetSectionNames(LPSTR buffer, uint len) uint f,l; PROFILESECTION *section; - if (trace > 1) + if (trace(2)) htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len); if (!buffer || !len) @@ -909,17 +909,17 @@ static int PROFILE_GetSectionNames(LPSTR buffer, uint len) buf = buffer; section = CurProfile->section; - if (trace > 1) + if (trace(2)) htrc("GetSectionNames: section=%p\n", section); while (section != NULL) { - if (trace > 1) + if (trace(2)) htrc("section=%s\n", section->name); if (section->name[0]) { l = strlen(section->name) + 1; - if (trace > 1) + if (trace(2)) htrc("l=%u f=%u\n", l, f); if (l > f) { @@ -982,7 +982,7 @@ static int PROFILE_GetString(LPCSTR section, LPCSTR key_name, key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE); PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE); - if (trace > 1) + if (trace(2)) htrc("('%s','%s','%s'): returning '%s'\n", section, key_name, def_val, buffer ); @@ -1010,7 +1010,7 @@ static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, LPCSTR value, BOOL create_always) { if (!key_name) { /* Delete a whole section */ - if (trace > 1) + if (trace(2)) htrc("Deleting('%s')\n", section_name); CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section, @@ -1018,7 +1018,7 @@ static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, return TRUE; /* Even if PROFILE_DeleteSection() has failed, this is not an error on application's level.*/ } else if (!value) { /* Delete a key */ - if (trace > 1) + if (trace(2)) htrc("Deleting('%s','%s')\n", section_name, key_name); CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section, @@ -1027,7 +1027,7 @@ static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, } else { /* Set the key value */ PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name, key_name, TRUE, create_always); - if (trace > 1) + if (trace(2)) htrc("Setting('%s','%s','%s')\n", section_name, key_name, value); if (!key) @@ -1040,17 +1040,17 @@ static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name, value++; if (!strcmp(key->value, value)) { - if (trace > 1) + if (trace(2)) htrc(" no change needed\n" ); return TRUE; /* No change needed */ } // endif value - if (trace > 1) + if (trace(2)) htrc(" replacing '%s'\n", key->value); free(key->value); - } else if (trace > 1) + } else if (trace(2)) htrc(" creating key\n" ); key->value = (char*)malloc(strlen(value) + 1); @@ -1345,7 +1345,7 @@ GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename) { DWORD ret = 0; - if (trace > 1) + if (trace(2)) htrc("GPPSN: filename=%s\n", filename); EnterCriticalSection(&PROFILE_CritSect); diff --git a/storage/connect/javaconn.cpp b/storage/connect/javaconn.cpp index 90f834ef9a7..d1be0ca1848 100644 --- a/storage/connect/javaconn.cpp +++ b/storage/connect/javaconn.cpp @@ -363,7 +363,7 @@ bool JAVAConn::GetJVM(PGLOBAL g) bool JAVAConn::Open(PGLOBAL g) { bool brc = true, err = false; - jboolean jt = (trace > 0); + jboolean jt = (trace(1)); // Link or check whether jvm library was linked if (GetJVM(g)) @@ -430,7 +430,7 @@ bool JAVAConn::Open(PGLOBAL g) jpop->Append(cp); } // endif cp - if (trace) { + if (trace(1)) { htrc("ClassPath=%s\n", ClassPath); htrc("CLASSPATH=%s\n", cp); htrc("%s\n", jpop->GetStr()); @@ -486,7 +486,7 @@ bool JAVAConn::Open(PGLOBAL g) break; } // endswitch rc - if (trace) + if (trace(1)) htrc("%s\n", g->Message); if (brc) diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp index 01c19f5b19f..33414ca74c2 100644 --- a/storage/connect/jdbconn.cpp +++ b/storage/connect/jdbconn.cpp @@ -1,7 +1,7 @@ /************ Jdbconn C++ Functions Source Code File (.CPP) ************/ -/* Name: JDBCONN.CPP Version 1.1 */ +/* Name: JDBCONN.CPP Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2016-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2016-2018 */ /* */ /* This file contains the JDBC connection classes functions. */ /***********************************************************************/ @@ -116,10 +116,26 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v) return TYPE_ERROR; else len = MY_MIN(abs(len), GetConvSize()); + // Pass through case 12: // VARCHAR + if (tn && !stricmp(tn, "TEXT")) + // Postgresql returns 12 for TEXT + if (GetTypeConv() == TPC_NO) + return TYPE_ERROR; + + // Postgresql can return this + if (len == 0x7FFFFFFF) + len = GetConvSize(); + + // Pass through case -9: // NVARCHAR (unicode) + // Postgresql can return this when size is unknown + if (len == 0x7FFFFFFF) + len = GetConvSize(); + v = 'V'; + // Pass through case 1: // CHAR case -15: // NCHAR (unicode) case -8: // ROWID @@ -171,6 +187,14 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v) case -5: // BIGINT type = TYPE_BIGINT; break; + case 1111: // UNKNOWN or UUID + if (!tn || !stricmp(tn, "UUID")) { + type = TYPE_STRING; + len = 36; + break; + } // endif tn + + // Pass through case 0: // NULL case -2: // BINARY case -4: // LONGVARBINARY @@ -192,6 +216,104 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v) return type; } // end of TranslateJDBCType + /***********************************************************************/ + /* A helper class to split an optionally qualified table name into */ + /* components. */ + /* These formats are understood: */ + /* "CatalogName.SchemaName.TableName" */ + /* "SchemaName.TableName" */ + /* "TableName" */ + /***********************************************************************/ +class SQLQualifiedName { + static const uint max_parts = 3; // Catalog.Schema.Table + MYSQL_LEX_STRING m_part[max_parts]; + char m_buf[512]; + + void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length) + { + S->str = str; + S->length = length; + } // end of lex_string_set + + void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs) + { + DBUG_ASSERT(offs <= S->length); + S->str += offs; + S->length -= offs; + } // end of lex_string_shorten_down + + /*********************************************************************/ + /* Find the rightmost '.' delimiter and return the length */ + /* of the qualifier, including the rightmost '.' delimier. */ + /* For example, for the string {"a.b.c",5} it will return 4, */ + /* which is the length of the qualifier "a.b." */ + /*********************************************************************/ + size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S) + { + size_t i; + for (i = S->length; i > 0; i--) + { + if (S->str[i - 1] == '.') + { + S->str[i - 1] = '\0'; + return i; + } + } + return 0; + } // end of lex_string_find_qualifier + +public: + /*********************************************************************/ + /* Initialize to the given optionally qualified name. */ + /* NULL pointer in "name" is supported. */ + /* name qualifier has precedence over schema. */ + /*********************************************************************/ + SQLQualifiedName(JCATPARM *cap) + { + const char *name = (const char *)cap->Tab; + char *db = (char *)cap->DB; + size_t len, i; + + // Initialize the parts + for (i = 0; i < max_parts; i++) + lex_string_set(&m_part[i], NULL, 0); + + if (name) { + // Initialize the first (rightmost) part + lex_string_set(&m_part[0], m_buf, + strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf); + + // Initialize the other parts, if exist. + for (i = 1; i < max_parts; i++) { + if (!(len = lex_string_find_qualifier(&m_part[i - 1]))) + break; + + lex_string_set(&m_part[i], m_part[i - 1].str, len - 1); + lex_string_shorten_down(&m_part[i - 1], len); + } // endfor i + + } // endif name + + // If it was not specified, set schema as the passed db name + if (db && !m_part[1].length) + lex_string_set(&m_part[1], db, strlen(db)); + + } // end of SQLQualifiedName + + char *ptr(uint i) + { + DBUG_ASSERT(i < max_parts); + return (char *)(m_part[i].length ? m_part[i].str : NULL); + } // end of ptr + + size_t length(uint i) + { + DBUG_ASSERT(i < max_parts); + return m_part[i].length; + } // end of length + +}; // end of class SQLQualifiedName + /***********************************************************************/ /* Allocate the structure used to refer to the result set. */ /***********************************************************************/ @@ -270,7 +392,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, length[11] = 255; } // endif jcp - if (trace) + if (trace(1)) htrc("JDBCColumns: max=%d len=%d,%d,%d,%d\n", maxres, length[0], length[1], length[2], length[3]); @@ -287,7 +409,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, if (info || !qrp) // Info table return qrp; - if (trace) + if (trace(1)) htrc("Getting col results ncol=%d\n", qrp->Nbcol); if (!(cap = AllocCatInfo(g, JCAT_COL, db, table, qrp))) @@ -303,7 +425,7 @@ PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat, qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -394,7 +516,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, length[4] = 255; } // endif info - if (trace) + if (trace(1)) htrc("JDBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]); /************************************************************************/ @@ -417,7 +539,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, cap->Pat = tabtyp; - if (trace) + if (trace(1)) htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol); /************************************************************************/ @@ -427,7 +549,7 @@ PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp, qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -475,7 +597,7 @@ PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info) } else maxres = 0; - if (trace) + if (trace(1)) htrc("JDBCDrivers: max=%d len=%d\n", maxres, length[0]); /************************************************************************/ @@ -519,7 +641,7 @@ JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper) xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr; prepid = xpid = pcid = nullptr; chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr; - objfldid = datfldid = timfldid = tspfldid = nullptr; + objfldid = datfldid = timfldid = tspfldid = uidfldid = nullptr; DiscFunc = "JdbcDisconnect"; m_Ncol = 0; m_Aff = 0; @@ -535,12 +657,84 @@ JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper) m_IDQuoteChar[1] = 0; } // end of JDBConn -//JDBConn::~JDBConn() -// { -//if (Connected()) -// EndCom(); +/***********************************************************************/ +/* Search for UUID columns. */ +/***********************************************************************/ +bool JDBConn::SetUUID(PGLOBAL g, PTDBJDBC tjp) +{ + int ncol, ctyp; + bool brc = true; + PCSZ fnc = "GetColumns"; + PCOL colp; + JCATPARM *cap; + //jint jtyp; + jboolean rc = false; + jobjectArray parms; + jmethodID catid = nullptr; + + if (gmID(g, catid, fnc, "([Ljava/lang/String;)I")) + return true; + else if (gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I")) + return true; + else if (gmID(g, readid, "ReadNext", "()I")) + return true; + + cap = AllocCatInfo(g, JCAT_COL, tjp->Schema, tjp->TableName, NULL); + SQLQualifiedName name(cap); + + // Build the java string array + parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL); + env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2))); + env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1))); + env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0))); + + for (colp = tjp->GetColumns(); colp; colp = colp->GetNext()) { + env->SetObjectArrayElement(parms, 3, env->NewStringUTF(colp->GetName())); + ncol = env->CallIntMethod(job, catid, parms); + + if (Check(ncol)) { + sprintf(g->Message, "%s: %s", fnc, Msg); + goto err; + } // endif Check + + rc = env->CallBooleanMethod(job, readid); + + if (Check(rc)) { + sprintf(g->Message, "ReadNext: %s", Msg); + goto err; + } else if (rc == 0) { + sprintf(g->Message, "table %s does not exist", tjp->TableName); + goto err; + } // endif rc + + // Returns 666 is case of error + //jtyp = env->CallIntMethod(job, typid, 5, nullptr); + + //if (Check((jtyp == 666) ? -1 : 1)) { + // sprintf(g->Message, "Getting jtyp: %s", Msg); + // goto err; + //} // endif ctyp + + ctyp = (int)env->CallIntMethod(job, intfldid, 5, nullptr); + + if (Check(ctyp)) { + sprintf(g->Message, "Getting ctyp: %s", Msg); + goto err; + } // endif ctyp + + if (ctyp == 1111) + ((PJDBCCOL)colp)->uuid = true; + + } // endfor colp + + // All is Ok + brc = false; -// } // end of ~JDBConn + err: + // Not used anymore + env->DeleteLocalRef(parms); + return brc; +} // end of SetUUID /***********************************************************************/ /* Utility routine. */ @@ -586,7 +780,7 @@ bool JDBConn::Connect(PJPARM sop) int irc = RC_FX; bool err = false; jint rc; - jboolean jt = (trace > 0); + jboolean jt = (trace(1)); PGLOBAL& g = m_G; /*******************************************************************/ @@ -770,6 +964,7 @@ int JDBConn::Rewind(PCSZ sql) /***********************************************************************/ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) { + const char *field; PGLOBAL& g = m_G; jint ctyp; jstring cn, jn = nullptr; @@ -793,6 +988,11 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) if (!gmID(g, objfldid, "ObjectField", "(ILjava/lang/String;)Ljava/lang/Object;")) { jb = env->CallObjectMethod(job, objfldid, (jint)rank, jn); + if (Check(0)) { + sprintf(g->Message, "Getting jp: %s", Msg); + throw (int)TYPE_AM_JDBC; + } // endif Check + if (jb == nullptr) { val->Reset(); val->SetNull(true); @@ -818,7 +1018,7 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) cn = nullptr; if (cn) { - const char *field = env->GetStringUTFChars(cn, (jboolean)false); + field = env->GetStringUTFChars(cn, (jboolean)false); val->SetValue_psz((PSZ)field); } else val->Reset(); @@ -885,6 +1085,19 @@ void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val) break; case java.sql.Types.BOOLEAN: System.out.print(jdi.BooleanField(i)); */ + case 1111: // UUID + if (!gmID(g, uidfldid, "UuidField", "(ILjava/lang/String;)Ljava/lang/String;")) + cn = (jstring)env->CallObjectMethod(job, uidfldid, (jint)rank, jn); + else + cn = nullptr; + + if (cn) { + const char *field = env->GetStringUTFChars(cn, (jboolean)false); + val->SetValue_psz((PSZ)field); + } else + val->Reset(); + + break; case 0: // NULL val->SetNull(true); // passthru @@ -1055,7 +1268,14 @@ bool JDBConn::SetParam(JDBCCOL *colp) if (gmID(g, setid, "SetNullParm", "(II)I")) return true; - jrc = env->CallIntMethod(job, setid, i, (jint)GetJDBCType(val->GetType())); + jrc = env->CallIntMethod(job, setid, i, + (colp->uuid ? 1111 : (jint)GetJDBCType(val->GetType()))); + } else if (colp->uuid) { + if (gmID(g, setid, "SetUuidParm", "(ILjava/lang/String;)V")) + return true; + + jst = env->NewStringUTF(val->GetCharValue()); + env->CallVoidMethod(job, setid, i, jst); } else switch (val->GetType()) { case TYPE_STRING: if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V")) @@ -1275,105 +1495,6 @@ bool JDBConn::SetParam(JDBCCOL *colp) } // end of GetMetaData /***********************************************************************/ - /* A helper class to split an optionally qualified table name into */ - /* components. */ - /* These formats are understood: */ - /* "CatalogName.SchemaName.TableName" */ - /* "SchemaName.TableName" */ - /* "TableName" */ - /***********************************************************************/ - class SQLQualifiedName - { - static const uint max_parts= 3; // Catalog.Schema.Table - MYSQL_LEX_STRING m_part[max_parts]; - char m_buf[512]; - - void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length) - { - S->str= str; - S->length= length; - } // end of lex_string_set - - void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs) - { - DBUG_ASSERT(offs <= S->length); - S->str+= offs; - S->length-= offs; - } // end of lex_string_shorten_down - - /*********************************************************************/ - /* Find the rightmost '.' delimiter and return the length */ - /* of the qualifier, including the rightmost '.' delimier. */ - /* For example, for the string {"a.b.c",5} it will return 4, */ - /* which is the length of the qualifier "a.b." */ - /*********************************************************************/ - size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S) - { - size_t i; - for (i= S->length; i > 0; i--) - { - if (S->str[i - 1] == '.') - { - S->str[i - 1]= '\0'; - return i; - } - } - return 0; - } // end of lex_string_find_qualifier - - public: - /*********************************************************************/ - /* Initialize to the given optionally qualified name. */ - /* NULL pointer in "name" is supported. */ - /* name qualifier has precedence over schema. */ - /*********************************************************************/ - SQLQualifiedName(JCATPARM *cap) - { - const char *name = (const char *)cap->Tab; - char *db = (char *)cap->DB; - size_t len, i; - - // Initialize the parts - for (i = 0; i < max_parts; i++) - lex_string_set(&m_part[i], NULL, 0); - - if (name) { - // Initialize the first (rightmost) part - lex_string_set(&m_part[0], m_buf, - strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf); - - // Initialize the other parts, if exist. - for (i= 1; i < max_parts; i++) { - if (!(len= lex_string_find_qualifier(&m_part[i - 1]))) - break; - - lex_string_set(&m_part[i], m_part[i - 1].str, len - 1); - lex_string_shorten_down(&m_part[i - 1], len); - } // endfor i - - } // endif name - - // If it was not specified, set schema as the passed db name - if (db && !m_part[1].length) - lex_string_set(&m_part[1], db, strlen(db)); - - } // end of SQLQualifiedName - - char *ptr(uint i) - { - DBUG_ASSERT(i < max_parts); - return (char *)(m_part[i].length ? m_part[i].str : NULL); - } // end of ptr - - size_t length(uint i) - { - DBUG_ASSERT(i < max_parts); - return m_part[i].length; - } // end of length - - }; // end of class SQLQualifiedName - - /***********************************************************************/ /* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */ /***********************************************************************/ int JDBConn::GetCatInfo(JCATPARM *cap) @@ -1443,7 +1564,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) // Not used anymore env->DeleteLocalRef(parms); - if (trace) + if (trace(1)) htrc("Method %s returned %d columns\n", fnc, ncol); // n because we no more ignore the first column @@ -1488,7 +1609,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) sprintf(g->Message, "Fetch: %s", Msg); return -1; } if (rc == 0) { - if (trace) + if (trace(1)) htrc("End of fetches i=%d\n", i); break; diff --git a/storage/connect/jdbconn.h b/storage/connect/jdbconn.h index 56f318d238b..0c36cccadcf 100644 --- a/storage/connect/jdbconn.h +++ b/storage/connect/jdbconn.h @@ -29,6 +29,7 @@ public: // Attributes public: char *GetQuoteChar(void) { return m_IDQuoteChar; } + bool SetUUID(PGLOBAL g, PTDBJDBC tjp); virtual int GetMaxValue(int infotype); public: @@ -58,13 +59,6 @@ public: protected: // Members -#if 0 - JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine) - JNIEnv *env; // Pointer to native interface - jclass jdi; // Pointer to the java wrapper class - jobject job; // The java wrapper class object - jmethodID errid; // The GetErrmsg method ID -#endif // 0 jmethodID xqid; // The ExecuteQuery method ID jmethodID xuid; // The ExecuteUpdate method ID jmethodID xid; // The Execute method ID @@ -84,8 +78,7 @@ protected: jmethodID timfldid; // The TimeField method ID jmethodID tspfldid; // The TimestampField method ID jmethodID bigfldid; // The BigintField method ID -// PCSZ Msg; -// PCSZ m_Wrap; + jmethodID uidfldid; // The UuidField method ID char m_IDQuoteChar[2]; PCSZ m_Pwd; int m_Ncol; diff --git a/storage/connect/jmgfam.cpp b/storage/connect/jmgfam.cpp index c7115cdd720..30f6279146d 100644 --- a/storage/connect/jmgfam.cpp +++ b/storage/connect/jmgfam.cpp @@ -298,7 +298,7 @@ int JMGFAM::ReadBuffer(PGLOBAL g) PSZ str = Jcp->GetDocument(); if (str) { - if (trace == 1) + if (trace(1)) htrc("%s\n", str); strncpy(Tdbp->GetLine(), str, Lrecl); diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp index 6b70696be74..0f5b18df4b4 100644 --- a/storage/connect/jmgoconn.cpp +++ b/storage/connect/jmgoconn.cpp @@ -254,7 +254,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, all = true; if (pipe && Options) { - if (trace) + if (trace(1)) htrc("Pipeline: %s\n", Options); p = strrchr(Options, ']'); @@ -312,13 +312,13 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, *(char*)p = ']'; // Restore Colist for discovery p = s->GetStr(); - if (trace) + if (trace(33)) htrc("New Pipeline: %s\n", p); return AggregateCollection(p); } else { if (filter || filp) { - if (trace) { + if (trace(1)) { if (filter) htrc("Filter: %s\n", filter); @@ -346,7 +346,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, tdbp->SetFilter(NULL); // Not needed anymore } // endif To_Filter - if (trace) + if (trace(33)) htrc("selector: %s\n", s->GetStr()); s->Resize(s->GetLength() + 1); @@ -355,7 +355,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, if (!all) { if (Options && *Options) { - if (trace) + if (trace(1)) htrc("options=%s\n", Options); op = Options; @@ -751,7 +751,7 @@ int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) jlong ar = env->CallLongMethod(job, updateid, upd); - if (trace) + if (trace(1)) htrc("DocUpdate: ar = %ld\n", ar); if (Check((int)ar)) { @@ -770,7 +770,7 @@ int JMgoConn::DocDelete(PGLOBAL g, bool all) int rc = RC_OK; jlong ar = env->CallLongMethod(job, deleteid, all); - if (trace) + if (trace(1)) htrc("DocDelete: ar = %ld\n", ar); if (Check((int)ar)) { diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index b86d2da21b7..98a4659cea8 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -97,7 +97,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) PJSON jsp = NULL; STRG src; - if (trace) + if (trace(1)) htrc("ParseJson: s=%.10s len=%d\n", s, len); if (!s || !len) { @@ -165,7 +165,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) }; // endswitch s[i] if (!jsp) - sprintf(g->Message, "Invalid Json string '%.*s'", 50, s); + sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN(len, 50), s); else if (ptyp && pretty == 3) { *ptyp = 3; // Not recognized pretty @@ -178,7 +178,7 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma) } // endif ptyp } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); jsp = NULL; } catch (const char *msg) { @@ -652,7 +652,7 @@ PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty) } // endif's } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); str = NULL; } catch (const char *msg) { @@ -1016,6 +1016,20 @@ PJAR JOBJECT::GetKeyList(PGLOBAL g) } // end of GetKeyList /***********************************************************************/ +/* Return all values as an array. */ +/***********************************************************************/ +PJAR JOBJECT::GetValList(PGLOBAL g) +{ + PJAR jarp = new(g) JARRAY(); + + for (PJPR jpp = First; jpp; jpp = jpp->Next) + jarp->AddValue(g, jpp->GetVal()); + + jarp->InitArray(g); + return jarp; +} // end of GetValList + +/***********************************************************************/ /* Get the value corresponding to the given key. */ /***********************************************************************/ PJVAL JOBJECT::GetValue(const char* key) @@ -1224,6 +1238,7 @@ PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp, int *x) Last->Next = jvp; Last = jvp; + Last->Next = NULL; } // endif x return jvp; @@ -1319,6 +1334,24 @@ bool JARRAY::IsNull(void) /* -------------------------- Class JVALUE- -------------------------- */ /***********************************************************************/ +/* Constructor for a JSON. */ +/***********************************************************************/ +JVALUE::JVALUE(PJSON jsp) : JSON() +{ + if (jsp->GetType() == TYPE_JVAL) { + Jsp = jsp->GetJsp(); + Value = jsp->GetValue(); + } else { + Jsp = jsp; + Value = NULL; + } // endif Type + + Next = NULL; + Del = false; + Size = 1; +} // end of JVALUE constructor + +/***********************************************************************/ /* Constructor for a Value with a given string or numeric value. */ /***********************************************************************/ JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() diff --git a/storage/connect/json.h b/storage/connect/json.h index addbd13676f..1d058ad575f 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -20,7 +20,8 @@ enum JTYP {TYPE_NULL = TYPE_VOID, TYPE_BINT = TYPE_BIGINT, TYPE_DTM = TYPE_DATE, TYPE_INTG = TYPE_INT, - TYPE_JSON = 12, + TYPE_VAL = 12, + TYPE_JSON, TYPE_JAR, TYPE_JOB, TYPE_JVAL}; @@ -160,6 +161,7 @@ class JSON : public BLOCK { //virtual PJVAL AddValue(PGLOBAL g, PJVAL jvp = NULL, int *x = NULL) {X return NULL;} virtual PJPR AddPair(PGLOBAL g, PCSZ key) {X return NULL;} virtual PJAR GetKeyList(PGLOBAL g) {X return NULL;} + virtual PJAR GetValList(PGLOBAL g) {X return NULL;} virtual PJVAL GetValue(const char *key) {X return NULL;} virtual PJOB GetObject(void) {return NULL;} virtual PJAR GetArray(void) {return NULL;} @@ -208,6 +210,7 @@ class JOBJECT : public JSON { virtual PJOB GetObject(void) {return this;} virtual PJVAL GetValue(const char* key); virtual PJAR GetKeyList(PGLOBAL g); + virtual PJAR GetValList(PGLOBAL g); virtual PSZ GetText(PGLOBAL g, PSZ text); virtual bool Merge(PGLOBAL g, PJSON jsp); virtual void SetValue(PGLOBAL g, PJVAL jvp, PCSZ key); @@ -261,8 +264,7 @@ class JVALUE : public JSON { friend bool SerializeValue(JOUT *, PJVAL); public: JVALUE(void) : JSON() {Clear();} - JVALUE(PJSON jsp) : JSON() - {Jsp = jsp; Value = NULL; Next = NULL; Del = false; Size = 1;} + JVALUE(PJSON jsp); JVALUE(PGLOBAL g, PVAL valp); JVALUE(PGLOBAL g, PCSZ strp); diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index 91917b48a23..ca51712af0c 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1,6 +1,6 @@ /****************** jsonudf C++ Program Source Code File (.CPP) ******************/ -/* PROGRAM NAME: jsonudf Version 1.6 */ -/* (C) Copyright to the author Olivier BERTRAND 2015-2017 */ +/* PROGRAM NAME: jsonudf Version 1.7 */ +/* (C) Copyright to the author Olivier BERTRAND 2015-2018 */ /* This program are the JSON User Defined Functions . */ /*********************************************************************************/ @@ -31,18 +31,41 @@ bool IsNum(PSZ s); char *NextChr(PSZ s, char sep); char *GetJsonNull(void); uint GetJsonGrpSize(void); -static int IsJson(UDF_ARGS *args, uint i); -static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i); +static int IsJson(UDF_ARGS *args, uint i, bool b = false); +static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i); static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error); static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error); +static PJSON JsonNew(PGLOBAL g, JTYP type); +static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp = NULL); +static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len = 64); void json_array_deinit(UDF_INIT* initid); static uint JsonGrpSize = 10; -/* ----------------------------------- JSNX ------------------------------------ */ +/*********************************************************************************/ +/* SubAlloc a new JSNX class with protection against memory exhaustion. */ +/*********************************************************************************/ +static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len) +{ + PJSNX jsx; + + try { + jsx = new(g) JSNX(g, jsp, type, len); + } catch (...) { + if (trace(1023)) + htrc("%s\n", g->Message); + + PUSH_WARNING(g->Message); + jsx = NULL; + } // end try/catch + + return jsx; +} /* end of JsnxNew */ + + /* ----------------------------------- JSNX ------------------------------------ */ /*********************************************************************************/ /* JSNX public constructor. */ @@ -83,21 +106,7 @@ my_bool JSNX::SetJpath(PGLOBAL g, char *path, my_bool jb) return true; Value->SetNullable(true); - -#if 0 - if (jb) { - // Path must return a Json item - size_t n = strlen(path); - - if (!n || path[n - 1] != '*') { - Jpath = (char*)PlugSubAlloc(g, NULL, n + 3); - strcat(strcpy(Jpath, path), (n) ? ":*" : "*"); - } else - Jpath = path; - - } else -#endif // 0 - Jpath = path; + Jpath = path; // Parse the json path Parsed = false; @@ -184,7 +193,7 @@ my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) // Set concat intermediate string p[n - 1] = 0; - if (trace) + if (trace(1)) htrc("Concat string=%s\n", p + 1); jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); @@ -248,7 +257,7 @@ my_bool JSNX::ParseJpath(PGLOBAL g) // Jpath = Name; return true; - if (trace) + if (trace(1)) htrc("ParseJpath %s\n", SVP(Jpath)); if (!(pbuf = PlgDBDup(g, Jpath))) @@ -311,7 +320,7 @@ my_bool JSNX::ParseJpath(PGLOBAL g) Nod = i; MulVal = AllocateValue(g, Value); - if (trace) + if (trace(1)) for (i = 0; i < Nod; i++) htrc("Node(%d) Key=%s Op=%d Rank=%d\n", i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank); @@ -508,13 +517,13 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n) vp->Reset(); - if (trace) + if (trace(1)) htrc("CalculateArray size=%d op=%d\n", ars, op); for (i = 0; i < ars; i++) { jvrp = arp->GetValue(i); - if (trace) + if (trace(1)) htrc("i=%d nv=%d\n", i, nv); if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) { @@ -527,7 +536,7 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n) } else jvp = jvrp; - if (trace) + if (trace(1)) htrc("jvp=%s null=%d\n", jvp->GetString(g), jvp->IsNull() ? 1 : 0); @@ -563,7 +572,7 @@ PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n) if (err) vp->Reset(); - if (trace) { + if (trace(1)) { char buf(32); htrc("vp='%s' err=%d\n", @@ -755,6 +764,7 @@ my_bool JSNX::WriteValue(PGLOBAL g, PJVAL jvalp) /*********************************************************************************/ PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k) { + PSZ str = NULL; my_bool b = false, err = true; g->Message[0] = 0; @@ -764,37 +774,47 @@ PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k) return NULL; } // endif jsp - // Write to the path string - Jp = new(g) JOUTSTR(g); - Jp->WriteChr('$'); - Jvalp = jvp; - K = k; + try { + // Write to the path string + Jp = new(g) JOUTSTR(g); + Jp->WriteChr('$'); + Jvalp = jvp; + K = k; - switch (jsp->GetType()) { - case TYPE_JAR: - err = LocateArray((PJAR)jsp); - break; - case TYPE_JOB: - err = LocateObject((PJOB)jsp); - break; - case TYPE_JVAL: - err = LocateValue((PJVAL)jsp); - break; - default: - err = true; + switch (jsp->GetType()) { + case TYPE_JAR: + err = LocateArray((PJAR)jsp); + break; + case TYPE_JOB: + err = LocateObject((PJOB)jsp); + break; + case TYPE_JVAL: + err = LocateValue((PJVAL)jsp); + break; + default: + err = true; } // endswitch Type - if (err) { - if (!g->Message[0]) - strcpy(g->Message, "Invalid json tree"); + if (err) { + if (!g->Message[0]) + strcpy(g->Message, "Invalid json tree"); - } else if (Found) { - Jp->WriteChr('\0'); - PlugSubAlloc(g, NULL, Jp->N); - return Jp->Strp; - } // endif's + } else if (Found) { + Jp->WriteChr('\0'); + PlugSubAlloc(g, NULL, Jp->N); + str = Jp->Strp; + } // endif's - return NULL; + } catch (int n) { + if (trace(1)) + htrc("Exception %d: %s\n", n, g->Message); + + PUSH_WARNING(g->Message); + } catch (const char *msg) { + strcpy(g->Message, msg); + } // end catch + + return str; } // end of Locate /*********************************************************************************/ @@ -866,53 +886,62 @@ my_bool JSNX::LocateValue(PJVAL jvp) /*********************************************************************************/ PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx) { + PSZ str = NULL; my_bool b = false, err = true; - PJPN jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx); - - memset(jnp, 0, sizeof(JPN) * mx); - g->Message[0] = 0; - + PJPN jnp; + if (!jsp) { strcpy(g->Message, "Null json tree"); return NULL; } // endif jsp - // Write to the path string - Jp = new(g)JOUTSTR(g); - Jvalp = jvp; - Imax = mx - 1; - Jpnp = jnp; - Jp->WriteChr('['); + try { + jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx); + memset(jnp, 0, sizeof(JPN) * mx); + g->Message[0] = 0; + + // Write to the path string + Jp = new(g)JOUTSTR(g); + Jvalp = jvp; + Imax = mx - 1; + Jpnp = jnp; + Jp->WriteChr('['); + + switch (jsp->GetType()) { + case TYPE_JAR: + err = LocateArrayAll((PJAR)jsp); + break; + case TYPE_JOB: + err = LocateObjectAll((PJOB)jsp); + break; + case TYPE_JVAL: + err = LocateValueAll((PJVAL)jsp); + break; + default: + err = true; + } // endswitch Type - switch (jsp->GetType()) { - case TYPE_JAR: - err = LocateArrayAll((PJAR)jsp); - break; - case TYPE_JOB: - err = LocateObjectAll((PJOB)jsp); - break; - case TYPE_JVAL: - err = LocateValueAll((PJVAL)jsp); - break; - default: - err = true; - } // endswitch Type + if (!err) { + if (Jp->N > 1) + Jp->N--; - if (err) { - if (!g->Message[0]) + Jp->WriteChr(']'); + Jp->WriteChr('\0'); + PlugSubAlloc(g, NULL, Jp->N); + str = Jp->Strp; + } else if (!g->Message[0]) strcpy(g->Message, "Invalid json tree"); - return NULL; - } else { - if (Jp->N > 1) - Jp->N--; + } catch (int n) { + if (trace(1)) + htrc("Exception %d: %s\n", n, g->Message); - Jp->WriteChr(']'); - Jp->WriteChr('\0'); - PlugSubAlloc(g, NULL, Jp->N); - return Jp->Strp; - } // endif's + PUSH_WARNING(g->Message); + } catch (const char *msg) { + strcpy(g->Message, msg); + } // end catch + return str; } // end of LocateAll /*********************************************************************************/ @@ -1140,6 +1169,72 @@ inline void JsonFreeMem(PGLOBAL g) } /* end of JsonFreeMem */ /*********************************************************************************/ +/* SubAlloc a new JSON item with protection against memory exhaustion. */ +/*********************************************************************************/ +static PJSON JsonNew(PGLOBAL g, JTYP type) +{ + PJSON jsp = NULL; + + try { + switch (type) { + case TYPE_JAR: + jsp = new(g) JARRAY; + break; + case TYPE_JOB: + jsp = new(g) JOBJECT; + break; + default: + break; + } // endswitch type + + } catch (...) { + if (trace(1023)) + htrc("%s\n", g->Message); + + PUSH_WARNING(g->Message); + } // end try/catch + + return jsp; +} /* end of JsonNew */ + +/*********************************************************************************/ +/* SubAlloc a new JValue with protection against memory exhaustion. */ +/*********************************************************************************/ +static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp) +{ + PJVAL jvp = NULL; + + try { + if (!vp) + jvp = new (g) JVALUE; + else switch (type) { + case TYPE_JSON: + case TYPE_JVAL: + case TYPE_JAR: + case TYPE_JOB: + jvp = new(g) JVALUE((PJSON)vp); + break; + case TYPE_VAL: + jvp = new(g) JVALUE(g, (PVAL)vp); + break; + case TYPE_STRG: + jvp = new(g) JVALUE(g, (PCSZ)vp); + break; + default: + break; + } // endswitch type + + } catch (...) { + if (trace(1023)) + htrc("%s\n", g->Message); + + PUSH_WARNING(g->Message); + } // end try/catch + + return jvp; +} /* end of JsonNew */ + +/*********************************************************************************/ /* Allocate and initialise the memory area. */ /*********************************************************************************/ static my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, @@ -1291,8 +1386,11 @@ static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n) for (uint i = n; i < args->arg_count; i++) if (args->arg_type[i] == INT_RESULT) { if (args->args[i]) { - x = (int*)PlugSubAlloc(g, NULL, sizeof(int)); - *x = (int)*(longlong*)args->args[i]; + if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int)))) + *x = (int)*(longlong*)args->args[i]; + else + PUSH_WARNING(g->Message); + } // endif args n = i + 1; @@ -1305,7 +1403,7 @@ static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n) /*********************************************************************************/ /* Returns not 0 if the argument is a JSON item or file name. */ /*********************************************************************************/ -static int IsJson(UDF_ARGS *args, uint i) +static int IsJson(UDF_ARGS *args, uint i, bool b) { int n = 0; @@ -1322,8 +1420,20 @@ static int IsJson(UDF_ARGS *args, uint i) else n = 2; // A file name may have been returned - } else if (!strnicmp(args->attributes[i], "Jfile_", 6)) + } else if (!strnicmp(args->attributes[i], "Jfile_", 6)) { n = 2; // arg is a json file name + } else if (b) { + char *sap; + PGLOBAL g = PlugInit(NULL, args->lengths[i] * M + 1024); + + JsonSubSet(g); + sap = MakePSZ(g, args, i); + + if (ParseJson(g, sap, strlen(sap))) + n = 4; + + JsonFreeMem(g); + } // endif's return n; } // end of IsJson @@ -1536,10 +1646,14 @@ static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i) { if (args->arg_count > (unsigned)i && args->args[i]) { int n = args->lengths[i]; - PSZ s = (PSZ)PlugSubAlloc(g, NULL, n + 1); + PSZ s = (PSZ)PlgDBSubAlloc(g, NULL, n + 1); + + if (s) { + memcpy(s, args->args[i], n); + s[n] = 0; + } else + PUSH_WARNING(g->Message); - memcpy(s, args->args[i], n); - s[n] = 0; return s; } else return NULL; @@ -1577,9 +1691,12 @@ static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i) return (char*) "Key"; if (!b) { - p = (PSZ)PlugSubAlloc(g, NULL, n + 1); - memcpy(p, s, n); - p[n] = 0; + if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) { + memcpy(p, s, n); + p[n] = 0; + } else + PUSH_WARNING(g->Message); + s = p; } // endif b @@ -1668,15 +1785,16 @@ static char *GetJsonFile(PGLOBAL g, char *fn) return NULL; } // endif len - str = (char*)PlugSubAlloc(g, NULL, len + 1); - - if ((n = read(h, str, len)) < 0) { - sprintf(g->Message, "Error %d reading %d bytes from %s", errno, len, fn); - return NULL; - } // endif n + if ((str = (char*)PlgDBSubAlloc(g, NULL, len + 1))) { + if ((n = read(h, str, len)) < 0) { + sprintf(g->Message, "Error %d reading %d bytes from %s", errno, len, fn); + return NULL; + } // endif n - str[n] = 0; - close(h); + str[n] = 0; + close(h); + } // endif str + return str; } // end of GetJsonFile @@ -1763,6 +1881,41 @@ static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, uint i, PJSON *top = NULL) } // end of MakeValue /*********************************************************************************/ +/* Try making a JSON value of the passed type from the passed argument. */ +/*********************************************************************************/ +static PJVAL MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i, + JTYP type, PJSON *top = NULL) +{ + char *sap; + PJSON jsp; + PJVAL jvp = MakeValue(g, args, i, top); + + //if (type == TYPE_JSON) { + // if (jvp->GetValType() >= TYPE_JSON) + // return jvp; + + //} else if (jvp->GetValType() == type) + // return jvp; + + if (jvp->GetValType() == TYPE_STRG) { + sap = jvp->GetString(g); + + if ((jsp = ParseJson(g, sap, strlen(sap)))) { + if ((type == TYPE_JSON && jsp->GetType() != TYPE_JVAL) || jsp->GetType() == type) { + if (top) + *top = jsp; + + jvp->SetValue(jsp); + } // endif Type + + } // endif jsp + + } // endif Type + + return jvp; +} // end of MakeTypedValue + +/*********************************************************************************/ /* Make a Json value containing the parameter. */ /*********************************************************************************/ my_bool jsonvalue_init(UDF_INIT *initid, UDF_ARGS *args, char *message) @@ -1864,9 +2017,9 @@ my_bool json_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *messa if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); return true; - } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) { - strcpy(message, "First argument must be a json string or item"); - return true; + //} else if (!IsJson(args, 0, true)) { + // strcpy(message, "First argument must be a valid json string or item"); + // return true; } else CalcLen(args, false, reslen, memlen); @@ -1894,23 +2047,14 @@ char *json_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, true)) { - char *p; PJSON top; PJAR arp; - PJVAL jvp = MakeValue(g, args, 0, &top); + PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top); - if ((p = jvp->GetString(g))) { - if (!(top = ParseJson(g, p, strlen(p)))) { - PUSH_WARNING(g->Message); - return NULL; - } // endif jsp - - jvp->SetValue(top); - } // endif p - if (jvp->GetValType() != TYPE_JAR) { arp = new(g)JARRAY; arp->AddValue(g, jvp); + top = arp; } else arp = jvp->GetArray(); @@ -1918,7 +2062,6 @@ char *json_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result, arp->AddValue(g, MakeValue(g, args, i)); arp->InitArray(g); -// str = Serialize(g, arp, NULL, 0); str = MakeResult(g, args, top, args->arg_count); } // endif CheckMemory @@ -1955,10 +2098,10 @@ my_bool json_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message) if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); - return true; - } else if (!IsJson(args, 0)) { - strcpy(message, "First argument must be a json item"); - return true; + return true; + //} else if (!IsJson(args, 0, true)) { + // strcpy(message, "First argument is not a valid Json item"); + // return true; } else CalcLen(args, false, reslen, memlen, true); @@ -1997,22 +2140,38 @@ char *json_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result, PJVAL jvp; PJAR arp; - jvp = MakeValue(g, args, 0, &top); + jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top); jsp = jvp->GetJson(); x = GetIntArgPtr(g, args, n); if (CheckPath(g, args, jsp, jvp, 2)) PUSH_WARNING(g->Message); - else if (jvp && jvp->GetValType() == TYPE_JAR) { + else if (jvp) { PGLOBAL gb = GetMemPtr(g, args, 0); - arp = jvp->GetArray(); - arp->AddValue(gb, MakeValue(gb, args, 1), x); - arp->InitArray(gb); - str = MakeResult(g, args, top, n); + if (jvp->GetValType() != TYPE_JAR) { + if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) { + arp->AddValue(gb, JvalNew(gb, TYPE_JVAL, jvp)); + jvp->SetValue(arp); + + if (!top) + top = arp; + + } // endif arp + + } else + arp = jvp->GetArray(); + + if (arp) { + arp->AddValue(gb, MakeValue(gb, args, 1), x); + arp->InitArray(gb); + str = MakeResult(g, args, top, n); + } else + PUSH_WARNING(gb->Message); + } else { - PUSH_WARNING("First argument target is not an array"); -// if (g->Mrr) *error = 1; (only if no path) + PUSH_WARNING("Target is not an array"); + // if (g->Mrr) *error = 1; (only if no path) } // endif jvp } // endif CheckMemory @@ -2051,9 +2210,6 @@ my_bool json_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message) if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); return true; - } else if (!IsJson(args, 0)) { - strcpy(message, "First argument must be a json item"); - return true; } else CalcLen(args, false, reslen, memlen, true); @@ -2090,7 +2246,7 @@ char *json_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result, uint n = 1; PJSON top; PJAR arp; - PJVAL jvp = MakeValue(g, args, 0, &top); + PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top); if (!(x = GetIntArgPtr(g, args, n))) PUSH_WARNING("Missing or null array index"); @@ -2189,9 +2345,14 @@ long long jsonsum_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *err if (g->N) { // Keep result of constant function - long long *np = (long long*)PlugSubAlloc(g, NULL, sizeof(long long)); - *np = n; - g->Activityp = (PACTIVITY)np; + long long *np; + + if ((np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)))) { + *np = n; + g->Activityp = (PACTIVITY)np; + } else + PUSH_WARNING(g->Message); + } // endif const_item return n; @@ -2255,13 +2416,21 @@ double jsonsum_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error } else { *error = 1; n = -1.0; - } // end of CheckMemory + } // endif CheckMemory if (g->N) { // Keep result of constant function - double *np = (double*)PlugSubAlloc(g, NULL, sizeof(double)); - *np = n; - g->Activityp = (PACTIVITY)np; + double *np; + + if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) { + *np = n; + g->Activityp = (PACTIVITY)np; + } else { + PUSH_WARNING(g->Message); + *error = 1; + n = -1.0; + } // endif np + } // endif const_item return n; @@ -2315,13 +2484,20 @@ double jsonavg_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error } else { *error = 1; n = -1.0; - } // end of CheckMemory + } // endif CheckMemory if (g->N) { // Keep result of constant function - double *np = (double*)PlugSubAlloc(g, NULL, sizeof(double)); - *np = n; - g->Activityp = (PACTIVITY)np; + double *np; + + if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) { + *np = n; + g->Activityp = (PACTIVITY)np; + } else { + *error = 1; + n = -1.0; + } // endif np + } // endif const_item return n; @@ -2351,12 +2527,15 @@ char *json_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) { - PJOB objp = new(g)JOBJECT; + PJOB objp; + + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i++) + objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i)); - for (uint i = 0; i < args->arg_count; i++) - objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i)); + str = Serialize(g, objp, NULL, 0); + } // endif objp - str = Serialize(g, objp, NULL, 0); } // endif CheckMemory if (!str) @@ -2397,13 +2576,16 @@ char *json_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) { PJVAL jvp; - PJOB objp = new(g)JOBJECT; + PJOB objp; + + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i++) + if (!(jvp = MakeValue(g, args, i))->IsNull()) + objp->SetValue(g, jvp, MakeKey(g, args, i)); - for (uint i = 0; i < args->arg_count; i++) - if (!(jvp = MakeValue(g, args, i))->IsNull()) - objp->SetValue(g, jvp, MakeKey(g, args, i)); + str = Serialize(g, objp, NULL, 0); + } // endif objp - str = Serialize(g, objp, NULL, 0); } // endif CheckMemory if (!str) @@ -2447,12 +2629,15 @@ char *json_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!g->Xchk) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) { - PJOB objp = new(g)JOBJECT; + PJOB objp; + + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i += 2) + objp->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i)); - for (uint i = 0; i < args->arg_count; i += 2) - objp->SetValue(g, MakeValue(g, args, i+1), MakePSZ(g, args, i)); + str = Serialize(g, objp, NULL, 0); + } // endif objp - str = Serialize(g, objp, NULL, 0); } // endif CheckMemory if (!str) @@ -2735,6 +2920,82 @@ void json_object_list_deinit(UDF_INIT* initid) } // end of json_object_list_deinit /*********************************************************************************/ +/* Returns an array of the Json object values. */ +/*********************************************************************************/ +my_bool json_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +{ + unsigned long reslen, memlen; + + if (args->arg_count != 1) { + strcpy(message, "This function must have 1 argument"); + return true; + } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) { + strcpy(message, "Argument must be a json object"); + return true; + } else + CalcLen(args, false, reslen, memlen); + + return JsonInit(initid, args, message, true, reslen, memlen); +} // end of json_object_list_init + +char *json_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result, + unsigned long *res_length, char *is_null, char *error) +{ + char *str = NULL; + PGLOBAL g = (PGLOBAL)initid->ptr; + + if (!g->N) { + if (!CheckMemory(g, initid, args, 1, true, true)) { + char *p; + PJSON jsp; + PJVAL jvp = MakeValue(g, args, 0); + + if ((p = jvp->GetString(g))) { + if (!(jsp = ParseJson(g, p, strlen(p)))) { + PUSH_WARNING(g->Message); + return NULL; + } // endif jsp + + } else + jsp = jvp->GetJson(); + + if (jsp->GetType() == TYPE_JOB) { + PJAR jarp = ((PJOB)jsp)->GetValList(g); + + if (!(str = Serialize(g, jarp, NULL, 0))) + PUSH_WARNING(g->Message); + + } else { + PUSH_WARNING("First argument is not an object"); + if (g->Mrr) *error = 1; + } // endif jvp + + } // endif CheckMemory + + if (initid->const_item) { + // Keep result of constant function + g->Xchk = str; + g->N = 1; // str can be NULL + } // endif const_item + + } else + str = (char*)g->Xchk; + + if (!str) { + *is_null = 1; + *res_length = 0; + } else + *res_length = strlen(str); + + return str; +} // end of json_object_values + +void json_object_values_deinit(UDF_INIT* initid) +{ + JsonFreeMem((PGLOBAL)initid->ptr); +} // end of json_object_values_deinit + +/*********************************************************************************/ /* Set the value of JsonGrpSize. */ /*********************************************************************************/ my_bool jsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message) @@ -2798,7 +3059,7 @@ my_bool json_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) PGLOBAL g = (PGLOBAL)initid->ptr; PlugSubSet(g, g->Sarea, g->Sarea_Size); - g->Activityp = (PACTIVITY)new(g) JARRAY; + g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR); g->N = (int)n; return false; } // end of json_array_grp_init @@ -2808,7 +3069,7 @@ void json_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*) PGLOBAL g = (PGLOBAL)initid->ptr; PJAR arp = (PJAR)g->Activityp; - if (g->N-- > 0) + if (arp && g->N-- > 0) arp->AddValue(g, MakeValue(g, args, 0)); } // end of json_array_grp_add @@ -2823,12 +3084,16 @@ char *json_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result, if (g->N < 0) PUSH_WARNING("Result truncated to json_grp_size values"); - arp->InitArray(g); + if (arp) { + arp->InitArray(g); + str = Serialize(g, arp, NULL, 0); + } else + str = NULL; - if (!(str = Serialize(g, arp, NULL, 0))) - str = strcpy(result, g->Message); + if (!str) + str = strcpy(result, g->Message); - *res_length = strlen(str); + *res_length = strlen(str); return str; } // end of json_array_grp @@ -2837,8 +3102,8 @@ void json_array_grp_clear(UDF_INIT *initid, char*, char*) PGLOBAL g = (PGLOBAL)initid->ptr; PlugSubSet(g, g->Sarea, g->Sarea_Size); - g->Activityp = (PACTIVITY)new(g) JARRAY; - g->N = GetJsonGroupSize(); + g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR); + g->N = GetJsonGroupSize(); } // end of json_array_grp_clear void json_array_grp_deinit(UDF_INIT* initid) @@ -2871,7 +3136,7 @@ my_bool json_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) PGLOBAL g = (PGLOBAL)initid->ptr; PlugSubSet(g, g->Sarea, g->Sarea_Size); - g->Activityp = (PACTIVITY)new(g) JOBJECT; + g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB); g->N = (int)n; return false; } // end of json_object_grp_init @@ -2896,7 +3161,7 @@ char *json_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result, if (g->N < 0) PUSH_WARNING("Result truncated to json_grp_size values"); - if (!(str = Serialize(g, objp, NULL, 0))) + if (!objp || !(str = Serialize(g, objp, NULL, 0))) str = strcpy(result, g->Message); *res_length = strlen(str); @@ -2908,8 +3173,8 @@ void json_object_grp_clear(UDF_INIT *initid, char*, char*) PGLOBAL g = (PGLOBAL)initid->ptr; PlugSubSet(g, g->Sarea, g->Sarea_Size); - g->Activityp = (PACTIVITY)new(g) JOBJECT; - g->N = GetJsonGroupSize(); + g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB); + g->N = GetJsonGroupSize(); } // end of json_object_grp_clear void json_object_grp_deinit(UDF_INIT* initid) @@ -3054,7 +3319,7 @@ my_bool json_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message) char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *) { - char *p, *path, *str = NULL; + char *path, *str = NULL; PJSON jsp; PJVAL jvp; PJSNX jsx; @@ -3070,17 +3335,10 @@ char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, if (CheckMemory(g, initid, args, 1, true, true)) { PUSH_WARNING("CheckMemory error"); goto fin; - } else - jvp = MakeValue(g, args, 0); - - if ((p = jvp->GetString(g))) { - if (!(jsp = ParseJson(g, p, strlen(p)))) { - PUSH_WARNING(g->Message); - return NULL; - } // endif jsp + } // endif CheckMemory - } else - jsp = jvp->GetJson(); + jvp = MakeTypedValue(g, args, 0, TYPE_JSON); + jsp = jvp->GetJson(); if (g->Mrr) { // First argument is a constant g->Xchk = jsp; @@ -3091,9 +3349,9 @@ char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g) JSNX(g, jsp, TYPE_STRING, initid->max_length); + jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length); - if (jsx->SetJpath(g, path, true)) { + if (!jsx || jsx->SetJpath(g, path, true)) { PUSH_WARNING(g->Message); *is_null = 1; return NULL; @@ -3206,9 +3464,9 @@ char *jsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g) JSNX(g, jsp, TYPE_STRING, initid->max_length); + jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length); - if (jsx->SetJpath(g, path)) { + if (!jsx || jsx->SetJpath(g, path)) { PUSH_WARNING(g->Message); goto err; } // endif SetJpath @@ -3223,7 +3481,7 @@ char *jsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result, g->Activityp = (PACTIVITY)str; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); PUSH_WARNING(g->Message); @@ -3323,9 +3581,9 @@ long long jsonget_int(UDF_INIT *initid, UDF_ARGS *args, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g) JSNX(g, jsp, TYPE_BIGINT); + jsx = JsnxNew(g, jsp, TYPE_BIGINT); - if (jsx->SetJpath(g, path)) { + if (!jsx || jsx->SetJpath(g, path)) { PUSH_WARNING(g->Message); *is_null = 1; return 0; @@ -3342,9 +3600,14 @@ long long jsonget_int(UDF_INIT *initid, UDF_ARGS *args, if (initid->const_item) { // Keep result of constant function - long long *np = (long long*)PlugSubAlloc(g, NULL, sizeof(long long)); - *np = n; - g->Activityp = (PACTIVITY)np; + long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)); + + if (np) { + *np = n; + g->Activityp = (PACTIVITY)np; + } else + PUSH_WARNING(g->Message); + } // endif const_item return n; @@ -3437,9 +3700,9 @@ double jsonget_real(UDF_INIT *initid, UDF_ARGS *args, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g) JSNX(g, jsp, TYPE_DOUBLE); + jsx = JsnxNew(g, jsp, TYPE_DOUBLE); - if (jsx->SetJpath(g, path)) { + if (!jsx || jsx->SetJpath(g, path)) { PUSH_WARNING(g->Message); *is_null = 1; return 0.0; @@ -3456,9 +3719,17 @@ double jsonget_real(UDF_INIT *initid, UDF_ARGS *args, if (initid->const_item) { // Keep result of constant function - double *dp = (double*)PlugSubAlloc(g, NULL, sizeof(double)); - *dp = d; - g->Activityp = (PACTIVITY)dp; + double *dp; + + if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) { + *dp = d; + g->Activityp = (PACTIVITY)dp; + } else { + PUSH_WARNING(g->Message); + *is_null = 1; + return 0.0; + } // endif dp + } // endif const_item return d; @@ -3504,7 +3775,7 @@ my_bool jsonlocate_init(UDF_INIT *initid, UDF_ARGS *args, char *message) char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error) { - char *p, *path = NULL; + char *path = NULL; int k; PJVAL jvp, jvp2; PJSON jsp; @@ -3532,16 +3803,20 @@ char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result, *error = 1; goto err; } else - jvp = MakeValue(g, args, 0); - - if ((p = jvp->GetString(g))) { - if (!(jsp = ParseJson(g, p, strlen(p)))) { - PUSH_WARNING(g->Message); - goto err; - } // endif jsp - - } else - jsp = jvp->GetJson(); + jvp = MakeTypedValue(g, args, 0, TYPE_JSON); + + //if ((p = jvp->GetString(g))) { + // if (!(jsp = ParseJson(g, p, strlen(p)))) { + // PUSH_WARNING(g->Message); + // goto err; + // } // endif jsp + //} else + // jsp = jvp->GetJson(); + + if (!(jsp = jvp->GetJson())) { + PUSH_WARNING("First argument is not a valid JSON item"); + goto err; + } // endif jsp if (g->Mrr) { // First argument is a constant g->Xchk = jsp; @@ -3564,7 +3839,7 @@ char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result, g->Activityp = (PACTIVITY)path; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); PUSH_WARNING(g->Message); @@ -3689,7 +3964,7 @@ char *json_locate_all(UDF_INIT *initid, UDF_ARGS *args, char *result, g->Activityp = (PACTIVITY)path; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); PUSH_WARNING(g->Message); @@ -3848,9 +4123,9 @@ long long jsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *result, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g)JSNX(g, jsp, TYPE_BIGINT); + jsx = JsnxNew(g, jsp, TYPE_BIGINT); - if (jsx->SetJpath(g, path)) { + if (!jsx || jsx->SetJpath(g, path)) { PUSH_WARNING(g->Message); goto err; } // endif SetJpath @@ -3859,9 +4134,14 @@ long long jsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *result, if (initid->const_item) { // Keep result of constant function - long long *np = (long long*)PlugSubAlloc(g, NULL, sizeof(long long)); - *np = n; - g->Activityp = (PACTIVITY)np; + long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)); + + if (np) { + *np = n; + g->Activityp = (PACTIVITY)np; + } else + PUSH_WARNING(g->Message); + } // endif const_item return n; @@ -3964,7 +4244,7 @@ char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result, g->Activityp = (PACTIVITY)str; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); PUSH_WARNING(g->Message); @@ -4338,18 +4618,23 @@ char *jbin_array(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, false)) { - PJAR arp = new(g) JARRAY; + PJAR arp; - bsp = JbinAlloc(g, args, initid->max_length, arp); - strcat(bsp->Msg, " array"); + if ((arp = (PJAR)JsonNew(g, TYPE_JAR)) && + (bsp = JbinAlloc(g, args, initid->max_length, arp))) { + strcat(bsp->Msg, " array"); - for (uint i = 0; i < args->arg_count; i++) - arp->AddValue(g, MakeValue(g, args, i)); + for (uint i = 0; i < args->arg_count; i++) + arp->AddValue(g, MakeValue(g, args, i)); + + arp->InitArray(g); + } // endif arp && bsp - arp->InitArray(g); } else - if ((bsp = JbinAlloc(g, args, initid->max_length, NULL))) - strncpy(bsp->Msg, g->Message, 139); + bsp = NULL; + + if (!bsp && (bsp = JbinAlloc(g, args, initid->max_length, NULL))) + strncpy(bsp->Msg, g->Message, 139); // Keep result of constant function g->Xchk = (initid->const_item) ? bsp : NULL; @@ -4380,9 +4665,6 @@ my_bool jbin_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *messa if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); return true; - } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) { - strcpy(message, "First argument must be a json string or item"); - return true; } else CalcLen(args, false, reslen, memlen); @@ -4397,24 +4679,17 @@ char *jbin_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, true)) { - char *p; PJSON top; PJAR arp; - PJVAL jvp = MakeValue(g, args, 0, &top); + PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top); PGLOBAL gb = GetMemPtr(g, args, 0); - if ((p = jvp->GetString(g))) { - if (!(top = ParseJson(g, p, strlen(p)))) { - PUSH_WARNING(g->Message); - return NULL; - } // endif jsp - - jvp->SetValue(top); - } // endif p - if (jvp->GetValType() != TYPE_JAR) { - arp = new(gb)JARRAY; - arp->AddValue(gb, jvp); + if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) { + arp->AddValue(gb, jvp); + top = arp; + } // endif arp + } else arp = jvp->GetArray(); @@ -4461,9 +4736,9 @@ my_bool jbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message) if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); return true; - } else if (!IsJson(args, 0)) { - strcpy(message, "First argument must be a json item"); - return true; + //} else if (!IsJson(args, 0)) { + // strcpy(message, "First argument must be a json item"); + // return true; } else CalcLen(args, false, reslen, memlen, true); @@ -4491,20 +4766,32 @@ char *jbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result, PJVAL jvp; PJAR arp; - jvp = MakeValue(g, args, 0, &top); -// jsp = jvp->GetJson(); + jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top); + // jsp = jvp->GetJson(); x = GetIntArgPtr(g, args, n); if (CheckPath(g, args, top, jvp, n)) PUSH_WARNING(g->Message); - else if (jvp && jvp->GetValType() == TYPE_JAR) { + else if (jvp) { PGLOBAL gb = GetMemPtr(g, args, 0); - arp = jvp->GetArray(); + if (jvp->GetValType() != TYPE_JAR) { + if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) { + arp->AddValue(gb, (PJVAL)JvalNew(gb, TYPE_JVAL, jvp)); + jvp->SetValue(arp); + + if (!top) + top = arp; + + } // endif arp + + } else + arp = jvp->GetArray(); + arp->AddValue(gb, MakeValue(gb, args, 1), x); arp->InitArray(gb); } else { - PUSH_WARNING("First argument is not an array"); + PUSH_WARNING("First argument target is not an array"); // if (g->Mrr) *error = 1; (only if no path) } // endif jvp @@ -4542,9 +4829,6 @@ my_bool jbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message) if (args->arg_count < 2) { strcpy(message, "This function must have at least 2 arguments"); return true; - } else if (!IsJson(args, 0)) { - strcpy(message, "First argument must be a json item"); - return true; } else CalcLen(args, false, reslen, memlen, true); @@ -4568,7 +4852,7 @@ char *jbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result, int *x; uint n = 1; PJAR arp; - PJVAL jvp = MakeValue(g, args, 0, &top); + PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top); if (CheckPath(g, args, top, jvp, 1)) PUSH_WARNING(g->Message); @@ -4581,8 +4865,8 @@ char *jbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result, PUSH_WARNING("Missing or null array index"); } else { - PUSH_WARNING("First argument is not an array"); - if (g->Mrr) *error = 1; + PUSH_WARNING("First argument target is not an array"); +// if (g->Mrr) *error = 1; } // endif jvp } // endif CheckMemory @@ -4628,13 +4912,18 @@ char *jbin_object(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, true)) { - PJOB objp = new(g)JOBJECT; + PJOB objp; - for (uint i = 0; i < args->arg_count; i++) - objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i)); + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i++) + objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i)); + + + if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) + strcat(bsp->Msg, " object"); - if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) - strcat(bsp->Msg, " object"); + } else + bsp = NULL; } else if ((bsp = JbinAlloc(g, args, initid->max_length, NULL))) @@ -4679,14 +4968,18 @@ char *jbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) { PJVAL jvp; - PJOB objp = new(g)JOBJECT; + PJOB objp; - for (uint i = 0; i < args->arg_count; i++) - if (!(jvp = MakeValue(g, args, i))->IsNull()) - objp->SetValue(g, jvp, MakeKey(g, args, i)); + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i++) + if (!(jvp = MakeValue(g, args, i))->IsNull()) + objp->SetValue(g, jvp, MakeKey(g, args, i)); - if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) - strcat(bsp->Msg, " object"); + if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) + strcat(bsp->Msg, " object"); + + } else + bsp = NULL; } else if ((bsp = JbinAlloc(g, args, initid->max_length, NULL))) @@ -4735,13 +5028,17 @@ char *jbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result, if (!bsp || bsp->Changed) { if (!CheckMemory(g, initid, args, args->arg_count, false, true)) { - PJOB objp = new(g)JOBJECT; + PJOB objp; + + if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) { + for (uint i = 0; i < args->arg_count; i += 2) + objp->SetValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i)); - for (uint i = 0; i < args->arg_count; i += 2) - objp->SetValue(g, MakeValue(g, args, i+1), MakePSZ(g, args, i)); + if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) + strcat(bsp->Msg, " object"); - if ((bsp = JbinAlloc(g, args, initid->max_length, objp))) - strcat(bsp->Msg, " object"); + } else + bsp = NULL; } else if ((bsp = JbinAlloc(g, args, initid->max_length, NULL))) @@ -4992,7 +5289,7 @@ my_bool jbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message) char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *res_length, char *is_null, char *error) { - char *p, *path; + char *path; PJSON jsp; PJSNX jsx; PJVAL jvp; @@ -5009,17 +5306,10 @@ char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, if (CheckMemory(g, initid, args, 1, true, true)) { PUSH_WARNING("CheckMemory error"); goto fin; - } else - jvp = MakeValue(g, args, 0); - - if ((p = jvp->GetString(g))) { - if (!(jsp = ParseJson(g, p, strlen(p)))) { - PUSH_WARNING(g->Message); - goto fin; - } // endif jsp + } // endif CheckMemory - } else - jsp = jvp->GetJson(); + jvp = MakeTypedValue(g, args, 0, TYPE_JSON); + jsp = jvp->GetJson(); if (g->Mrr) { // First argument is a constant g->Xchk = jsp; @@ -5030,16 +5320,16 @@ char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result, jsp = (PJSON)g->Xchk; path = MakePSZ(g, args, 1); - jsx = new(g) JSNX(g, jsp, TYPE_STRING, initid->max_length); + jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length); - if (jsx->SetJpath(g, path, false)) { + if (!jsx || jsx->SetJpath(g, path, false)) { PUSH_WARNING(g->Message); goto fin; } // endif SetJpath // Get the json tree if ((jvp = jsx->GetRowValue(g, jsp, 0, false))) { - jsp = (jvp->GetJsp()) ? jvp->GetJsp() : new(g) JVALUE(g, jvp->GetValue()); + jsp = (jvp->GetJsp()) ? jvp->GetJsp() : JvalNew(g, TYPE_VAL, jvp->GetValue()); if ((bsp = JbinAlloc(g, args, initid->max_length, jsp))) strcat(bsp->Msg, " item"); diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h index cd3b9768f7a..23e8c0e1aed 100644 --- a/storage/connect/jsonudf.h +++ b/storage/connect/jsonudf.h @@ -89,6 +89,10 @@ extern "C" { DllExport char *json_object_list(UDF_EXEC_ARGS); DllExport void json_object_list_deinit(UDF_INIT*); + DllExport my_bool json_object_values_init(UDF_INIT*, UDF_ARGS*, char*); + DllExport char *json_object_values(UDF_EXEC_ARGS); + DllExport void json_object_values_deinit(UDF_INIT*); + DllExport my_bool jsonset_grp_size_init(UDF_INIT*, UDF_ARGS*, char*); DllExport long long jsonset_grp_size(UDF_INIT*, UDF_ARGS*, char*, char*); diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp index 700d247da38..9b30b315441 100644 --- a/storage/connect/libdoc.cpp +++ b/storage/connect/libdoc.cpp @@ -194,7 +194,7 @@ void xtrc(char const *fmt, ...) { va_list ap; va_start (ap, fmt); - + ; //vfprintf(stderr, fmt, ap); vsprintf(s, fmt, ap); if (s[strlen(s)-1] == '\n') @@ -210,7 +210,7 @@ static xmlStrdupFunc Strdup; void xmlMyFree(void *mem) { - if (trace) { + if (trace(1)) { htrc("%.4d Freeing at %p %s\n", ++m, mem, s); *s = 0; } // endif trace @@ -220,7 +220,7 @@ void xmlMyFree(void *mem) void *xmlMyMalloc(size_t size) { void *p = Malloc(size); - if (trace) { + if (trace(1)) { htrc("%.4d Allocating %.5d at %p %s\n", ++m, size, p, s); *s = 0; } // endif trace @@ -230,7 +230,7 @@ void *xmlMyMalloc(size_t size) void *xmlMyMallocAtomic(size_t size) { void *p = MallocA(size); - if (trace) { + if (trace(1)) { htrc("%.4d Atom alloc %.5d at %p %s\n", ++m, size, p, s); *s = 0; } // endif trace @@ -240,7 +240,7 @@ void *xmlMyMallocAtomic(size_t size) void *xmlMyRealloc(void *mem, size_t size) { void *p = Realloc(mem, size); - if (trace) { + if (trace(1)) { htrc("%.4d ReAlloc %.5d to %p from %p %s\n", ++m, size, p, mem, s); *s = 0; } // endif trace @@ -250,7 +250,7 @@ void *xmlMyRealloc(void *mem, size_t size) char *xmlMyStrdup(const char *str) { char *p = Strdup(str); - if (trace) { + if (trace(1)) { htrc("%.4d Duplicating to %p from %p %s %s\n", ++m, p, str, str, s); *s = 0; } // endif trace @@ -339,7 +339,7 @@ void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all) { PX2BLOCK xp = (PX2BLOCK)fp; - if (trace) + if (trace(1)) htrc("CloseXML2File: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0); if (xp && xp->Count > 1 && !all) { @@ -387,7 +387,7 @@ bool LIBXMLDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped) /******************************************************************/ bool LIBXMLDOC::ParseFile(PGLOBAL g, char *fn) { - if (trace) + if (trace(1)) htrc("ParseFile\n"); if (zip) { @@ -436,7 +436,7 @@ PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) /******************************************************************/ bool LIBXMLDOC::NewDoc(PGLOBAL g, PCSZ ver) { - if (trace) + if (trace(1)) htrc("NewDoc\n"); return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL); @@ -447,7 +447,7 @@ bool LIBXMLDOC::NewDoc(PGLOBAL g, PCSZ ver) /******************************************************************/ void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp) { - if (trace) + if (trace(1)) htrc("AddComment: %s\n", txtp); xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp); @@ -459,7 +459,7 @@ void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp) /******************************************************************/ PXNODE LIBXMLDOC::GetRoot(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("GetRoot\n"); xmlNodePtr root = xmlDocGetRootElement(Docp); @@ -475,7 +475,7 @@ PXNODE LIBXMLDOC::GetRoot(PGLOBAL g) /******************************************************************/ PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name) { - if (trace) + if (trace(1)) htrc("NewRoot: %s\n", name); xmlNodePtr root = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL); @@ -493,7 +493,7 @@ PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name) /******************************************************************/ PXNODE LIBXMLDOC::NewPnode(PGLOBAL g, char *name) { - if (trace) + if (trace(1)) htrc("NewNode: %s\n", name); xmlNodePtr nop; @@ -534,7 +534,7 @@ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn) int rc = 0; FILE *of; - if (trace) + if (trace(1)) htrc("DumpDoc: %s\n", ofn); if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w"))) @@ -576,7 +576,7 @@ int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn) /******************************************************************/ void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) { - if (trace) + if (trace(1)) htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0); //if (xp && xp->Count == 1) { @@ -630,24 +630,24 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) { xmlNodeSetPtr nl; - if (trace) + if (trace(1)) htrc("GetNodeList: %s np=%p\n", xp, np); if (!Ctxp) { // Init Xpath - if (trace) + if (trace(1)) htrc("Calling xmlPathInit\n"); xmlXPathInit(); - if (trace) + if (trace(1)) htrc("Calling xmlXPathNewContext Docp=%p\n", Docp); // Create xpath evaluation context if (!(Ctxp = xmlXPathNewContext(Docp))) { strcpy(g->Message, MSG(XPATH_CNTX_ERR)); - if (trace) + if (trace(1)) htrc("Context error: %s\n", g->Message); return NULL; @@ -655,7 +655,7 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) // Register namespaces from list (if any) for (PNS nsp = Namespaces; nsp; nsp = nsp->Next) { - if (trace) + if (trace(1)) htrc("Calling xmlXPathRegisterNs Prefix=%s Uri=%s\n", nsp->Prefix, nsp->Uri); @@ -663,7 +663,7 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) BAD_CAST nsp->Uri)) { sprintf(g->Message, MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri); - if (trace) + if (trace(1)) htrc("Ns error: %s\n", g->Message); return NULL; @@ -674,7 +674,7 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) } // endif Ctxp if (Xop) { - if (trace) + if (trace(1)) htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n", Xop, Nofreelist); @@ -698,21 +698,21 @@ xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) // Set the context to the calling node Ctxp->node = np; - if (trace) + if (trace(1)) htrc("Calling xmlXPathEval %s Ctxp=%p\n", xp, Ctxp); // Evaluate table xpath if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) { sprintf(g->Message, MSG(XPATH_EVAL_ERR), xp); - if (trace) + if (trace(1)) htrc("Path error: %s\n", g->Message); return NULL; } else nl = Xop->nodesetval; - if (trace) + if (trace(1)) htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0); return nl; @@ -811,7 +811,7 @@ XML2NODE::XML2NODE(PXDOC dp, xmlNodePtr np) : XMLNODE(dp) int XML2NODE::GetType(void) { - if (trace) + if (trace(1)) htrc("GetType type=%d\n", Nodep->type); return Nodep->type; @@ -822,7 +822,7 @@ int XML2NODE::GetType(void) /******************************************************************/ PXNODE XML2NODE::GetNext(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("GetNext\n"); if (!Nodep->next) @@ -838,7 +838,7 @@ PXNODE XML2NODE::GetNext(PGLOBAL g) /******************************************************************/ PXNODE XML2NODE::GetChild(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("GetChild\n"); if (!Nodep->children) @@ -856,7 +856,7 @@ RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len) { RCODE rc = RC_OK; - if (trace) + if (trace(1)) htrc("GetContent\n"); if (Content) @@ -888,7 +888,7 @@ RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len) *p2 = 0; - if (trace) + if (trace(1)) htrc("GetText buf='%s' len=%d\n", buf, len); xmlFree(Content); @@ -896,7 +896,7 @@ RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len) } else *buf = '\0'; - if (trace) + if (trace(1)) htrc("GetContent: %s\n", buf); return rc; @@ -907,12 +907,12 @@ RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len) /******************************************************************/ bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len) { - if (trace) + if (trace(1)) htrc("SetContent: %s\n", txtp); xmlChar *buf = xmlEncodeEntitiesReentrant(Docp, BAD_CAST txtp); - if (trace) + if (trace(1)) htrc("SetContent: %s -> %s\n", txtp, buf); xmlNodeSetContent(Nodep, buf); @@ -925,7 +925,7 @@ bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len) /******************************************************************/ PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np) { - if (trace) + if (trace(1)) htrc("Clone: np=%p\n", np); if (np) { @@ -941,7 +941,7 @@ PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np) /******************************************************************/ PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp) { - if (trace) + if (trace(1)) htrc("GetChildElements: %s\n", xp); return SelectNodes(g, (xp) ? xp : (char*)"*", lp); @@ -952,7 +952,7 @@ PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp) /******************************************************************/ PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp) { - if (trace) + if (trace(1)) htrc("SelectNodes: %s\n", xp); xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); @@ -970,7 +970,7 @@ PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp) /******************************************************************/ PXNODE XML2NODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np) { - if (trace) + if (trace(1)) htrc("SelectSingleNode: %s\n", xp); xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); @@ -994,7 +994,7 @@ PXATTR XML2NODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap) { xmlAttrPtr atp; - if (trace) + if (trace(1)) htrc("GetAttribute: %s\n", SVP(name)); if (name) @@ -1023,7 +1023,7 @@ PXNODE XML2NODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np) { char *p, *pn, *pf = NULL, *nmp = PlugDup(g, name); - if (trace) + if (trace(1)) htrc("AddChildNode: %s\n", name); // Is a prefix specified @@ -1074,7 +1074,7 @@ PXNODE XML2NODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np) /******************************************************************/ PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap) { - if (trace) + if (trace(1)) htrc("AddProperty: %s\n", name); xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL); @@ -1097,7 +1097,7 @@ PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap) /******************************************************************/ void XML2NODE::AddText(PGLOBAL g, PCSZ txtp) { - if (trace) + if (trace(1)) htrc("AddText: %s\n", txtp); // This is to avoid a blank line when inserting a new line @@ -1119,7 +1119,7 @@ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) { xmlErrorPtr xerr; - if (trace) + if (trace(1)) htrc("DeleteChild: node=%p\n", dnp); xmlNodePtr np = ((PNODE2)dnp)->Nodep; @@ -1157,7 +1157,7 @@ void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) return; err: - if (trace) + if (trace(1)) htrc("DeleteChild: errmsg=%s\n", xerr->message); xmlResetError(xerr); @@ -1187,7 +1187,7 @@ int XML2NODELIST::GetLength(void) /******************************************************************/ PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np) { - if (trace) + if (trace(1)) htrc("GetItem: %d\n", n); if (!Listp || Listp->nodeNr <= n) @@ -1206,7 +1206,7 @@ PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np) /******************************************************************/ bool XML2NODELIST::DropItem(PGLOBAL g, int n) { - if (trace) + if (trace(1)) htrc("DropItem: n=%d\n", n); // We should do something here @@ -1234,7 +1234,7 @@ XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np) /******************************************************************/ PXATTR XML2ATTR::GetNext(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("Attr GetNext\n"); if (!Atrp->next) @@ -1252,7 +1252,7 @@ RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len) RCODE rc = RC_OK; xmlChar *txt; - if (trace) + if (trace(1)) htrc("GetText\n"); if ((txt = xmlGetProp(Atrp->parent, Atrp->name))) { @@ -1269,7 +1269,7 @@ RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len) } else *buf = '\0'; - if (trace) + if (trace(1)) htrc("GetText: %s\n", buf); return rc; @@ -1280,7 +1280,7 @@ RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len) /******************************************************************/ bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len) { - if (trace) + if (trace(1)) htrc("SetText: %s %d\n", txtp, len); xmlSetProp(Parent, Atrp->name, BAD_CAST txtp); diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp index 088dc2d29d1..53e2bf377c4 100644 --- a/storage/connect/mongo.cpp +++ b/storage/connect/mongo.cpp @@ -172,7 +172,7 @@ PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info) goto err; skipit: - if (trace) + if (trace(1)) htrc("MGOColumns: n=%d len=%d\n", n, length[0]); /*********************************************************************/ @@ -276,7 +276,7 @@ int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt) tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper", (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface"); - if (trace) + if (trace(1)) htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n", tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl); diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 95af2eeee92..dd04d667e58 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -90,9 +90,9 @@ #if defined(XML_SUPPORT) #include "tabxml.h" #endif // XML_SUPPORT -#if defined(JAVA_SUPPORT) +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) #include "mongo.h" -#endif // JAVA_SUPPORT +#endif // JAVA_SUPPORT || CMGO_SUPPORT #if defined(ZIP_SUPPORT) #include "tabzip.h" #endif // ZIP_SUPPORT @@ -105,9 +105,10 @@ extern "C" HINSTANCE s_hModule; // Saved module handle #endif // !__WIN__ -#if defined(JAVA_SUPPORT) -//bool MongoEnabled(void); -#endif // JAVA_SUPPORT +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) +bool MongoEnabled(void); +#endif // JAVA_SUPPORT || CMGO_SUPPORT + PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); /***********************************************************************/ @@ -140,7 +141,9 @@ TABTYPE GetTypeID(const char *type) #endif #if defined(JAVA_SUPPORT) : (!stricmp(type, "JDBC")) ? TAB_JDBC - : (!stricmp(type, "MONGO")) ? TAB_MONGO +#endif +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) + : (!stricmp(type, "MONGO") && MongoEnabled()) ? TAB_MONGO #endif : (!stricmp(type, "MYSQL")) ? TAB_MYSQL : (!stricmp(type, "MYPRX")) ? TAB_MYSQL @@ -484,7 +487,7 @@ void MYCAT::Reset(void) PRELDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR type, PRELDEF *) { - if (trace) + if (trace(1)) printf("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type)); // If not specified get the type of this table @@ -505,7 +508,7 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) LPCSTR schema = (PSZ)PlugDup(g, tablep->GetSchema()); PRELDEF tdp= NULL; - if (trace) + if (trace(1)) printf("MakeTableDesc: name=%s schema=%s am=%s\n", name, SVP(schema), SVP(am)); @@ -548,18 +551,17 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; -#if defined(MONGO_SUPPORT) - case TAB_MONGO: -// if (MongoEnabled()) - tdp = new(g) MGODEF; -// else -// strcpy(g->Message, "MONGO type not enabled"); - - break; -#endif // MONGO_SUPPORT #if defined(ZIP_SUPPORT) - case TAB_ZIP: tdp= new(g) ZIPDEF; break; + case TAB_ZIP: tdp = new(g) ZIPDEF; break; #endif // ZIP_SUPPORT +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) + case TAB_MONGO: + if (MongoEnabled()) { + tdp = new(g) MGODEF; + break; + } // endif enabled + // fall through +#endif // JAVA_SUPPORT || CMGO_SUPPORT default: sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); } // endswitch @@ -580,14 +582,14 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) PTDB tdbp= NULL; // LPCSTR name= tablep->GetName(); - if (trace) + if (trace(1)) printf("GetTableDB: name=%s\n", tablep->GetName()); // Look for the description of the requested table tdp= GetTableDesc(g, tablep, type); if (tdp) { - if (trace) + if (trace(1)) printf("tdb=%p type=%s\n", tdp, tdp->GetType()); if (tablep->GetSchema()) @@ -597,7 +599,7 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) } // endif tdp if (tdbp) { - if (trace) + if (trace(1)) printf("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(), tdbp->GetAmType()); tablep->SetTo_Tdb(tdbp); diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index e99e089d940..253c42bb002 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -177,7 +177,7 @@ PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db, return NULL; } // endif b - if (trace) + if (trace(1)) htrc("MyColumns: cmd='%s'\n", cmd.GetStr()); if ((n = myc.GetResultSize(g, cmd.GetStr())) < 0) { @@ -482,7 +482,7 @@ int MYSQLC::Open(PGLOBAL g, const char *host, const char *db, return RC_FX; } // endif m_DB - if (trace) + if (trace(1)) htrc("MYSQLC Open: m_DB=%.4X size=%d\n", m_DB, (int)sizeof(*m_DB)); // Removed to do like FEDERATED do @@ -744,7 +744,7 @@ int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w) m_Fields = mysql_num_fields(m_Res); m_Rows = (!m_Use) ? (int)mysql_num_rows(m_Res) : 0; - if (trace) + if (trace(1)) htrc("ExecSQL: m_Res=%.4X size=%d m_Fields=%d m_Rows=%d\n", m_Res, sizeof(*m_Res), m_Fields, m_Rows); @@ -1068,7 +1068,7 @@ void MYSQLC::Close(void) { FreeResult(); - if (trace) + if (trace(1)) htrc("MYSQLC Close: m_DB=%.4X\n", m_DB); mysql_close(m_DB); diff --git a/storage/connect/mysql-test/connect/r/jdbc_postgresql.result b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result index 6d77d79d5d3..7969672dd66 100644 --- a/storage/connect/mysql-test/connect/r/jdbc_postgresql.result +++ b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result @@ -1,9 +1,11 @@ +SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar'; CREATE TABLE t2 ( command varchar(128) not null, number int(5) not null flag=1, message varchar(255) flag=2) -ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:postgresql://localhost/mtr' -OPTION_LIST='User=mtr,Password=mtr,Schema=public,Execsrc=1'; +ENGINE=CONNECT TABLE_TYPE=JDBC +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono' +OPTION_LIST='Execsrc=1'; SELECT * FROM t2 WHERE command='drop table employee'; command number message drop table employee 0 Execute: org.postgresql.util.PSQLException: ERREUR: la table « employee » n'existe pas @@ -14,17 +16,18 @@ SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'E command number message insert into employee values(4567,'Johnson', 'Engineer', 12560.50) 1 Affected rows CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables -CONNECTION='jdbc:postgresql://localhost/mtr' -OPTION_LIST='User=mtr,Password=mtr,Schema=public,Tabtype=TABLE,Maxres=10'; +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono' +OPTION_LIST='Tabtype=TABLE,Maxres=10'; SELECT * FROM t1; Table_Cat Table_Schema Table_Name Table_Type Remark - public employee TABLE NULL - public t1 TABLE NULL - public t2 TABLE NULL +NULL public employee TABLE NULL +NULL public t1 TABLE NULL +NULL public t2 TABLE NULL +NULL public tchar TABLE NULL +NULL public testuuid TABLE NULL DROP TABLE t1; -CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=columns -CONNECTION='jdbc:postgresql://localhost/mtr' tabname=employee -OPTION_LIST='User=mtr,Password=mtr,Maxres=10'; +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC tabname=employee CATFUNC=columns +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'; SELECT * FROM t1; Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks NULL public employee id 4 int4 10 0 0 10 0 NULL @@ -34,13 +37,14 @@ NULL public employee salary 2 numeric 8 0 2 10 1 NULL DROP TABLE t1; CREATE SERVER 'postgresql' FOREIGN DATA WRAPPER 'postgresql' OPTIONS ( HOST 'localhost', -DATABASE 'mtr', -USER 'mtr', -PASSWORD 'mtr', +DATABASE 'test', +USER 'postgres', +PASSWORD 'tinono', PORT 0, SOCKET '', OWNER 'root'); -CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='postgresql/public.employee'; +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC +CONNECTION='postgresql/public.employee'; SELECT * FROM t1; id name title salary 4567 Johnson Engineer 12560.50 @@ -60,6 +64,3 @@ SELECT * FROM t2 WHERE command='drop table employee'; command number message drop table employee 0 Affected rows DROP TABLE t2; -SET GLOBAL connect_jvm_path=NULL; -SET GLOBAL connect_class_path=NULL; -SET GLOBAL time_zone = SYSTEM; diff --git a/storage/connect/mysql-test/connect/r/json_java_2.result b/storage/connect/mysql-test/connect/r/json_java_2.result index 966330248e5..6c578b35d6f 100644 --- a/storage/connect/mysql-test/connect/r/json_java_2.result +++ b/storage/connect/mysql-test/connect/r/json_java_2.result @@ -1,4 +1,5 @@ SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/Mongo2.jar'; +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -381,3 +382,4 @@ planner 167 41.75 postcard 23 5.75 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/json_java_3.result b/storage/connect/mysql-test/connect/r/json_java_3.result index f8e9e161475..4c5fc94fca6 100644 --- a/storage/connect/mysql-test/connect/r/json_java_3.result +++ b/storage/connect/mysql-test/connect/r/json_java_3.result @@ -1,4 +1,5 @@ SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/Mongo3.jar'; +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -381,3 +382,4 @@ planner 167 41.75 postcard 23 5.75 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/json_mongo_c.result b/storage/connect/mysql-test/connect/r/json_mongo_c.result index 8adc006a51b..550e94f286e 100644 --- a/storage/connect/mysql-test/connect/r/json_mongo_c.result +++ b/storage/connect/mysql-test/connect/r/json_mongo_c.result @@ -1,3 +1,4 @@ +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -380,3 +381,4 @@ planner 167 41.75 postcard 23 5.75 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/json_udf.result b/storage/connect/mysql-test/connect/r/json_udf.result index 7d81ca5e73d..09544bb1ecb 100644 --- a/storage/connect/mysql-test/connect/r/json_udf.result +++ b/storage/connect/mysql-test/connect/r/json_udf.result @@ -50,17 +50,19 @@ SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Arra Array [56,3.141600,"foo",null,"One more"] SELECT Json_Array_Add(JsonValue('one value'), 'One more'); -ERROR HY000: Can't initialize function 'json_array_add'; First argument must be a json item +Json_Array_Add(JsonValue('one value'), 'One more') +["\"one value\"","One more"] SELECT Json_Array_Add('one value', 'One more'); -ERROR HY000: Can't initialize function 'json_array_add'; First argument must be a json item +Json_Array_Add('one value', 'One more') +["one value","One more"] SELECT Json_Array_Add('one value' json_, 'One more'); Json_Array_Add('one value' json_, 'One more') one value Warnings: Warning 1105 Error 2 opening one value -Warning 1105 First argument target is not an array SELECT Json_Array_Add(5 json_, 'One more'); -ERROR HY000: Can't initialize function 'json_array_add'; First argument must be a json item +Json_Array_Add(5 json_, 'One more') +[5,"One more"] SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 0); Json_Array_Add('[5,3,8,7,9]' json_, 4, 0) [4,5,3,8,7,9] diff --git a/storage/connect/mysql-test/connect/r/json_udf_bin.result b/storage/connect/mysql-test/connect/r/json_udf_bin.result index 0c009d612fe..d0819619c33 100644 --- a/storage/connect/mysql-test/connect/r/json_udf_bin.result +++ b/storage/connect/mysql-test/connect/r/json_udf_bin.result @@ -272,10 +272,9 @@ Json_Serialize(Jbin_Array('a','b','c')) ["a","b","c"] SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('not_exist.json'), 'd')); Json_Serialize(Jbin_Array_Add(Jbin_File('not_exist.json'), 'd')) -Null json tree +[null,"d"] Warnings: Warning 1105 Open(map) error 2 on not_exist.json -Warning 1105 First argument is not an array # This does not modify the file SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')); Json_Serialize(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) diff --git a/storage/connect/mysql-test/connect/r/mongo_c.result b/storage/connect/mysql-test/connect/r/mongo_c.result index c7aadcf1165..132bb34ce64 100644 --- a/storage/connect/mysql-test/connect/r/mongo_c.result +++ b/storage/connect/mysql-test/connect/r/mongo_c.result @@ -1,3 +1,4 @@ +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -376,3 +377,4 @@ planner 167 41.750000 postcard 23 5.750000 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/mongo_java_2.result b/storage/connect/mysql-test/connect/r/mongo_java_2.result index 8c58a9eceea..67c67653e88 100644 --- a/storage/connect/mysql-test/connect/r/mongo_java_2.result +++ b/storage/connect/mysql-test/connect/r/mongo_java_2.result @@ -1,4 +1,5 @@ SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/Mongo2.jar'; +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -377,3 +378,4 @@ planner 167 41.75 postcard 23 5.75 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/mongo_java_3.result b/storage/connect/mysql-test/connect/r/mongo_java_3.result index 1dd3048b49b..665178bd3ea 100644 --- a/storage/connect/mysql-test/connect/r/mongo_java_3.result +++ b/storage/connect/mysql-test/connect/r/mongo_java_3.result @@ -1,4 +1,5 @@ SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/Mongo3.jar'; +set connect_enable_mongo=1; # # Test the MONGO table type # @@ -377,3 +378,4 @@ planner 167 41.75 postcard 23 5.75 DROP TABLE t1; true +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/r/tbl_thread.result b/storage/connect/mysql-test/connect/r/tbl_thread.result index f53ccd25b97..3526fc43ffc 100644 --- a/storage/connect/mysql-test/connect/r/tbl_thread.result +++ b/storage/connect/mysql-test/connect/r/tbl_thread.result @@ -87,7 +87,7 @@ a b CREATE TABLE total (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4,t5' OPTION_LIST='thread=yes,port=PORT'; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by a desc; a b 19 test19 @@ -129,7 +129,7 @@ SELECT * FROM t2; v 22 CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=PORT';; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by v desc; v 22 @@ -148,7 +148,7 @@ SELECT * FROM t2; v 22 CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=PORT';; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by v desc; v 22 diff --git a/storage/connect/mysql-test/connect/r/vcol.result b/storage/connect/mysql-test/connect/r/vcol.result index 1e3ecf8450a..e0fd37203e4 100644 --- a/storage/connect/mysql-test/connect/r/vcol.result +++ b/storage/connect/mysql-test/connect/r/vcol.result @@ -6,7 +6,7 @@ birth date not null date_format='DD/MM/YYYY', hired date not null date_format='DD/MM/YYYY' flag=36, agehired int(3) as (floor(datediff(hired,birth)/365.25)) ) -engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47; +engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1; select * from t1; name city birth hired agehired John Boston 1986-01-25 2010-06-02 24 @@ -25,5 +25,5 @@ hired date not null date_format='DD/MM/YYYY' flag=36, agehired int(3) as (floor(datediff(hired,birth)/365.25)), index (agehired) ) -engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47; +engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1; ERROR 42000: Table handler doesn't support NULL in given index. Please change column 'agehired' to be NOT NULL or use another handler diff --git a/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar b/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar Binary files differnew file mode 100644 index 00000000000..33b29e7685b --- /dev/null +++ b/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar diff --git a/storage/connect/mysql-test/connect/t/jdbc_postgresql.test b/storage/connect/mysql-test/connect/t/jdbc_postgresql.test index 1041ef468d7..8036f71020d 100644 --- a/storage/connect/mysql-test/connect/t/jdbc_postgresql.test +++ b/storage/connect/mysql-test/connect/t/jdbc_postgresql.test @@ -3,25 +3,32 @@ # # This test is run against Postgresql driver # +eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar'; CREATE TABLE t2 ( command varchar(128) not null, number int(5) not null flag=1, message varchar(255) flag=2) -ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:postgresql://localhost/mtr' -OPTION_LIST='User=mtr,Password=mtr,Schema=public,Execsrc=1'; +ENGINE=CONNECT TABLE_TYPE=JDBC +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono' +OPTION_LIST='Execsrc=1'; +#CONNECTION='jdbc:postgresql://localhost/mtr' +#OPTION_LIST='User=mtr,Password=mtr,Schema=public,Execsrc=1'; SELECT * FROM t2 WHERE command='drop table employee'; SELECT * FROM t2 WHERE command = 'create table employee (id int not null, name varchar(32), title char(16), salary decimal(8,2))'; SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'Engineer', 12560.50)"; CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables -CONNECTION='jdbc:postgresql://localhost/mtr' -OPTION_LIST='User=mtr,Password=mtr,Schema=public,Tabtype=TABLE,Maxres=10'; +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono' +OPTION_LIST='Tabtype=TABLE,Maxres=10'; +#CONNECTION='jdbc:postgresql://localhost/mtr' +#OPTION_LIST='User=mtr,Password=mtr,Schema=public,Tabtype=TABLE,Maxres=10'; SELECT * FROM t1; DROP TABLE t1; -CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=columns -CONNECTION='jdbc:postgresql://localhost/mtr' tabname=employee -OPTION_LIST='User=mtr,Password=mtr,Maxres=10'; +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC tabname=employee CATFUNC=columns +CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'; +#CONNECTION='jdbc:postgresql://localhost/mtr' tabname=employee; +#OPTION_LIST='User=mtr,Password=mtr,Maxres=10'; SELECT * FROM t1; DROP TABLE t1; @@ -30,14 +37,18 @@ DROP TABLE t1; # CREATE SERVER 'postgresql' FOREIGN DATA WRAPPER 'postgresql' OPTIONS ( HOST 'localhost', -DATABASE 'mtr', -USER 'mtr', -PASSWORD 'mtr', +DATABASE 'test', +USER 'postgres', +PASSWORD 'tinono', PORT 0, SOCKET '', OWNER 'root'); +#DATABASE 'mtr', +#USER 'mtr', +#PASSWORD 'mtr', -CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='postgresql/public.employee'; +CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC +CONNECTION='postgresql/public.employee'; SELECT * FROM t1; INSERT INTO t1 VALUES(3126,'Smith', 'Clerk', 5230.00); UPDATE t1 SET salary = salary + 100.00; diff --git a/storage/connect/mysql-test/connect/t/jdbconn.inc b/storage/connect/mysql-test/connect/t/jdbconn.inc index 05122f51924..81ec80c13d6 100644 --- a/storage/connect/mysql-test/connect/t/jdbconn.inc +++ b/storage/connect/mysql-test/connect/t/jdbconn.inc @@ -22,10 +22,11 @@ DROP TABLE t1; # 1 - The current directory. # 2 - The paths of the connect_class_path global variable. # 3 - The paths of the CLASSPATH environment variable. -# In this test we use an executable jar file that contains all what is needed. -eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JdbcMariaDB.jar'; +# In this test we use an executable jar file that contains all the eisting wrappers. +#eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JdbcMariaDB.jar'; +eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JavaWrappers.jar'; -# Paths to the JDK classes and to the MySQL and MariaDB drivers can be defined in the CLASSPATH environment variable +# Paths to the JDK classes and to the JDBC drivers should be defined in the CLASSPATH environment variable #CREATE FUNCTION envar RETURNS STRING SONAME 'ha_connect.dll'; #SELECT envar('CLASSPATH'); diff --git a/storage/connect/mysql-test/connect/t/json_udf.test b/storage/connect/mysql-test/connect/t/json_udf.test index 35dbbfed706..d45131f32ba 100644 --- a/storage/connect/mysql-test/connect/t/json_udf.test +++ b/storage/connect/mysql-test/connect/t/json_udf.test @@ -29,12 +29,12 @@ SELECT Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE); --error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL)) Array; SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array; ---error ER_CANT_INITIALIZE_UDF +#--error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Add(JsonValue('one value'), 'One more'); ---error ER_CANT_INITIALIZE_UDF +#--error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Add('one value', 'One more'); SELECT Json_Array_Add('one value' json_, 'One more'); ---error ER_CANT_INITIALIZE_UDF +#--error ER_CANT_INITIALIZE_UDF SELECT Json_Array_Add(5 json_, 'One more'); SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 0); SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array; diff --git a/storage/connect/mysql-test/connect/t/mongo.inc b/storage/connect/mysql-test/connect/t/mongo.inc index 2d7cbcfa8bd..fab2ca84139 100644 --- a/storage/connect/mysql-test/connect/t/mongo.inc +++ b/storage/connect/mysql-test/connect/t/mongo.inc @@ -1,3 +1,3 @@ -let $MONGO= C:/PROGRA~1/MongoDB/Server/3.4/bin/mongo; -let $MONGOIMPORT= C:/PROGRA~1/MongoDB/Server/3.4/bin/mongoimport; +let $MONGO= C:/Applic/MongoDB/Server/3.6/bin/mongo; +let $MONGOIMPORT= C:/Applic/MongoDB/Server/3.6/bin/mongoimport; diff --git a/storage/connect/mysql-test/connect/t/mongo_test.inc b/storage/connect/mysql-test/connect/t/mongo_test.inc index dfc223e9074..357fa55240b 100644 --- a/storage/connect/mysql-test/connect/t/mongo_test.inc +++ b/storage/connect/mysql-test/connect/t/mongo_test.inc @@ -1,4 +1,4 @@ -#set connect_enable_mongo=1; +set connect_enable_mongo=1; --echo # --echo # Test the MONGO table type @@ -130,7 +130,9 @@ DROP TABLE t1; --echo # --echo # try CRUD operations --echo # +--disable_query_log --exec $MONGO --eval "db.testcoll.drop()" --quiet +--enable_query_log eval CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64)) ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='testcoll' OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN; @@ -147,7 +149,9 @@ DROP TABLE t1; --echo # --echo # List states whose population is equal or more than 10 millions --echo # +--disable_query_log --exec $MONGO --eval "db.cities.drop()" --quiet +--enable_query_log --exec $MONGOIMPORT --quiet $MTR_SUITE_DIR/std_data/cities.json eval CREATE TABLE t1 ( _id char(5) NOT NULL, @@ -204,4 +208,4 @@ SELECT * FROM t1; DROP TABLE t1; --exec $MONGO --eval "db.testcoll.drop()" --quiet -#set connect_enable_mongo=0; +set connect_enable_mongo=0; diff --git a/storage/connect/mysql-test/connect/t/tbl_thread.test b/storage/connect/mysql-test/connect/t/tbl_thread.test index 68a0ebcd44d..05409c695fb 100644 --- a/storage/connect/mysql-test/connect/t/tbl_thread.test +++ b/storage/connect/mysql-test/connect/t/tbl_thread.test @@ -56,7 +56,7 @@ SELECT * FROM t5; eval CREATE TABLE total (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4,t5' OPTION_LIST='thread=yes,port=$PORT'; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by a desc; set connect_xtrace=0; @@ -85,7 +85,7 @@ SELECT * FROM t2; --replace_result $PORT PORT --eval CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=$PORT'; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by v desc; set connect_xtrace=0; DROP TABLE t1,t2,total; @@ -101,7 +101,7 @@ SELECT * FROM t2; --replace_result $PORT PORT --eval CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=$PORT'; -set connect_xtrace=1; +set connect_xtrace=96; SELECT * FROM total order by v desc; set connect_xtrace=0; diff --git a/storage/connect/mysql-test/connect/t/vcol.test b/storage/connect/mysql-test/connect/t/vcol.test index 0ed13c0e340..cdf37175f41 100644 --- a/storage/connect/mysql-test/connect/t/vcol.test +++ b/storage/connect/mysql-test/connect/t/vcol.test @@ -9,7 +9,7 @@ create table t1 ( hired date not null date_format='DD/MM/YYYY' flag=36, agehired int(3) as (floor(datediff(hired,birth)/365.25)) ) -engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47; +engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1; select * from t1; drop table t1; @@ -23,4 +23,9 @@ create table t1 ( agehired int(3) as (floor(datediff(hired,birth)/365.25)), index (agehired) ) -engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47; +engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1; + +# +# Clean up +# +--remove_file $datadir/test/boys.txt diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 45662779b81..f7b1a43a95d 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -137,10 +137,10 @@ int TranslateSQLType(int stp, int prec, int& len, char& v, bool& w) case SQL_WLONGVARCHAR: // (-10) w = true; case SQL_LONGVARCHAR: // (-1) - if (GetTypeConv() == TPC_YES) { + if (GetTypeConv() == TPC_YES || GetTypeConv() == TPC_FORCE) { v = 'V'; type = TYPE_STRING; - len = MY_MIN(abs(len), GetConvSize()); + len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize(); } else type = TYPE_ERROR; @@ -190,12 +190,23 @@ int TranslateSQLType(int stp, int prec, int& len, char& v, bool& w) case SQL_BIGINT: // (-5) type = TYPE_BIGINT; break; - case SQL_UNKNOWN_TYPE: // 0 case SQL_BINARY: // (-2) case SQL_VARBINARY: // (-3) case SQL_LONGVARBINARY: // (-4) - case SQL_GUID: // (-11) - default: + if (GetTypeConv() == TPC_FORCE) { + v = 'V'; + type = TYPE_STRING; + len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize(); + } else + type = TYPE_ERROR; + + break; + case SQL_GUID: // (-11) + type = TYPE_STRING; + len = 36; + break; + case SQL_UNKNOWN_TYPE: // 0 + default: type = TYPE_ERROR; len = 0; } // endswitch type @@ -364,7 +375,7 @@ PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table, length[11] = 255; } // endif ocp - if (trace) + if (trace(1)) htrc("ODBCColumns: max=%d len=%d,%d,%d,%d\n", maxres, length[0], length[1], length[2], length[3]); @@ -381,7 +392,7 @@ PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table, if (info || !qrp) // Info table return qrp; - if (trace) + if (trace(1)) htrc("Getting col results ncol=%d\n", qrp->Nbcol); if (!(cap = AllocCatInfo(g, CAT_COL, db, table, qrp))) @@ -396,7 +407,7 @@ PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table, qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -536,7 +547,7 @@ PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info) } else maxres = 0; - if (trace) + if (trace(1)) htrc("ODBCDrivers: max=%d len=%d\n", maxres, length[0]); /************************************************************************/ @@ -593,7 +604,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info) maxres = 0; } // endif info - if (trace) + if (trace(1)) htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]); /************************************************************************/ @@ -666,7 +677,7 @@ PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat, PCSZ tabtyp, length[4] = 255; } // endif info - if (trace) + if (trace(1)) htrc("ODBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]); /************************************************************************/ @@ -687,7 +698,7 @@ PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat, PCSZ tabtyp, cap->Pat = tabtyp; - if (trace) + if (trace(1)) htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol); /************************************************************************/ @@ -697,7 +708,7 @@ PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat, PCSZ tabtyp, qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -755,7 +766,7 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN); length[3] = (n) ? (n + 1) : 128; - if (trace) + if (trace(1)) htrc("ODBCPrimaryKeys: max=%d len=%d,%d,%d\n", maxres, length[0], length[1], length[2]); @@ -765,7 +776,7 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY, buftyp, NULL, length, false, true); - if (trace) + if (trace(1)) htrc("Getting pkey results ncol=%d\n", qrp->Nbcol); cap = AllocCatInfo(g, CAT_KEY, NULL, table, qrp); @@ -777,7 +788,7 @@ PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table) qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -838,7 +849,7 @@ PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN); length[7] = (n) ? (n + 1) : 128; - if (trace) + if (trace(1)) htrc("SemStatistics: max=%d pat=%s\n", maxres, SVP(pat)); /************************************************************************/ @@ -847,7 +858,7 @@ PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT, buftyp, NULL, length, false, true); - if (trace) + if (trace(1)) htrc("Getting stat results ncol=%d\n", qrp->Nbcol); cap = AllocCatInfo(g, CAT_STAT, NULL, pat, qrp); @@ -861,7 +872,7 @@ PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat, qrp->Nblin = n; // ResetNullValues(cap); - if (trace) + if (trace(1)) htrc("Statistics: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin); } else @@ -918,7 +929,7 @@ bool DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt) && strcmp((char*)state, "00000"); i++) { m_ErrMsg[i] = (PSZ)PlugDup(g, (char*)msg); - if (trace) + if (trace(1)) htrc("%s: %s, Native=%d\n", state, msg, native); rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state, @@ -932,7 +943,7 @@ bool DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt) MSG(BAD_HANDLE_VAL)); m_ErrMsg[0] = (PSZ)PlugDup(g, (char*)msg); - if (trace) + if (trace(1)) htrc("%s: rc=%hd\n", SVP(m_ErrMsg[0]), m_RC); return true; @@ -941,7 +952,7 @@ bool DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt) } else m_ErrMsg[0] = "No connexion address provided"; - if (trace) + if (trace(1)) htrc("%s: rc=%hd (%s)\n", SVP(m_Msg), m_RC, SVP(m_ErrMsg[0])); return true; @@ -1004,7 +1015,7 @@ bool ODBConn::Check(RETCODE rc) { switch (rc) { case SQL_SUCCESS_WITH_INFO: - if (trace) { + if (trace(1)) { DBX x(rc); if (x.BuildErrorMessage(this, m_hstmt)) @@ -1223,7 +1234,7 @@ void ODBConn::AllocConnect(DWORD Options) if ((signed)m_LoginTimeout >= 0) { rc = SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT, m_LoginTimeout); - if (trace && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) + if (trace(1) && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) htrc("Warning: Failure setting login timeout\n"); } // endif Timeout @@ -1231,7 +1242,7 @@ void ODBConn::AllocConnect(DWORD Options) if (!m_Updatable) { rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE, SQL_MODE_READ_ONLY); - if (trace && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) + if (trace(1) && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) htrc("Warning: Failure setting read only access mode\n"); } // endif @@ -1385,7 +1396,7 @@ void ODBConn::GetConnectInfo() else m_Updatable = false; - if (trace) + if (trace(1)) htrc("Warning: data source is readonly\n"); } else // Make data source is !Updatable @@ -1397,7 +1408,7 @@ void ODBConn::GetConnectInfo() rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR, m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult); - if (trace) + if (trace(1)) htrc("DBMS: %s, Version: %s, rc=%d\n", GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER), rc); @@ -1447,7 +1458,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) OnSetOptions(hstmt); b = true; - if (trace) + if (trace(1)) htrc("ExecDirect hstmt=%p %.256s\n", hstmt, sql); if (m_Tdb->Srcdef) { @@ -1510,7 +1521,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) ThrowDBX(m_G->Message); } // endif tp - if (trace) + if (trace(1)) htrc("Binding col=%u type=%d buf=%p len=%d slen=%p\n", n, tp, buffer, len, colp->GetStrLen()); @@ -1523,7 +1534,7 @@ int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols) } // endif pcol } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -1569,7 +1580,7 @@ int ODBConn::GetResultSize(char *sql, ODBCCOL *colp) } catch(DBX *x) { strcpy(m_G->Message, x->GetErrorMessage(0)); - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -1610,7 +1621,7 @@ int ODBConn::Fetch(int pos) } // endif m_RowsetSize // } while (rc == SQL_STILL_EXECUTING); - if (trace > 1) + if (trace(2)) htrc("Fetch: hstmt=%p RowseSize=%d rc=%d\n", m_hstmt, m_RowsetSize, rc); @@ -1626,7 +1637,7 @@ int ODBConn::Fetch(int pos) m_Fetch++; m_Rows += irc; } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -1662,7 +1673,7 @@ int ODBConn::PrepareSQL(char *sql) m_Transact = true; } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -1693,7 +1704,7 @@ int ODBConn::PrepareSQL(char *sql) OnSetOptions(hstmt); b = true; - if (trace) + if (trace(1)) htrc("Prepare hstmt=%p %.64s\n", hstmt, sql); do { @@ -1708,7 +1719,7 @@ int ODBConn::PrepareSQL(char *sql) } while (rc == SQL_STILL_EXECUTING); } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -1881,7 +1892,7 @@ bool ODBConn::ExecSQLcommand(char *sql) OnSetOptions(hstmt); b = true; - if (trace) + if (trace(1)) htrc("ExecSQLcommand hstmt=%p %.64s\n", hstmt, sql); // Proceed with command execution @@ -1908,7 +1919,7 @@ bool ODBConn::ExecSQLcommand(char *sql) } // endif ncol } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -2394,7 +2405,7 @@ int ODBConn::GetCatInfo(CATPARM *cap) if ((rc = SQLFetch(hstmt)) == SQL_NO_DATA_FOUND) break; else if (rc != SQL_SUCCESS) { - if (trace > 1 || (trace && rc != SQL_SUCCESS_WITH_INFO)) { + if (trace(2) || (trace(1) && rc != SQL_SUCCESS_WITH_INFO)) { UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1]; UCHAR state[SQL_SQLSTATE_SIZE + 1]; RETCODE erc; @@ -2466,7 +2477,7 @@ int ODBConn::GetCatInfo(CATPARM *cap) irc = (int)crow; } catch(DBX *x) { - if (trace) + if (trace(1)) for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++) htrc(x->m_ErrMsg[i]); @@ -2605,12 +2616,12 @@ void ODBConn::Close() rc = SQLDisconnect(m_hdbc); - if (trace && rc != SQL_SUCCESS) + if (trace(1) && rc != SQL_SUCCESS) htrc("Error: SQLDisconnect rc=%d\n", rc); rc = SQLFreeConnect(m_hdbc); - if (trace && rc != SQL_SUCCESS) + if (trace(1) && rc != SQL_SUCCESS) htrc("Error: SQLFreeConnect rc=%d\n", rc); m_hdbc = SQL_NULL_HDBC; @@ -2619,7 +2630,7 @@ void ODBConn::Close() if (m_henv != SQL_NULL_HENV) { rc = SQLFreeEnv(m_henv); - if (trace && rc != SQL_SUCCESS) // Nothing we can do + if (trace(1) && rc != SQL_SUCCESS) // Nothing we can do htrc("Error: SQLFreeEnv failure ignored in Close\n"); m_henv = SQL_NULL_HENV; diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 6a0a8be8ff8..5446e0d2a07 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -362,7 +362,8 @@ enum COLUSE {U_P = 0x01, /* the projection list. */ U_IS_NULL = 0x80, /* The column has a null value */ U_SPECIAL = 0x100, /* The column is special */ U_UNSIGNED = 0x200, /* The column type is unsigned */ - U_ZEROFILL = 0x400}; /* The column is zero filled */ + U_ZEROFILL = 0x400, /* The column is zero filled */ + U_UUID = 0x800}; /* The column is a UUID */ /***********************************************************************/ /* DB description class and block pointer definitions. */ diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 8c2842f8e41..e296553d8e2 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -1,11 +1,11 @@ /********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: PLGDBUTL */ /* ------------- */ -/* Version 4.0 */ +/* Version 4.1 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2018 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -215,35 +215,13 @@ int global_open(GLOBAL *g, int msgid, const char *path, int flags, int mode) } DllExport void SetTrc(void) - { +{ // If tracing is on, debug must be initialized. debug = pfile; - } // end of SetTrc - -#if 0 -/**************************************************************************/ -/* Tracing output function. */ -/**************************************************************************/ -void ptrc(char const *fmt, ...) - { - va_list ap; - va_start (ap, fmt); - -// if (trace == 0 || (trace == 1 && !pfile) || !fmt) -// printf("In %s wrong trace=%d pfile=%p fmt=%p\n", -// __FILE__, trace, pfile, fmt); - - if (trace == 1) - vfprintf(pfile, fmt, ap); - else - vprintf(fmt, ap); - - va_end (ap); - } // end of ptrc -#endif // 0 +} // end of SetTrc /**************************************************************************/ -/* Allocate the result structure that will contain result data. */ +/* SubAllocate the result structure that will contain result data. */ /**************************************************************************/ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, int *buftyp, XFLD *fldtyp, @@ -307,7 +285,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, else crp->Kdata = NULL; - if (trace) + if (trace(1)) htrc("Column(%d) %s type=%d len=%d value=%p\n", crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata); @@ -475,7 +453,7 @@ bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci) char *tp, *sp; bool b; - if (trace) + if (trace(2)) htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat); if (ci) { /* Case insensitive test */ @@ -544,7 +522,7 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp) ssize_t n; bool b, t = false; - if (trace) + if (trace(2)) htrc("Eval Like: sp=%s tp=%s\n", (sp) ? sp : "Null", (tp) ? tp : "Null"); @@ -582,7 +560,7 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp) else n = strlen(tp); /* Get length of pattern head */ - if (trace) + if (trace(2)) htrc(" testing: t=%d sp=%s tp=%s p=%p\n", t, sp, tp, p); if (n > (signed)strlen(sp)) /* If head is longer than strg */ @@ -628,7 +606,7 @@ bool EvalLikePattern(LPCSTR sp, LPCSTR tp) b = !strcmp(sp, tp); } /* endif p */ - if (trace) + if (trace(2)) htrc(" done: b=%d n=%d sp=%s tp=%s\n", b, n, (sp) ? sp : "Null", tp); @@ -668,7 +646,7 @@ char *MakeEscape(PGLOBAL g, char* str, char q) /***********************************************************************/ void PlugConvertConstant(PGLOBAL g, void* & value, short& type) { - if (trace) + if (trace(1)) htrc("PlugConvertConstant: value=%p type=%hd\n", value, type); if (type != TYPE_XOBJECT) { @@ -688,7 +666,7 @@ PDTP MakeDateFormat(PGLOBAL g, PCSZ dfmt, bool in, bool out, int flag) int rc; PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR)); - if (trace) + if (trace(1)) htrc("MakeDateFormat: dfmt=%s\n", dfmt); memset(pdp, 0, sizeof(DATPAR)); @@ -711,7 +689,7 @@ PDTP MakeDateFormat(PGLOBAL g, PCSZ dfmt, bool in, bool out, int flag) rc = fmdflex(pdp); pthread_mutex_unlock(&parmut); - if (trace) + if (trace(1)) htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc); return pdp; @@ -733,7 +711,7 @@ int ExtractDate(char *dts, PDTP pdp, int defy, int val[6]) else // assume standard MySQL date format fmt = "%4d-%2d-%2d %2d:%2d:%2d"; - if (trace > 1) + if (trace(2)) htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy); // Set default values for time only use @@ -816,7 +794,7 @@ int ExtractDate(char *dts, PDTP pdp, int defy, int val[6]) } // endfor i - if (trace > 1) + if (trace(2)) htrc("numval=%d val=(%d,%d,%d,%d,%d,%d)\n", numval, val[0], val[1], val[2], val[3], val[4], val[5]); @@ -833,18 +811,18 @@ FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype) PFBLOCK fp; PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; - if (trace) { + if (trace(1)) { htrc("PlugOpenFile: fname=%s ftype=%s\n", fname, ftype); htrc("dbuserp=%p\n", dbuserp); } // endif trace if ((fop= global_fopen(g, MSGID_OPEN_MODE_STRERROR, fname, ftype)) != NULL) { - if (trace) + if (trace(1)) htrc(" fop=%p\n", fop); fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); - if (trace) + if (trace(1)) htrc(" fp=%p\n", fp); // fname may be in volatile memory such as stack @@ -857,7 +835,7 @@ FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype) dbuserp->Openlist = fp; } /* endif fop */ - if (trace) + if (trace(1)) htrc(" returning fop=%p\n", fop); return (fop); @@ -888,7 +866,7 @@ int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all) { int rc = 0; - if (trace) + if (trace(1)) htrc("PlugCloseFile: fp=%p count=%hd type=%hd\n", fp, ((fp) ? fp->Count : 0), ((fp) ? fp->Type : 0)); @@ -1050,7 +1028,7 @@ int GetIniSize(char *section, char *key, char *def, char *ini) n *= 1024; } // endswitch c - if (trace) + if (trace(1)) htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n); return n; @@ -1086,7 +1064,7 @@ DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key, p = (PSZ)PlugSubAlloc(g, mp, n + 1); - if (trace) + if (trace(1)) htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf); strcpy(p, buf); @@ -1237,7 +1215,7 @@ char *GetExceptionDesc(PGLOBAL g, unsigned int e) /* so it can be freed at the normal or error query completion. */ /***********************************************************************/ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) - { +{ //bool b; size_t maxsub, minsub; void *arp = (area) ? area : g->Sarea; @@ -1253,7 +1231,7 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) // done to check whether the block is already there. // b = mp.Sub; mp.Sub = false; // Restrict suballocation to one quarter - } // endif Memp + } // endif Memp // Suballoc when possible if mp.Sub is initially true, but leaving // a minimum amount of storage for future operations such as the @@ -1263,35 +1241,40 @@ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp) maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub; mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2)); - if (trace > 1) - htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n", - arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub); + if (trace(2)) + htrc("PlgDBalloc: in %p size=%d used=%d free=%d sub=%d\n", + arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub); - if (!mp.Sub) { + if (!mp.Sub) { // For allocations greater than one fourth of remaining storage // in the area, do allocate from virtual storage. + const char*v = "malloc"; #if defined(__WIN__) - if (mp.Size >= BIGMEM) - mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - else + if (mp.Size >= BIGMEM) { + v = "VirtualAlloc"; + mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + } else #endif mp.Memp = malloc(mp.Size); - if (!mp.Inlist && mp.Memp) { + if (trace(8)) + htrc("PlgDBalloc: %s(%d) at %p\n", v, mp.Size, mp.Memp); + + if (!mp.Inlist && mp.Memp) { // New allocated block, put it in the memory block chain. PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; mp.Next = dbuserp->Memlist; dbuserp->Memlist = ∓ mp.Inlist = true; - } // endif mp + } // endif mp } else // Suballocating is Ok. mp.Memp = PlugSubAlloc(g, area, mp.Size); return mp.Memp; - } // end of PlgDBalloc +} // end of PlgDBalloc /***********************************************************************/ /* PlgDBrealloc: reallocates memory conditionally. */ @@ -1306,7 +1289,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) // assert (mp.Memp != NULL); #endif - if (trace > 1) + if (trace(2)) htrc("PlgDBrealloc: %p size=%d sub=%d\n", mp.Memp, mp.Size, mp.Sub); if (newsize == mp.Size) @@ -1326,10 +1309,14 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) mp.Memp = PlugSubAlloc(g, area, newsize); memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize)); PlgDBfree(m); // Free the old block - } else if (!(mp.Memp = realloc(mp.Memp, newsize))) { - mp = m; // Possible only if newsize > Size - return NULL; // Failed - } // endif's + } else { + if (!(mp.Memp = realloc(mp.Memp, newsize))) { + mp = m; // Possible only if newsize > Size + return NULL; // Failed + } else if (trace(8)) + htrc("PlgDBrealloc: realloc(%ld) at %p\n", newsize, mp.Memp); + + } // endif's mp.Size = newsize; } else if (!mp.Sub || newsize > mp.Size) { @@ -1352,7 +1339,7 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) } // endif's - if (trace) + if (trace(8)) htrc(" newsize=%d newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub); return mp.Memp; @@ -1363,16 +1350,20 @@ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize) /***********************************************************************/ void PlgDBfree(MBLOCK& mp) { - if (trace > 1) - htrc("PlgDBfree: %p sub=%d size=%d\n", mp.Memp, mp.Sub, mp.Size); - - if (!mp.Sub && mp.Memp) + if (!mp.Sub && mp.Memp) { + const char*v = "free"; #if defined(__WIN__) - if (mp.Size >= BIGMEM) - VirtualFree(mp.Memp, 0, MEM_RELEASE); - else + if (mp.Size >= BIGMEM) { + v = "VirtualFree"; + VirtualFree(mp.Memp, 0, MEM_RELEASE); + } else #endif - free(mp.Memp); + free(mp.Memp); + + if (trace(8)) + htrc("PlgDBfree: %s(%p) size=%d\n", v, mp.Memp, mp.Size); + + } // endif mp // Do not reset Next to avoid cutting the Mblock chain mp.Memp = NULL; @@ -1384,7 +1375,7 @@ void PlgDBfree(MBLOCK& mp) /* Program for sub-allocating one item in a storage area. */ /* Note: This function is equivalent to PlugSubAlloc except that in */ /* case of insufficient memory, it returns NULL instead of doing a */ -/* long jump. The caller must test the return value for error. */ +/* throw. The caller must test the return value for error. */ /***********************************************************************/ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) { @@ -1400,7 +1391,7 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */ pph = (PPOOLHEADER)memp; - if (trace > 1) + if (trace(16)) htrc("PlgDBSubAlloc: memp=%p size=%d used=%d free=%d\n", memp, size, pph->To_Free, pph->FreeBlk); @@ -1409,7 +1400,7 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) "Not enough memory in Work area for request of %d (used=%d free=%d)", (int) size, pph->To_Free, pph->FreeBlk); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return NULL; @@ -1422,7 +1413,7 @@ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size) pph->To_Free += size; // New offset of pool free block pph->FreeBlk -= size; // New size of pool free block - if (trace > 1) + if (trace(16)) htrc("Done memp=%p used=%d free=%d\n", memp, pph->To_Free, pph->FreeBlk); @@ -1453,7 +1444,7 @@ void PlugPutOut(PGLOBAL g, FILE *f, short t, void *v, uint n) { char m[64]; - if (trace) + if (trace(1)) htrc("PUTOUT: f=%p t=%d v=%p n=%d\n", f, t, v, n); if (!v) diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index 57215b2f745..ac102d03208 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -136,7 +136,7 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize) { PGLOBAL g; - if (trace > 1) + if (trace(2)) htrc("PlugInit: Language='%s'\n", ((!Language) ? "Null" : (char*)Language)); @@ -205,7 +205,7 @@ LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName) _splitpath(FileName, drive, direc, fname, ftype); - if (trace > 1) { + if (trace(2)) { htrc("after _splitpath: FileName=%s\n", FileName); htrc("drive=%s dir=%s fname=%s ext=%s\n", SVP(drive), direc, fname, ftype); @@ -213,7 +213,7 @@ LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName) _makepath(pBuff, drive, direc, fname, ""); - if (trace > 1) + if (trace(2)) htrc("buff='%s'\n", pBuff); return pBuff; @@ -246,7 +246,7 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath) char *drive = NULL, *defdrv = NULL; #endif - if (trace > 1) + if (trace(2)) htrc("prefix=%s fn=%s path=%s\n", prefix, FileName, defpath); if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) { @@ -263,7 +263,7 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath) #if !defined(__WIN__) if (*FileName == '~') { if (_fullpath(pBuff, FileName, _MAX_PATH)) { - if (trace > 1) + if (trace(2)) htrc("pbuff='%s'\n", pBuff); return pBuff; @@ -298,7 +298,7 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath) _splitpath(tmpdir, defdrv, defdir, NULL, NULL); - if (trace > 1) { + if (trace(2)) { htrc("after _splitpath: FileName=%s\n", FileName); #if defined(__WIN__) htrc("drive=%s dir=%s fname=%s ext=%s\n", drive, direc, fname, ftype); @@ -325,11 +325,11 @@ LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath) _makepath(newname, drive, direc, fname, ftype); - if (trace > 1) + if (trace(2)) htrc("newname='%s'\n", newname); if (_fullpath(pBuff, newname, _MAX_PATH)) { - if (trace > 1) + if (trace(2)) htrc("pbuff='%s'\n", pBuff); return pBuff; @@ -470,7 +470,7 @@ bool AllocSarea(PGLOBAL g, uint size) #if defined(DEVELOPMENT) if (true) { #else - if (trace) { + if (trace(8)) { #endif if (g->Sarea) htrc("Work area of %u allocated at %p\n", size, g->Sarea); @@ -498,7 +498,7 @@ void FreeSarea(PGLOBAL g) #if defined(DEVELOPMENT) if (true) #else - if (trace) + if (trace(8)) #endif htrc("Freeing Sarea at %p size = %d\n", g->Sarea, g->Sarea_Size); @@ -545,7 +545,7 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */ pph = (PPOOLHEADER)memp; - if (trace > 3) + if (trace(16)) htrc("SubAlloc in %p size=%d used=%d free=%d\n", memp, size, pph->To_Free, pph->FreeBlk); @@ -556,7 +556,7 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) "Not enough memory in %s area for request of %u (used=%d free=%d)", pname, (uint)size, pph->To_Free, pph->FreeBlk); - if (trace) + if (trace(1)) htrc("PlugSubAlloc: %s\n", g->Message); abort(); @@ -569,7 +569,7 @@ void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size) pph->To_Free += (OFFSET)size; /* New offset of pool free block */ pph->FreeBlk -= (uint)size; /* New size of pool free block */ - if (trace > 3) + if (trace(16)) htrc("Done memp=%p used=%d free=%d\n", memp, pph->To_Free, pph->FreeBlk); diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 0fb24baa785..e4f169575f8 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -450,7 +450,7 @@ int TABDEF::GetColCatInfo(PGLOBAL g) } // endswitch tc // lrecl must be at least recln to avoid buffer overflow - if (trace) + if (trace(1)) htrc("Lrecl: Calculated=%d defined=%d\n", recln, Hc->GetIntegerOption("Lrecl")); diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp index 5065d86ce6a..93de0598fe8 100644 --- a/storage/connect/tabcol.cpp +++ b/storage/connect/tabcol.cpp @@ -33,7 +33,7 @@ XTAB::XTAB(LPCSTR name, LPCSTR srcdef) : Name(name) Schema = NULL; Qualifier = NULL; - if (trace) + if (trace(1)) htrc("XTAB: making new TABLE %s %s\n", Name, Srcdef); } // end of XTAB constructor @@ -49,7 +49,7 @@ XTAB::XTAB(PTABLE tp) : Name(tp->Name) Schema = tp->Schema; Qualifier = tp->Qualifier; - if (trace) + if (trace(1)) htrc(" making copy TABLE %s %s\n", Name, SVP(Srcdef)); } // end of XTAB constructor @@ -61,7 +61,7 @@ PTABLE XTAB::Link(PTABLE tab2) { PTABLE tabp; - if (trace) + if (trace(1)) htrc("Linking tables %s... to %s\n", Name, tab2->Name); for (tabp = this; tabp->Next; tabp = tabp->Next) ; @@ -117,7 +117,7 @@ COLUMN::COLUMN(LPCSTR name) : Name(name) To_Col = NULL; Qualifier = NULL; - if (trace) + if (trace(1)) htrc(" making new COLUMN %s\n", Name); } // end of COLUMN constructor diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 3b850cfd258..29cbbb35765 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -704,7 +704,7 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) // savmin = cdp->GetBmap(); // cdp->SetBmap(PlugSubAlloc(g, NULL, block * sizeof(int))); - if (trace) + if (trace(1)) htrc("Dval(%p) Bmap(%p) col(%d) %s Block=%d lg=%d\n", cdp->GetDval(), cdp->GetBmap(), i, cdp->GetName(), block, lg); @@ -729,7 +729,7 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) memset(cdp->GetMax(), 0, block * lg); } // endif Type - if (trace) + if (trace(1)) htrc("min(%p) max(%p) col(%d) %s Block=%d lg=%d\n", cdp->GetMin(), cdp->GetMax(), i, cdp->GetName(), block, lg); @@ -901,7 +901,7 @@ bool TDBDOS::SaveBlockValues(PGLOBAL g) "wb", (int)errno, filename); strcat(strcat(g->Message, ": "), strerror(errno)); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); return true; @@ -1634,7 +1634,7 @@ int TDBDOS::TestBlock(PGLOBAL g) To_Filter = NULL; // So remove filter } // endswitch Beval - if (trace) + if (trace(1)) htrc("BF Eval Beval=%d\n", Beval); } // endif To_BlkFil @@ -1779,7 +1779,7 @@ int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add) return RC_INFO; // Error or Physical table does not exist } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); rc = RC_FX; } catch (const char *msg) { @@ -1902,7 +1902,7 @@ bool TDBDOS::InitialyzeIndex(PGLOBAL g, volatile PIXDEF xdp, bool sorted) } // endif brc } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); brc = true; } catch (const char *msg) { @@ -2001,7 +2001,7 @@ int TDBDOS::Cardinality(PGLOBAL g) if (len >= 0) { int rec; - if (trace) + if (trace(1)) htrc("Estimating lines len=%d ending=%d/n", len, ((PDOSDEF)To_Def)->Ending); @@ -2018,7 +2018,7 @@ int TDBDOS::Cardinality(PGLOBAL g) Cardinal = (len + rec - 1) / rec; - if (trace) + if (trace(1)) htrc("avglen=%d MaxSize%d\n", rec, Cardinal); } // endif len @@ -2048,7 +2048,7 @@ int TDBDOS::GetMaxSize(PGLOBAL g) if (len >= 0) { int rec; - if (trace) + if (trace(1)) htrc("Estimating lines len=%d ending=%d/n", len, ((PDOSDEF)To_Def)->Ending); @@ -2059,7 +2059,7 @@ int TDBDOS::GetMaxSize(PGLOBAL g) rec = EstimatedLength() + ((PDOSDEF)To_Def)->Ending; MaxSize = (len + rec - 1) / rec; - if (trace) + if (trace(1)) htrc("avglen=%d MaxSize%d\n", rec, MaxSize); } // endif len @@ -2108,7 +2108,7 @@ bool TDBDOS::IsUsingTemp(PGLOBAL) /***********************************************************************/ bool TDBDOS::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("DOS OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode); @@ -2184,7 +2184,7 @@ bool TDBDOS::OpenDB(PGLOBAL g) } else memset(To_Line, 0, linelen); - if (trace) + if (trace(1)) htrc("OpenDos: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line); if (SkipHeader(g)) // When called from CSV/FMT files @@ -2202,7 +2202,7 @@ bool TDBDOS::OpenDB(PGLOBAL g) /***********************************************************************/ int TDBDOS::ReadDB(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("DOS ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p To_Line=%p\n", GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex, To_Line); @@ -2227,7 +2227,7 @@ int TDBDOS::ReadDB(PGLOBAL g) if (SetRecpos(g, recpos)) return RC_FX; - if (trace > 1) + if (trace(2)) htrc("File position is now %d\n", GetRecpos()); if (Mode == MODE_READ) @@ -2243,7 +2243,7 @@ int TDBDOS::ReadDB(PGLOBAL g) } // endif To_Kindex - if (trace > 1) + if (trace(2)) htrc(" ReadDB: this=%p To_Line=%p\n", this, To_Line); /*********************************************************************/ @@ -2279,14 +2279,14 @@ bool TDBDOS::PrepareWriting(PGLOBAL) /***********************************************************************/ int TDBDOS::WriteDB(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("DOS WriteDB: R%d Mode=%d \n", Tdb_No, Mode); // Make the line to write if (PrepareWriting(g)) return RC_FX; - if (trace > 1) + if (trace(2)) htrc("Write: line is='%s'\n", To_Line); // Now start the writing process @@ -2403,7 +2403,7 @@ DOSCOL::DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am) Dcm = (*p) ? atoi(p) : GetScale(); } // endif fmt - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); } // end of DOSCOL constructor @@ -2518,7 +2518,7 @@ void DOSCOL::ReadColumn(PGLOBAL g) double dval; PTDBDOS tdbp = (PTDBDOS)To_Tdb; - if (trace > 1) + if (trace(2)) htrc( "DOS ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n", Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type); @@ -2607,13 +2607,13 @@ void DOSCOL::WriteColumn(PGLOBAL g) int i, k, len, field; PTDBDOS tdbp = (PTDBDOS)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("DOS WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, tdbp->GetTdb_No(), ColUse, Status); p = tdbp->To_Line + Deplac; - if (trace > 1) + if (trace(2)) htrc("Lrecl=%d deplac=%d int=%d\n", tdbp->Lrecl, Deplac, Long); field = Long; @@ -2630,7 +2630,7 @@ void DOSCOL::WriteColumn(PGLOBAL g) } // endif Ftype - if (trace > 1) + if (trace(2)) htrc("Long=%d field=%d coltype=%d colval=%p\n", Long, field, Buf_Type, Value); @@ -2703,7 +2703,7 @@ void DOSCOL::WriteColumn(PGLOBAL g) } else // Standard CONNECT format p2 = Value->ShowValue(Buf, field); - if (trace) + if (trace(1)) htrc("new length(%p)=%d\n", p2, strlen(p2)); if ((len = strlen(p2)) > field) { @@ -2714,7 +2714,7 @@ void DOSCOL::WriteColumn(PGLOBAL g) if (p2[i] == '.') p2[i] = Dsp; - if (trace > 1) + if (trace(2)) htrc("buffer=%s\n", p2); /*******************************************************************/ @@ -2724,7 +2724,7 @@ void DOSCOL::WriteColumn(PGLOBAL g) memset(p, ' ', field); memcpy(p, p2, len); - if (trace > 1) + if (trace(2)) htrc(" col write: '%.*s'\n", len, p); } // endif Use diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 948b357dc1f..bdde37adaad 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -29,6 +29,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ friend class TXTFAM; friend class DBFBASE; friend class UNZIPUTL; + friend class JSONCOL; public: // Constructor DOSDEF(void); diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp index 207c8401c7b..7be6c0e8328 100644 --- a/storage/connect/tabext.cpp +++ b/storage/connect/tabext.cpp @@ -433,7 +433,7 @@ bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt) } else Query->Resize(len); - if (trace) + if (trace(33)) htrc("Query=%s\n", Query->GetStr()); return false; @@ -527,7 +527,7 @@ bool TDBEXT::MakeCommand(PGLOBAL g) return true; } // endif p - if (trace) + if (trace(33)) htrc("Command=%s\n", stmt); Query = new(g)STRING(g, 0, stmt); @@ -585,7 +585,7 @@ EXTCOL::EXTCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) tdbp->SetColumns(this); } // endif cprec - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); // Set additional remote access method information for column. diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index a78d5861e53..1969fd4465f 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -291,7 +291,7 @@ bool TDBFIX::IsUsingTemp(PGLOBAL) /***********************************************************************/ bool TDBFIX::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("FIX OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d Ftype=%d\n", this, Tdb_No, Use, To_Key_Col, Mode, Ftype); @@ -345,7 +345,7 @@ bool TDBFIX::OpenDB(PGLOBAL g) /*********************************************************************/ To_BlkFil = InitBlockFilter(g, To_Filter); - if (trace) + if (trace(1)) htrc("OpenFix: R%hd mode=%d BlkFil=%p\n", Tdb_No, Mode, To_BlkFil); /*********************************************************************/ @@ -474,7 +474,7 @@ void BINCOL::ReadColumn(PGLOBAL g) int rc; PTDBFIX tdbp = (PTDBFIX)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("BIN ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n", Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type); @@ -565,7 +565,7 @@ void BINCOL::WriteColumn(PGLOBAL g) longlong n; PTDBFIX tdbp = (PTDBFIX)To_Tdb; - if (trace) { + if (trace(1)) { htrc("BIN WriteColumn: col %s R%d coluse=%.4X status=%.4X", Name, tdbp->GetTdb_No(), ColUse, Status); htrc(" Lrecl=%d\n", tdbp->Lrecl); diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index f616f24d16b..63fa2a63668 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -185,7 +185,7 @@ PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info) mxr = MY_MAX(0, tdp->Maxerr); - if (trace) + if (trace(1)) htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n", SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr); @@ -379,7 +379,7 @@ PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info) skip: ; // Skip erroneous line } // endfor num_read - if (trace) { + if (trace(1)) { htrc("imax=%d Lengths:", imax); for (i = 0; i < imax; i++) @@ -391,7 +391,7 @@ PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info) tdbp->CloseDB(g); skipit: - if (trace) + if (trace(1)) htrc("CSVColumns: imax=%d hmax=%d len=%d\n", imax, hmax, length[0]); @@ -701,7 +701,7 @@ int TDBCSV::EstimatedLength(void) int n = 0; PCOLDEF cdp; - if (trace) + if (trace(1)) htrc("EstimatedLength: Fields=%d Columns=%p\n", Fields, Columns); for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) @@ -906,7 +906,7 @@ int TDBCSV::ReadBuffer(PGLOBAL g) int i, n, len, rc = Txfp->ReadBuffer(g); bool bad = false; - if (trace > 1) + if (trace(2)) htrc("CSV: Row is '%s' rc=%d\n", To_Line, rc); if (rc != RC_OK || !Fields) @@ -1024,7 +1024,7 @@ bool TDBCSV::PrepareWriting(PGLOBAL g) char sep[2], qot[2]; int i, nlen, oldlen = strlen(To_Line); - if (trace > 1) + if (trace(2)) htrc("CSV WriteDB: R%d Mode=%d key=%p link=%p\n", Tdb_No, Mode, To_Key_Col, To_Link); @@ -1090,7 +1090,7 @@ bool TDBCSV::PrepareWriting(PGLOBAL g) To_Line[nlen] = '\0'; } // endif - if (trace > 1) + if (trace(2)) htrc("Write: line is=%s", To_Line); return false; @@ -1118,7 +1118,7 @@ int TDBCSV::CheckWrite(PGLOBAL g) { int maxlen, n, nlen = (Fields - 1); - if (trace > 1) + if (trace(2)) htrc("CheckWrite: R%d Mode=%d\n", Tdb_No, Mode); // Before writing the line we must check its length @@ -1290,7 +1290,7 @@ int TDBFMT::ReadBuffer(PGLOBAL g) else ++Linenum; - if (trace > 1) + if (trace(2)) htrc("FMT: Row %d is '%s' rc=%d\n", Linenum, To_Line, rc); // Find the offsets and lengths of the columns for this row @@ -1445,7 +1445,7 @@ void CSVCOL::ReadColumn(PGLOBAL g) Deplac = tdbp->Offset[Fldnum]; // Field offset Long = tdbp->Fldlen[Fldnum]; // Field length - if (trace > 1) + if (trace(2)) htrc("CSV ReadColumn %s Fldnum=%d offset=%d fldlen=%d\n", Name, Fldnum, Deplac, Long); @@ -1489,13 +1489,13 @@ void CSVCOL::WriteColumn(PGLOBAL g) int flen; PTDBCSV tdbp = (PTDBCSV)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("CSV WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, tdbp->GetTdb_No(), ColUse, Status); flen = GetLength(); - if (trace > 1) + if (trace(2)) htrc("Lrecl=%d Long=%d field=%d coltype=%d colval=%p\n", tdbp->Lrecl, Long, flen, Buf_Type, Value); @@ -1510,7 +1510,7 @@ void CSVCOL::WriteColumn(PGLOBAL g) /*********************************************************************/ p = Value->ShowValue(buf); - if (trace > 1) + if (trace(2)) htrc("new length(%p)=%d\n", p, strlen(p)); if ((signed)strlen(p) > flen) { @@ -1522,7 +1522,7 @@ void CSVCOL::WriteColumn(PGLOBAL g) if (p[i] == '.') p[i] = Dsp; - if (trace > 1) + if (trace(2)) htrc("buffer=%s\n", p); /*********************************************************************/ @@ -1536,7 +1536,7 @@ void CSVCOL::WriteColumn(PGLOBAL g) } else strncpy(tdbp->Field[Fldnum], p, flen); - if (trace > 1) + if (trace(2)) htrc(" col written: '%s'\n", p); } // end of WriteColumn diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp index b6a1487955b..adbfb2168ae 100644 --- a/storage/connect/tabjdbc.cpp +++ b/storage/connect/tabjdbc.cpp @@ -153,7 +153,7 @@ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) // Tabname = GetStringCatInfo(g, "Tabname", Tabname); } // endif - if (trace) + if (trace(1)) htrc("server: %s Tabname: %s", url, Tabname); // Now make the required URL @@ -470,7 +470,7 @@ bool TDBJDBC::MakeInsert(PGLOBAL g) else Prepared = true; - if (trace) + if (trace(33)) htrc("Insert=%s\n", Query->GetStr()); return false; @@ -553,7 +553,7 @@ bool TDBJDBC::OpenDB(PGLOBAL g) { bool rc = true; - if (trace) + if (trace(1)) htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode); @@ -605,6 +605,10 @@ bool TDBJDBC::OpenDB(PGLOBAL g) else if (Quoted) Quote = Jcp->GetQuoteChar(); + if (Mode != MODE_READ && Mode != MODE_READX) + if (Jcp->SetUUID(g, this)) + PushWarning(g, this, 1); + Use = USE_OPEN; // Do it now in case we are recursively called /*********************************************************************/ @@ -767,7 +771,7 @@ bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) Mode = MODE_READ; } // endif's op - if (trace) + if (trace(33)) htrc("JDBC ReadKey: Query=%s\n", Query->GetStr()); rc = Jcp->ExecuteQuery((char*)Query->GetStr()); @@ -783,7 +787,7 @@ int TDBJDBC::ReadDB(PGLOBAL g) { int rc; - if (trace > 1) + if (trace(2)) htrc("JDBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode); if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { @@ -836,7 +840,7 @@ int TDBJDBC::ReadDB(PGLOBAL g) } // endif placed - if (trace > 1) + if (trace(2)) htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc); return rc; @@ -897,7 +901,7 @@ int TDBJDBC::WriteDB(PGLOBAL g) Query->RepLast(')'); - if (trace > 1) + if (trace(2)) htrc("Inserting: %s\n", Query->GetStr()); rc = Jcp->ExecuteUpdate(Query->GetStr()); @@ -925,7 +929,7 @@ int TDBJDBC::DeleteDB(PGLOBAL g, int irc) AftRows = Jcp->m_Aff; sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); PushWarning(g, this, 0); // 0 means a Note @@ -946,14 +950,14 @@ void TDBJDBC::CloseDB(PGLOBAL g) if (Jcp) Jcp->Close(); - if (trace) + if (trace(1)) htrc("JDBC CloseDB: closing %s\n", Name); if (!Werr && (Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) { sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); PushWarning(g, this, 0); // 0 means a Note @@ -970,6 +974,7 @@ void TDBJDBC::CloseDB(PGLOBAL g) JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) : EXTCOL(cdp, tdbp, cprec, i, am) { + uuid = false; } // end of JDBCCOL constructor /***********************************************************************/ @@ -977,6 +982,7 @@ JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) /***********************************************************************/ JDBCCOL::JDBCCOL(void) : EXTCOL() { + uuid = false; } // end of JDBCCOL constructor /***********************************************************************/ @@ -985,12 +991,11 @@ JDBCCOL::JDBCCOL(void) : EXTCOL() /***********************************************************************/ JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) { + uuid = col1->uuid; } // end of JDBCCOL copy constructor /***********************************************************************/ -/* ReadColumn: when SQLFetch is used there is nothing to do as the */ -/* column buffer was bind to the record set. This is also the case */ -/* when calculating MaxSize (Bufp is NULL even when Rows is not). */ +/* ReadColumn: retrieve the column value via the JDBC driver. */ /***********************************************************************/ void JDBCCOL::ReadColumn(PGLOBAL g) { @@ -1117,7 +1122,7 @@ bool TDBXJDC::OpenDB(PGLOBAL g) { bool rc = false; - if (trace) + if (trace(1)) htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode); diff --git a/storage/connect/tabjdbc.h b/storage/connect/tabjdbc.h index d422ed26ef2..078129a14e3 100644 --- a/storage/connect/tabjdbc.h +++ b/storage/connect/tabjdbc.h @@ -101,6 +101,7 @@ protected: /***********************************************************************/ class JDBCCOL : public EXTCOL { friend class TDBJDBC; + friend class JDBConn; public: // Constructors JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "JDBC"); @@ -119,6 +120,7 @@ protected: JDBCCOL(void); // Members + bool uuid; // For PostgreSQL }; // end of class JDBCCOL /***********************************************************************/ diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 8778b7d4b47..6151d924a9f 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -54,16 +54,16 @@ USETEMP UseTemp(void); char *GetJsonNull(void); -typedef struct _jncol { - struct _jncol *Next; - char *Name; - char *Fmt; - int Type; - int Len; - int Scale; - bool Cbn; - bool Found; -} JCOL, *PJCL; +//typedef struct _jncol { +// struct _jncol *Next; +// char *Name; +// char *Fmt; +// int Type; +// int Len; +// int Scale; +// bool Cbn; +// bool Found; +//} JCOL, *PJCL; /***********************************************************************/ /* JSONColumns: construct the result blocks containing the description */ @@ -76,26 +76,13 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT}; static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0}; - char *p, colname[65], fmt[129]; - int i, j, lvl, n = 0; + int i, n = 0; int ncol = sizeof(buftyp) / sizeof(int); - bool mgo = (GetTypeID(topt->type) == TAB_MONGO); - PCSZ sep, level; - PVAL valp; - JCOL jcol; - PJCL jcp, fjcp = NULL, pjcp = NULL; - PJPR *jrp, jpp; - PJSON jsp; - PJVAL jvp; - PJOB row; - PJDEF tdp; - TDBJSN *tjnp = NULL; - PJTDB tjsp = NULL; + PJCL jcp; + JSONDISC *pjdc = NULL; PQRYRES qrp; PCOLRES crp; - jcol.Name = jcol.Fmt = NULL; - if (info) { length[0] = 128; length[7] = 256; @@ -107,20 +94,100 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) return NULL; } // endif Multiple - /*********************************************************************/ - /* Open the input file. */ + pjdc = new(g) JSONDISC(g, length); + + if (!(n = pjdc->GetColumns(g, db, dsn, topt))) + return NULL; + + skipit: + if (trace(1)) + htrc("JSONColumns: n=%d len=%d\n", n, length[0]); + + /*********************************************************************/ + /* Allocate the structures used to refer to the result set. */ + /*********************************************************************/ + qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, + buftyp, fldtyp, length, false, false); + + crp = qrp->Colresp->Next->Next->Next->Next->Next->Next; + crp->Name = "Nullable"; + crp->Next->Name = "Jpath"; + + if (info || !qrp) + return qrp; + + qrp->Nblin = n; + /*********************************************************************/ - level = GetStringTableOption(g, topt, "Level", NULL); + /* Now get the results into blocks. */ + /*********************************************************************/ + for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) { + if (jcp->Type == TYPE_UNKNOWN) + jcp->Type = TYPE_STRING; // Void column + + crp = qrp->Colresp; // Column Name + crp->Kdata->SetValue(jcp->Name, i); + crp = crp->Next; // Data Type + crp->Kdata->SetValue(jcp->Type, i); + crp = crp->Next; // Type Name + crp->Kdata->SetValue(GetTypeName(jcp->Type), i); + crp = crp->Next; // Precision + crp->Kdata->SetValue(jcp->Len, i); + crp = crp->Next; // Length + crp->Kdata->SetValue(jcp->Len, i); + crp = crp->Next; // Scale (precision) + crp->Kdata->SetValue(jcp->Scale, i); + crp = crp->Next; // Nullable + crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i); + crp = crp->Next; // Field format + + if (crp->Kdata) + crp->Kdata->SetValue(jcp->Fmt, i); + + } // endfor i + + /*********************************************************************/ + /* Return the result pointer. */ + /*********************************************************************/ + return qrp; + } // end of JSONColumns + +/* -------------------------- Class JSONDISC ------------------------- */ + +/***********************************************************************/ +/* Class used to get the columns of a JSON table. */ +/***********************************************************************/ +JSONDISC::JSONDISC(PGLOBAL g, uint *lg) +{ + length = lg; + jcp = fjcp = pjcp = NULL; + tjnp = NULL; + jpp = NULL; + tjsp = NULL; + jsp = NULL; + row = NULL; + sep = NULL; + i = n = bf = ncol = lvl = 0; + all = false; +} // end of JSONDISC constructor + +int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) +{ + bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + PCSZ level = GetStringTableOption(g, topt, "Level", NULL); if (level) { lvl = atoi(level); lvl = (lvl > 16) ? 16 : lvl; - } else + } else lvl = 0; sep = GetStringTableOption(g, topt, "Separator", "."); - tdp = new(g) JSONDEF; + /*********************************************************************/ + /* Open the input file. */ + /*********************************************************************/ + tdp = new(g) JSONDEF; #if defined(ZIP_SUPPORT) tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); @@ -128,23 +195,23 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); if (!(tdp->Database = SetPath(g, db))) - return NULL; + return 0ULL; - tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); - tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; - tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); + tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); + tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; + tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false); tdp->Uri = (dsn && *dsn ? dsn : NULL); if (!tdp->Fn && !tdp->Uri) { strcpy(g->Message, MSG(MISSING_FNAME)); - return NULL; + return 0; } // endif Fn - if (trace) - htrc("File %s objname=%s pretty=%d lvl=%d\n", - tdp->Fn, tdp->Objname, tdp->Pretty, lvl); + if (trace(1)) + htrc("File %s objname=%s pretty=%d lvl=%d\n", + tdp->Fn, tdp->Objname, tdp->Pretty, lvl); if (tdp->Uri) { #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) @@ -160,34 +227,34 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) tdp->Pretty = 0; #else // !MONGO_SUPPORT sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return NULL; + return 0; #endif // !MONGO_SUPPORT } // endif Uri - if (tdp->Pretty == 2) { + if (tdp->Pretty == 2) { if (tdp->Zipped) { #if defined(ZIP_SUPPORT) tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp)); #else // !ZIP_SUPPORT sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); - return NULL; + return 0; #endif // !ZIP_SUPPORT - } else - tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); + } else + tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); - if (tjsp->MakeDocument(g)) - return NULL; + if (tjsp->MakeDocument(g)) + return 0ULL; - jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; - } else { - if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) + jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; + } else { + if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) if (!mgo) { sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); - return NULL; - } else + return 0ULL; + } else tdp->Lrecl = 8192; // Should be enough - tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); + tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); if (tdp->Zipped) { #if defined(ZIP_SUPPORT) @@ -196,36 +263,36 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); return NULL; #endif // !ZIP_SUPPORT - } else if (tdp->Uri) { + } else if (tdp->Uri) { if (tdp->Driver && toupper(*tdp->Driver) == 'C') { #if defined(CMGO_SUPPORT) tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); #else sprintf(g->Message, "Mongo %s Driver not available", "C"); - return NULL; + return 0ULL; #endif - } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') { + } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') { #if defined(JAVA_SUPPORT) tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); #else sprintf(g->Message, "Mongo %s Driver not available", "Java"); - return NULL; + return 0ULL; #endif - } else { // Driver not specified + } else { // Driver not specified #if defined(CMGO_SUPPORT) tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); #elif defined(JAVA_SUPPORT) tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); #else sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return NULL; + return 0ULL; #endif } // endif Driver - } else + } else tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); - tjnp->SetMode(MODE_READ); + tjnp->SetMode(MODE_READ); // Allocate the parse work memory PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); @@ -237,248 +304,227 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) tjnp->SetG(G); if (tjnp->OpenDB(g)) - return NULL; + return 0ULL; - switch (tjnp->ReadDB(g)) { - case RC_EF: - strcpy(g->Message, "Void json table"); - case RC_FX: - goto err; - default: - jsp = tjnp->GetRow(); - } // endswitch ReadDB + switch (tjnp->ReadDB(g)) { + case RC_EF: + strcpy(g->Message, "Void json table"); + case RC_FX: + goto err; + default: + jsp = tjnp->GetRow(); + } // endswitch ReadDB - } // endif pretty + } // endif pretty - if (!(row = (jsp) ? jsp->GetObject() : NULL)) { - strcpy(g->Message, "Can only retrieve columns from object rows"); - goto err; - } // endif row + if (!(row = (jsp) ? jsp->GetObject() : NULL)) { + strcpy(g->Message, "Can only retrieve columns from object rows"); + goto err; + } // endif row - jcol.Next = NULL; - jcol.Found = true; - colname[64] = 0; - fmt[128] = 0; + all = GetBooleanTableOption(g, topt, "Fullarray", false); + jcol.Name = jcol.Fmt = NULL; + jcol.Next = NULL; + jcol.Found = true; + colname[0] = 0; if (!tdp->Uri) { - *fmt = '$'; + fmt[0] = '$'; fmt[1] = '.'; - p = fmt + 2; - } else - p = fmt; - - jrp = (PJPR*)PlugSubAlloc(g, NULL, sizeof(PJPR) * MY_MAX(lvl, 0)); - - /*********************************************************************/ - /* Analyse the JSON tree and define columns. */ - /*********************************************************************/ - for (i = 1; ; i++) { - for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) { - for (j = 0; j < lvl; j++) - jrp[j] = NULL; - - more: - strncpy(colname, jpp->GetKey(), 64); - *p = 0; - j = 0; - jvp = jpp->GetVal(); - - retry: - if ((valp = jvp ? jvp->GetValue() : NULL)) { - jcol.Type = valp->GetType(); - jcol.Len = valp->GetValLen(); - jcol.Scale = valp->GetValPrec(); - jcol.Cbn = valp->IsNull(); - } else if (!jvp || jvp->IsNull()) { - jcol.Type = TYPE_UNKNOWN; - jcol.Len = jcol.Scale = 0; - jcol.Cbn = true; - } else if (j < lvl) { - if (!*p) - strcat(fmt, colname); - - jsp = jvp->GetJson(); - - switch (jsp->GetType()) { - case TYPE_JOB: - if (!jrp[j]) - jrp[j] = jsp->GetFirst(); - - if (*jrp[j]->GetKey() != '$') { - strncat(strncat(fmt, sep, 128), jrp[j]->GetKey(), 128); - strncat(strncat(colname, "_", 64), jrp[j]->GetKey(), 64); - } // endif Key - - jvp = jrp[j]->GetVal(); - j++; - break; - case TYPE_JAR: - if (!tdp->Xcol || stricmp(tdp->Xcol, colname)) { - if (tdp->Uri) - strncat(strncat(fmt, sep, 128), "0", 128); - else - strncat(fmt, "[0]", 128); - - } else - strncat(fmt, (tdp->Uri ? sep : "[]"), 128); - - jvp = jsp->GetValue(0); - break; - default: - sprintf(g->Message, "Logical error after %s", fmt); - goto err; - } // endswitch jsp - - goto retry; - } else if (lvl >= 0) { - jcol.Type = TYPE_STRING; - jcol.Len = 256; - jcol.Scale = 0; - jcol.Cbn = true; - } else - continue; + bf = 2; + } // endif Uri - // Check whether this column was already found - for (jcp = fjcp; jcp; jcp = jcp->Next) - if (!strcmp(colname, jcp->Name)) - break; - - if (jcp) { - if (jcp->Type != jcol.Type) { - if (jcp->Type == TYPE_UNKNOWN) - jcp->Type = jcol.Type; - else if (jcol.Type != TYPE_UNKNOWN) - jcp->Type = TYPE_STRING; + /*********************************************************************/ + /* Analyse the JSON tree and define columns. */ + /*********************************************************************/ + for (i = 1; ; i++) { + for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) { + strncpy(colname, jpp->GetKey(), 64); + fmt[bf] = 0; + + if (Find(g, jpp->GetVal(), MY_MIN(lvl, 0))) + goto err; + + } // endfor jpp + + // Missing column can be null + for (jcp = fjcp; jcp; jcp = jcp->Next) { + jcp->Cbn |= !jcp->Found; + jcp->Found = false; + } // endfor jcp + + if (tdp->Pretty != 2) { + // Read next record + switch (tjnp->ReadDB(g)) { + case RC_EF: + jsp = NULL; + break; + case RC_FX: + goto err; + default: + jsp = tjnp->GetRow(); + } // endswitch ReadDB - } // endif Type + } else + jsp = tjsp->GetDoc()->GetValue(i); - if (*p && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { - jcp->Fmt = PlugDup(g, fmt); - length[7] = MY_MAX(length[7], strlen(fmt)); - } // endif fmt - - jcp->Len = MY_MAX(jcp->Len, jcol.Len); - jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); - jcp->Cbn |= jcol.Cbn; - jcp->Found = true; - } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) { - // New column - jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL)); - *jcp = jcol; - jcp->Cbn |= (i > 1); - jcp->Name = PlugDup(g, colname); - length[0] = MY_MAX(length[0], strlen(colname)); - - if (*p) { - jcp->Fmt = PlugDup(g, fmt); - length[7] = MY_MAX(length[7], strlen(fmt)); - } else - jcp->Fmt = NULL; - - if (pjcp) { - jcp->Next = pjcp->Next; - pjcp->Next = jcp; - } else - fjcp = jcp; + if (!(row = (jsp) ? jsp->GetObject() : NULL)) + break; - n++; - } // endif jcp + } // endfor i - pjcp = jcp; + if (tdp->Pretty != 2) + tjnp->CloseDB(g); - for (j = lvl - 1; j >= 0; j--) - if (jrp[j] && (jrp[j] = jrp[j]->GetNext())) - goto more; + return n; - } // endfor jpp +err: + if (tdp->Pretty != 2) + tjnp->CloseDB(g); - // Missing column can be null - for (jcp = fjcp; jcp; jcp = jcp->Next) { - jcp->Cbn |= !jcp->Found; - jcp->Found = false; - } // endfor jcp + return 0; +} // end of GetColumns - if (tdp->Pretty != 2) { - // Read next record - switch (tjnp->ReadDB(g)) { - case RC_EF: - jsp = NULL; - break; - case RC_FX: - goto err; - default: - jsp = tjnp->GetRow(); - } // endswitch ReadDB +bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, int j) +{ + char *p, *pc = colname + strlen(colname); + int ars; + PJOB job; + PJAR jar; + + if ((valp = jvp ? jvp->GetValue() : NULL)) { + jcol.Type = valp->GetType(); + jcol.Len = valp->GetValLen(); + jcol.Scale = valp->GetValPrec(); + jcol.Cbn = valp->IsNull(); + } else if (!jvp || jvp->IsNull()) { + jcol.Type = TYPE_UNKNOWN; + jcol.Len = jcol.Scale = 0; + jcol.Cbn = true; + } else if (j < lvl) { + if (!fmt[bf]) + strcat(fmt, colname); + + p = fmt + strlen(fmt); + jsp = jvp->GetJson(); + + switch (jsp->GetType()) { + case TYPE_JOB: + job = (PJOB)jsp; + + for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) { + if (*jrp->GetKey() != '$') { + strncat(strncat(fmt, sep, 128), jrp->GetKey(), 128); + strncat(strncat(colname, "_", 64), jrp->GetKey(), 64); + } // endif Key + + if (Find(g, jrp->GetVal(), j + 1)) + return true; + + *p = *pc = 0; + } // endfor jrp + + return false; + case TYPE_JAR: + jar = (PJAR)jsp; + + if (all || (tdp->Xcol && !stricmp(tdp->Xcol, colname))) + ars = jar->GetSize(false); + else + ars = MY_MIN(jar->GetSize(false), 1); - } else - jsp = tjsp->GetDoc()->GetValue(i); + for (int k = 0; k < ars; k++) { + if (!tdp->Xcol || stricmp(tdp->Xcol, colname)) { + sprintf(buf, "%d", k); - if (!(row = (jsp) ? jsp->GetObject() : NULL)) - break; + if (tdp->Uri) + strncat(strncat(fmt, sep, 128), buf, 128); + else + strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128); - } // endor i + if (all) + strncat(strncat(colname, "_", 64), buf, 64); - if (tdp->Pretty != 2) - tjnp->CloseDB(g); + } else + strncat(fmt, (tdp->Uri ? sep : "[*]"), 128); - skipit: - if (trace) - htrc("JSONColumns: n=%d len=%d\n", n, length[0]); + if (Find(g, jar->GetValue(k), j)) + return true; - /*********************************************************************/ - /* Allocate the structures used to refer to the result set. */ - /*********************************************************************/ - qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, - buftyp, fldtyp, length, false, false); + *p = *pc = 0; + } // endfor k - crp = qrp->Colresp->Next->Next->Next->Next->Next->Next; - crp->Name = "Nullable"; - crp->Next->Name = "Jpath"; + return false; + default: + sprintf(g->Message, "Logical error after %s", fmt); + return true; + } // endswitch Type - if (info || !qrp) - return qrp; + } else if (lvl >= 0) { + jcol.Type = TYPE_STRING; + jcol.Len = 256; + jcol.Scale = 0; + jcol.Cbn = true; + } else + return false; - qrp->Nblin = n; + AddColumn(g); + return false; +} // end of Find - /*********************************************************************/ - /* Now get the results into blocks. */ - /*********************************************************************/ - for (i = 0, jcp = fjcp; jcp; i++, jcp = jcp->Next) { - if (jcp->Type == TYPE_UNKNOWN) - jcp->Type = TYPE_STRING; // Void column +void JSONDISC::AddColumn(PGLOBAL g) +{ + bool b = fmt[bf] != 0; // True if formatted - crp = qrp->Colresp; // Column Name - crp->Kdata->SetValue(jcp->Name, i); - crp = crp->Next; // Data Type - crp->Kdata->SetValue(jcp->Type, i); - crp = crp->Next; // Type Name - crp->Kdata->SetValue(GetTypeName(jcp->Type), i); - crp = crp->Next; // Precision - crp->Kdata->SetValue(jcp->Len, i); - crp = crp->Next; // Length - crp->Kdata->SetValue(jcp->Len, i); - crp = crp->Next; // Scale (precision) - crp->Kdata->SetValue(jcp->Scale, i); - crp = crp->Next; // Nullable - crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i); - crp = crp->Next; // Field format + // Check whether this column was already found + for (jcp = fjcp; jcp; jcp = jcp->Next) + if (!strcmp(colname, jcp->Name)) + break; - if (crp->Kdata) - crp->Kdata->SetValue(jcp->Fmt, i); + if (jcp) { + if (jcp->Type != jcol.Type) { + if (jcp->Type == TYPE_UNKNOWN) + jcp->Type = jcol.Type; + else if (jcol.Type != TYPE_UNKNOWN) + jcp->Type = TYPE_STRING; + + } // endif Type + + if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } // endif fmt + + jcp->Len = MY_MAX(jcp->Len, jcol.Len); + jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); + jcp->Cbn |= jcol.Cbn; + jcp->Found = true; + } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) { + // New column + jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL)); + *jcp = jcol; + jcp->Cbn |= (i > 1); + jcp->Name = PlugDup(g, colname); + length[0] = MY_MAX(length[0], strlen(colname)); + + if (b) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } else + jcp->Fmt = NULL; - } // endfor i + if (pjcp) { + jcp->Next = pjcp->Next; + pjcp->Next = jcp; + } else + fjcp = jcp; - /*********************************************************************/ - /* Return the result pointer. */ - /*********************************************************************/ - return qrp; + n++; + } // endif jcp -err: - if (tdp->Pretty != 2) - tjnp->CloseDB(g); + pjcp = jcp; +} // end of AddColumn - return NULL; - } // end of JSONColumns /* -------------------------- Class JSONDEF -------------------------- */ @@ -513,6 +559,7 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR, int poff) Limit = GetIntCatInfo("Limit", 10); Base = GetIntCatInfo("Base", 0) ? 1 : 0; Sep = *GetStringCatInfo(g, "Separator", "."); + Accept = GetBoolCatInfo("Accept", false); if (Uri = GetStringCatInfo(g, "Connect", NULL)) { #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) @@ -1471,6 +1518,9 @@ void JSONCOL::ReadColumn(PGLOBAL g) if (!Tjp->SameRow || Xnod >= Tjp->SameRow) Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0)); + if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept) + throw("Null expandable JSON value"); + // Set null when applicable if (!Nullable) Value->SetNull(false); @@ -1546,11 +1596,16 @@ PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i) /***********************************************************************/ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n) { - int ars; + int ars = MY_MIN(Tjp->Limit, arp->size()); PJVAL jvp; JVALUE jval; - ars = MY_MIN(Tjp->Limit, arp->size()); + if (!ars) { + Value->Reset(); + Value->SetNull(true); + Tjp->NextSame = 0; + return Value; + } // endif ars if (!(jvp = arp->GetValue((Nodes[n].Rx = Nodes[n].Nx)))) { strcpy(g->Message, "Logical error expanding array"); @@ -1591,14 +1646,14 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) vp->Reset(); ars = MY_MIN(Tjp->Limit, arp->size()); - if (trace) + if (trace(1)) htrc("CalculateArray: size=%d op=%d nextsame=%d\n", ars, op, nextsame); for (i = 0; i < ars; i++) { jvrp = arp->GetValue(i); - if (trace) + if (trace(1)) htrc("i=%d nv=%d\n", i, nv); if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do { @@ -1612,7 +1667,7 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) } else jvp = jvrp; - if (trace) + if (trace(1)) htrc("jvp=%s null=%d\n", jvp->GetString(g), jvp->IsNull() ? 1 : 0); @@ -1648,7 +1703,7 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) if (err) vp->Reset(); - if (trace) { + if (trace(1)) { char buf(32); htrc("vp='%s' err=%d\n", diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index 17583cba333..0341c0f8aa0 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -15,6 +15,7 @@ enum JMODE {MODE_OBJECT, MODE_ARRAY, MODE_VALUE}; typedef class JSONDEF *PJDEF; typedef class TDBJSON *PJTDB; typedef class JSONCOL *PJCOL; +class TDBJSN; /***********************************************************************/ /* The JSON tree node. Can be an Object or an Array. */ @@ -29,6 +30,47 @@ typedef struct _jnode { int Nx; // Next to read row number } JNODE, *PJNODE; +typedef struct _jncol { + struct _jncol *Next; + char *Name; + char *Fmt; + int Type; + int Len; + int Scale; + bool Cbn; + bool Found; +} JCOL, *PJCL; + +/***********************************************************************/ +/* Class used to get the columns of a mongo collection. */ +/***********************************************************************/ +class JSONDISC : public BLOCK { +public: + // Constructor + JSONDISC(PGLOBAL g, uint *lg); + + // Functions + int GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt); + bool Find(PGLOBAL g, PJVAL jvp, int j); + void AddColumn(PGLOBAL g); + + // Members + JCOL jcol; + PJCL jcp, fjcp, pjcp; + PVAL valp; + PJDEF tdp; + TDBJSN *tjnp; + PJTDB tjsp; + PJPR jpp; + PJSON jsp; + PJOB row; + PCSZ sep; + char colname[65], fmt[129], buf[16]; + uint *length; + int i, n, bf, ncol, lvl; + bool all; +}; // end of JSONDISC + /***********************************************************************/ /* JSON table. */ /***********************************************************************/ @@ -36,13 +78,13 @@ class DllExport JSONDEF : public DOSDEF { /* Table description */ friend class TDBJSON; friend class TDBJSN; friend class TDBJCL; + friend class JSONDISC; #if defined(CMGO_SUPPORT) friend class CMGFAM; #endif // CMGO_SUPPORT #if defined(JAVA_SUPPORT) friend class JMGFAM; #endif // JAVA_SUPPORT - friend PQRYRES JSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool); public: // Constructor JSONDEF(void); diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp index 61aefc93082..d4d3a34d67e 100644 --- a/storage/connect/table.cpp +++ b/storage/connect/table.cpp @@ -128,7 +128,7 @@ PCOL TDB::ColDB(PGLOBAL g, PSZ name, int num) PCOLDEF cdp; PCOL cp, colp = NULL, cprec = NULL; - if (trace) + if (trace(1)) htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n", GetAmType(), SVP(name), Name, num); @@ -146,7 +146,7 @@ PCOL TDB::ColDB(PGLOBAL g, PSZ name, int num) else if (cp->GetIndex() < i) cprec = cp; - if (trace) + if (trace(1)) htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp); /*****************************************************************/ @@ -159,7 +159,7 @@ PCOL TDB::ColDB(PGLOBAL g, PSZ name, int num) else if (Mode != MODE_INSERT) colp = InsertSpcBlk(g, cdp); - if (trace) + if (trace(1)) htrc("colp=%p\n", colp); if (name || num) @@ -256,7 +256,7 @@ PCOL TDB::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp) /***********************************************************************/ void TDB::MarkDB(PGLOBAL, PTDB tdb2) { - if (trace) + if (trace(1)) htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2); } // end of MarkDB @@ -416,7 +416,7 @@ PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) PCOLDEF cdp; PCOL cp, colp = NULL, cprec = NULL; - if (trace) + if (trace(1)) htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n", GetAmType(), SVP(name), Name, num); @@ -434,7 +434,7 @@ PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) else if (cp->GetIndex() < i) cprec = cp; - if (trace) + if (trace(1)) htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp); /*****************************************************************/ @@ -447,7 +447,7 @@ PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) else if (Mode != MODE_INSERT) colp = InsertSpcBlk(g, cdp); - if (trace) + if (trace(1)) htrc("colp=%p\n", colp); if (name || num) @@ -592,7 +592,7 @@ void TDBASE::PrintAM(FILE *f, char *m) /***********************************************************************/ void TDBASE::MarkDB(PGLOBAL, PTDB tdb2) { - if (trace) + if (trace(1)) htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2); } // end of MarkDB diff --git a/storage/connect/tabmul.cpp b/storage/connect/tabmul.cpp index 0967afca6cd..649fc6706c6 100644 --- a/storage/connect/tabmul.cpp +++ b/storage/connect/tabmul.cpp @@ -134,7 +134,7 @@ bool TDBMUL::InitFileNames(PGLOBAL g) PSZ filename; int rc, n = 0; - if (trace) + if (trace(1)) htrc("in InitFileName: fn[]=%d\n", FNSZ); filename = (char*)PlugSubAlloc(g, NULL, FNSZ); @@ -144,7 +144,7 @@ bool TDBMUL::InitFileNames(PGLOBAL g) PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("InitFileName: fn='%s'\n", filename); if (Mul != 2) { @@ -159,7 +159,7 @@ bool TDBMUL::InitFileNames(PGLOBAL g) if (dirp->OpenDB(g)) return true; - if (trace && Mul == 3) { + if (trace(1) && Mul == 3) { int nf = ((PTDBSDR)dirp)->FindInDir(g); htrc("Number of files = %d\n", nf); } // endif trace @@ -319,7 +319,7 @@ int TDBMUL::GetMaxSize(PGLOBAL g) int i; int mxsz; - if (trace) + if (trace(1)) htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames); if (!Filenames && InitFileNames(g)) @@ -375,7 +375,7 @@ int TDBMUL::RowNumber(PGLOBAL g, bool b) /***********************************************************************/ bool TDBMUL::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", this, Tdb_No, Use, To_Key_Col, Mode); @@ -546,7 +546,7 @@ bool TDBMSD::InitFileNames(PGLOBAL g) PSZ filename; int rc, n = 0; - if (trace) + if (trace(1)) htrc("in InitFileName: fn[]=%d\n", FNSZ); filename = (char*)PlugSubAlloc(g, NULL, FNSZ); @@ -556,7 +556,7 @@ bool TDBMSD::InitFileNames(PGLOBAL g) PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("InitFileName: fn='%s'\n", filename); dirp = new(g) TDBSDR(filename); @@ -787,7 +787,7 @@ int TDBDIR::GetMaxSize(PGLOBAL g) /***********************************************************************/ bool TDBDIR::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode); @@ -985,7 +985,7 @@ void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime) /***********************************************************************/ void DIRCOL::ReadColumn(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n", Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N); @@ -1452,7 +1452,7 @@ int TDBDHR::GetMaxSize(PGLOBAL g) /***********************************************************************/ bool TDBDHR::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n", this, Tdb_No, Use, Mode); @@ -1589,7 +1589,7 @@ void DHRCOL::ReadColumn(PGLOBAL g) int rc; PTDBDHR tdbp = (PTDBDHR)To_Tdb; - if (trace) + if (trace(1)) htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n", Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N); diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index b9c97bd2f40..605b3822430 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -203,7 +203,7 @@ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b) // Otherwise, straight server name, Tabname = (b) ? GetStringCatInfo(g, "Tabname", Name) : NULL; - if (trace) + if (trace(1)) htrc("server: %s TableName: %s", url, Tabname); Server = url; @@ -567,7 +567,7 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx) return true; } // endif Query - if (trace) + if (trace(33)) htrc("Query=%s\n", Query->GetStr()); return false; @@ -1042,7 +1042,7 @@ int TDBMYSQL::SendCommand(PGLOBAL g) sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); PushWarning(g, this, 0); // 0 means a Note - if (trace) + if (trace(1)) htrc("%s\n", g->Message); if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) { @@ -1109,7 +1109,7 @@ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) Mode = MODE_READ; } // endif's op - if (trace) + if (trace(33)) htrc("MYSQL ReadKey: Query=%s\n", Query->GetStr()); m_Rc = Myc.ExecSQL(g, Query->GetStr()); @@ -1124,7 +1124,7 @@ int TDBMYSQL::ReadDB(PGLOBAL g) { int rc; - if (trace > 1) + if (trace(2)) htrc("MySQL ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode); if (Mode == MODE_UPDATE || Mode == MODE_DELETE) @@ -1137,7 +1137,7 @@ int TDBMYSQL::ReadDB(PGLOBAL g) N++; Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK); - if (trace > 1) + if (trace(2)) htrc(" Read: rc=%d\n", rc); return rc; @@ -1220,7 +1220,7 @@ void TDBMYSQL::CloseDB(PGLOBAL g) Myc.Close(); } // endif Myc - if (trace) + if (trace(1)) htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc); } // end of CloseDB @@ -1248,7 +1248,7 @@ MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) Slen = 0; Rank = -1; // Not known yet - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); } // end of MYSQLCOL constructor @@ -1279,7 +1279,7 @@ MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am) Slen = 0; Rank = i; - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); } // end of MYSQLCOL constructor @@ -1409,7 +1409,7 @@ void MYSQLCOL::ReadColumn(PGLOBAL g) tdbp->Fetched = true; if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) { - if (trace > 1) + if (trace(2)) htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf); // TODO: have a true way to differenciate temporal values @@ -1679,7 +1679,7 @@ MYXCOL::MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) MYXCOL::MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am) : MYSQLCOL(fld, tdbp, i, am) { - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); } // end of MYSQLCOL constructor diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 8ffa234ba5c..f7bc3934fbd 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -538,7 +538,7 @@ bool TDBODBC::OpenDB(PGLOBAL g) { bool rc = true; - if (trace) + if (trace(1)) htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", this, Tdb_No, Use, Mode); @@ -750,7 +750,7 @@ bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) Mode = MODE_READ; } // endif's op - if (trace) + if (trace(33)) htrc("ODBC ReadKey: Query=%s\n", Query->GetStr()); Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns); @@ -765,7 +765,7 @@ int TDBODBC::ReadDB(PGLOBAL g) { int rc; - if (trace > 1) + if (trace(2)) htrc("ODBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode); if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { @@ -776,7 +776,7 @@ int TDBODBC::ReadDB(PGLOBAL g) if (!Ocp->ExecSQLcommand(Query->GetStr())) { sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); PushWarning(g, this, 0); // 0 means a Note @@ -817,7 +817,7 @@ int TDBODBC::ReadDB(PGLOBAL g) } // endif Placed - if (trace > 1) + if (trace(2)) htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc); return rc; @@ -852,7 +852,7 @@ int TDBODBC::DeleteDB(PGLOBAL g, int irc) if (!Ocp->ExecSQLcommand(Query->GetStr())) { sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); - if (trace) + if (trace(1)) htrc("%s\n", g->Message); PushWarning(g, this, 0); // 0 means a Note @@ -874,7 +874,7 @@ void TDBODBC::CloseDB(PGLOBAL g) Ocp->Close(); - if (trace) + if (trace(1)) htrc("ODBC CloseDB: closing %s\n", Name); } // end of CloseDB @@ -975,7 +975,7 @@ void ODBCCOL::ReadColumn(PGLOBAL g) } // endif Buf_Type - if (trace > 1) { + if (trace(2)) { char buf[64]; htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n", @@ -1214,7 +1214,7 @@ bool TDBXDBC::OpenDB(PGLOBAL g) { bool rc = false; - if (trace) + if (trace(1)) htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", this, Tdb_No, Use, Mode); diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp index 76a46e6899b..da5d134f347 100644 --- a/storage/connect/tabpivot.cpp +++ b/storage/connect/tabpivot.cpp @@ -299,7 +299,7 @@ PQRYRES PIVAID::MakePivotColumns(PGLOBAL g) Qryp->Nbcol += (ndif - 2); return Qryp; } catch (int n) { - if (trace) + if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); } catch (const char *msg) { strcpy(g->Message, msg); diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp index 7f0d9881298..f73a2b6578d 100644 --- a/storage/connect/tabsys.cpp +++ b/storage/connect/tabsys.cpp @@ -180,7 +180,7 @@ PTDB TDBINI::Clone(PTABS t) /***********************************************************************/ char *TDBINI::GetSeclist(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("GetSeclist: Seclist=%p\n", Seclist); if (!Seclist) { @@ -267,7 +267,7 @@ bool TDBINI::OpenDB(PGLOBAL g) if (!colp->IsSpecial()) // Not a pseudo column colp->AllocBuf(g); - if (trace) + if (trace(1)) htrc("INI OpenDB: seclist=%s seclen=%d ifile=%s\n", Seclist, Seclen, Ifile); @@ -287,7 +287,7 @@ int TDBINI::ReadDB(PGLOBAL) else Section += (strlen(Section) + 1); - if (trace > 1) + if (trace(2)) htrc("INI ReadDB: section=%s N=%d\n", Section, N); N++; @@ -453,7 +453,7 @@ void INICOL::ReadColumn(PGLOBAL) { PTDBINI tdbp = (PTDBINI)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("INI ReadColumn: col %s R%d flag=%d\n", Name, tdbp->GetTdb_No(), Flag); @@ -493,7 +493,7 @@ void INICOL::WriteColumn(PGLOBAL g) bool rc; PTDBINI tdbp = (PTDBINI)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("INI WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, tdbp->GetTdb_No(), ColUse, Status); @@ -823,7 +823,7 @@ void XINCOL::WriteColumn(PGLOBAL g) bool rc; PTDBXIN tdbp = (PTDBXIN)To_Tdb; - if (trace > 1) + if (trace(2)) htrc("XIN WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, tdbp->GetTdb_No(), ColUse, Status); diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index aa7cf4e41b4..b2dbdd70e06 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -132,7 +132,7 @@ bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR, int) tbl = new(g) XTAB(pn, def); tbl->SetSchema(pdb); - if (trace) + if (trace(1)) htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetSchema()); // Link the blocks @@ -436,7 +436,7 @@ int TDBTBL::RowNumber(PGLOBAL g, bool b) /***********************************************************************/ bool TDBTBL::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", this, Tdb_No, Use, To_Key_Col, Mode); @@ -475,7 +475,7 @@ bool TDBTBL::OpenDB(PGLOBAL g) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept) return TRUE; - if (trace) + if (trace(1)) htrc("Opening subtable %s\n", Tdbp->GetName()); // Now we can safely open the table @@ -530,7 +530,7 @@ int TDBTBL::ReadDB(PGLOBAL g) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept) return RC_FX; - if (trace) + if (trace(1)) htrc("Opening subtable %s\n", Tdbp->GetName()); // Now we can safely open the table @@ -555,7 +555,7 @@ int TDBTBL::ReadDB(PGLOBAL g) /***********************************************************************/ void TBTBLK::ReadColumn(PGLOBAL) { - if (trace) + if (trace(1)) htrc("TBT ReadColumn: name=%s\n", Name); Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName()); @@ -575,27 +575,30 @@ pthread_handler_t ThreadOpen(void *p) if (!my_thread_init()) { set_current_thd(cmp->Thd); - if (trace) + if (trace(1)) htrc("ThreadOpen: Thd=%d\n", cmp->Thd); // Try to open the connection - if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) { - pthread_mutex_lock(&tblmut); - if (trace) + pthread_mutex_lock(&tblmut); + + if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) { +// pthread_mutex_lock(&tblmut); + if (trace(1)) htrc("Table %s ready\n", cmp->Tap->GetName()); cmp->Ready = true; - pthread_mutex_unlock(&tblmut); +// pthread_mutex_unlock(&tblmut); } else { - pthread_mutex_lock(&tblmut); - if (trace) +// pthread_mutex_lock(&tblmut); + if (trace(1)) htrc("Opening %s failed\n", cmp->Tap->GetName()); cmp->Rc = RC_FX; - pthread_mutex_unlock(&tblmut); +// pthread_mutex_unlock(&tblmut); } // endif OpenDB - my_thread_end(); + pthread_mutex_unlock(&tblmut); + my_thread_end(); } else cmp->Rc = RC_FX; @@ -672,7 +675,7 @@ bool TDBTBM::OpenTables(PGLOBAL g) // Remove remote table from the local list *ptabp = tabp->Next; - if (trace) + if (trace(1)) htrc("=====> New remote table %s\n", tabp->GetName()); // Make the remote table block @@ -698,7 +701,7 @@ bool TDBTBM::OpenTables(PGLOBAL g) ptp = &tp->Next; Nrc++; // Number of remote connections } else { - if (trace) + if (trace(1)) htrc("=====> Local table %s\n", tabp->GetName()); ptabp = &tabp->Next; @@ -714,7 +717,7 @@ bool TDBTBM::OpenTables(PGLOBAL g) /***********************************************************************/ bool TDBTBM::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("TBM OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", this, Tdb_No, Use, To_Key_Col, Mode); @@ -762,7 +765,7 @@ bool TDBTBM::OpenDB(PGLOBAL g) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept) return TRUE; - if (trace) + if (trace(1)) htrc("Opening subtable %s\n", Tdbp->GetName()); // Now we can safely open the table @@ -863,7 +866,7 @@ int TDBTBM::ReadNextRemote(PGLOBAL g) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept) return RC_FX; - if (trace) + if (trace(1)) htrc("Reading subtable %s\n", Tdbp->GetName()); return RC_OK; diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index 948ea24aa6b..59666d4e127 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -457,7 +457,7 @@ PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) hc->get_table()->s->option_struct->srcdef = sp; } // endif s - if (trace && tdbp) + if (trace(1) && tdbp) htrc("Subtable %s in %s\n", name, SVP(tdbp->GetDef()->GetDB())); @@ -647,7 +647,7 @@ PRXCOL::PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) Pseudo = false; Colnum = cdp->GetOffset(); // If columns are retrieved by number - if (trace) + if (trace(1)) htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); } // end of PRXCOL constructor @@ -732,7 +732,7 @@ void PRXCOL::Reset(void) /***********************************************************************/ void PRXCOL::ReadColumn(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("PRX ReadColumn: name=%s\n", Name); if (Colp) { @@ -759,7 +759,7 @@ void PRXCOL::ReadColumn(PGLOBAL g) /***********************************************************************/ void PRXCOL::WriteColumn(PGLOBAL g) { - if (trace > 1) + if (trace(2)) htrc("PRX WriteColumn: name=%s\n", Name); if (Colp) { diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp index 533986e44da..11b344ef652 100644 --- a/storage/connect/tabvct.cpp +++ b/storage/connect/tabvct.cpp @@ -304,7 +304,7 @@ bool TDBVCT::IsUsingTemp(PGLOBAL) /***********************************************************************/ bool TDBVCT::OpenDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("VCT OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", this, Tdb_No, Use, To_Key_Col, Mode); @@ -364,7 +364,7 @@ bool TDBVCT::OpenDB(PGLOBAL g) /***********************************************************************/ int TDBVCT::ReadDB(PGLOBAL g) { - if (trace) + if (trace(1)) htrc("VCT ReadDB: R%d Mode=%d CurBlk=%d CurNum=%d key=%p link=%p Kindex=%p\n", GetTdb_No(), Mode, Txfp->CurBlk, Txfp->CurNum, To_Key_Col, To_Link, To_Kindex); @@ -546,7 +546,7 @@ void VCTCOL::ReadColumn(PGLOBAL g) assert (!To_Kcol); #endif - if (trace > 1) + if (trace(2)) htrc("VCT ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n", Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type); @@ -574,7 +574,7 @@ void VCTCOL::WriteColumn(PGLOBAL) { PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;; - if (trace > 1) + if (trace(2)) htrc("VCT WriteColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n", Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type); diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp index 335ffce5d7f..8a8e1bcbcb6 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -34,7 +34,7 @@ PWMIUT InitWMI(PGLOBAL g, PCSZ nsp, PCSZ classname) HRESULT res; PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL)); - if (trace) + if (trace(1)) htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp)); /*********************************************************************/ @@ -103,7 +103,7 @@ PWMIUT InitWMI(PGLOBAL g, PCSZ nsp, PCSZ classname) loc->Release(); - if (trace) + if (trace(1)) htrc("Successfully connected to namespace.\n"); /*********************************************************************/ diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index c09386451ff..c96e0844497 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -153,7 +153,7 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; } // endif fn - if (trace) + if (trace(1)) htrc("File %s lvl=%d\n", topt->filename, lvl); tdp = new(g) XMLDEF; @@ -362,7 +362,7 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) txmp->CloseDB(g); skipit: - if (trace) + if (trace(1)) htrc("XMLColumns: n=%d len=%d\n", n, length[0]); /*********************************************************************/ @@ -686,7 +686,7 @@ PTDB TDBXML::Clone(PTABS t) /***********************************************************************/ PCOL TDBXML::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { - if (trace) + if (trace(1)) htrc("TDBXML: MakeCol %s n=%d\n", (cdp) ? cdp->GetName() : "<null>", n); return new(g) XMLCOL(cdp, this, cprec, n); @@ -720,7 +720,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) if (Docp) return rc; // Already done - if (trace) + if (trace(1)) htrc("TDBXML: loading %s\n", filename); /*********************************************************************/ @@ -753,7 +753,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) return RC_FX; } // endif init - if (trace) + if (trace(1)) htrc("TDBXML: parsing %s rc=%d\n", filename, rc); // Parse the XML file @@ -1182,7 +1182,7 @@ int TDBXML::ReadDB(PGLOBAL g) } // endswitch recpos } else { - if (trace) + if (trace(1)) htrc("TDBXML ReadDB: Irow=%d Nrow=%d\n", Irow, Nrow); // This is to force the table to be expanded when constructing @@ -1209,7 +1209,7 @@ int TDBXML::ReadDB(PGLOBAL g) } // endif To_Kindex if (!same) { - if (trace > 1) + if (trace(2)) htrc("TDBXML ReadDB: Irow=%d RowNode=%p\n", Irow, RowNode); // Get the new row node @@ -1472,7 +1472,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) } else strcat(pbuf, Xname); - if (trace) + if (trace(1)) htrc("XMLCOL: pbuf=%s\n", pbuf); // For Update or Insert the Xpath must be analyzed @@ -1555,7 +1555,7 @@ bool XMLCOL::ParseXpath(PGLOBAL g, bool mode) if (Type || Nod) Tdbp->Hasnod = true; - if (trace) + if (trace(1)) htrc("XMLCOL: Xname=%s\n", pbuf); // Save the calculated Xpath @@ -1679,7 +1679,7 @@ void XMLCOL::WriteColumn(PGLOBAL g) int i, n, k = 0; PXNODE TopNode = NULL; - if (trace > 1) + if (trace(2)) htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, Tdbp->GetTdb_No(), ColUse, Status); @@ -1913,7 +1913,7 @@ void XMULCOL::WriteColumn(PGLOBAL g) int i, n, len, k = 0; PXNODE TopNode = NULL; - if (trace) + if (trace(1)) htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, Tdbp->GetTdb_No(), ColUse, Status); @@ -2129,7 +2129,7 @@ void XPOSCOL::WriteColumn(PGLOBAL g) char *p, buf[16]; int i, k, n; - if (trace) + if (trace(1)) htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n", Name, Tdbp->GetTdb_No(), ColUse, Status); diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index ad7c21a6b40..e2d3b664aeb 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -179,7 +179,7 @@ bool user_connect::CheckCleanup(bool force) g->Mrr = 0; last_query_id= thdp->query_id; - if (trace && !force) + if (trace(65) && !force) printf("=====> Begin new query %llu\n", last_query_id); return true; diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index 018c7ee3fe1..73ca135691c 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -53,7 +53,7 @@ PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len, { PVBLK blkp; - if (trace) + if (trace(1)) htrc("AVB: mp=%p type=%d nval=%d len=%d check=%u blank=%u\n", mp, type, nval, len, check, blank); diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index bf56197ac56..e159efaa989 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -337,7 +337,7 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type, short prec) { PVAL valp; - if (trace) + if (trace(1)) htrc("AllocateConstant: value=%p type=%hd\n", value, type); switch (type) { @@ -727,7 +727,7 @@ bool TYPVAL<TYPE>::SetValue_char(const char *p, int n) else Tval = (TYPE)val; - if (trace > 1) { + if (trace(2)) { char buf[64]; htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), GetTypeName(Type), Tval); @@ -750,7 +750,7 @@ bool TYPVAL<double>::SetValue_char(const char *p, int n) buf[n] = '\0'; Tval = atof(buf); - if (trace > 1) + if (trace(2)) htrc(" setting double: '%s' -> %lf\n", buf, Tval); Null = false; @@ -996,7 +996,7 @@ int TYPVAL<TYPE>::CompareValue(PVAL vp) // Process filtering on numeric values. TYPE n = GetTypedValue(vp); -//if (trace) +//if (trace(1)) // htrc(" Comparing: val=%d,%d\n", Tval, n); return (Tval > n) ? 1 : (Tval < n) ? (-1) : 0; @@ -1384,7 +1384,7 @@ bool TYPVAL<PSZ>::SetValue_char(const char *cp, int n) strncpy(Strp, cp, n); Strp[n] = '\0'; - if (trace > 1) + if (trace(2)) htrc(" Setting string to: '%s'\n", Strp); } else @@ -1631,7 +1631,7 @@ int TYPVAL<PSZ>::CompareValue(PVAL vp) int n; //assert(vp->GetType() == Type); - if (trace) + if (trace(1)) htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue()); // Process filtering on character strings. @@ -1656,14 +1656,14 @@ bool TYPVAL<PSZ>::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) char *p[2], val[2][32]; int i; - if (trace) + if (trace(1)) htrc("Compute: np=%d op=%d\n", np, op); for (i = 0; i < np; i++) if (!vp[i]->IsNull()) { p[i] = vp[i]->GetCharString(val[i]); - if (trace) + if (trace(1)) htrc("p[%d]=%s\n", i, p[i]); } else @@ -1679,7 +1679,7 @@ bool TYPVAL<PSZ>::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) if ((i = Len - (signed)strlen(Strp)) > 0) strncat(Strp, p[np - 1], i); - if (trace) + if (trace(1)) htrc("Strp=%s\n", Strp); break; @@ -1854,7 +1854,7 @@ int DECVAL::CompareValue(PVAL vp) // Process filtering on numeric values. double f = atof(Strp), n = vp->GetFloatValue(); -//if (trace) +//if (trace(1)) // htrc(" Comparing: val=%d,%d\n", f, n); return (f > n) ? 1 : (f < n) ? (-1) : 0; @@ -2410,7 +2410,7 @@ void DTVAL::SetTimeShift(void) Shift = (int)mktime(&dtm) - 86400; - if (trace) + if (trace(1)) htrc("DTVAL Shift=%d\n", Shift); } // end of SetTimeShift @@ -2485,7 +2485,7 @@ bool DTVAL::MakeTime(struct tm *ptm) int n, y = ptm->tm_year; time_t t = mktime_mysql(ptm); - if (trace > 1) + if (trace(2)) htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n", ptm->tm_year, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); @@ -2508,7 +2508,7 @@ bool DTVAL::MakeTime(struct tm *ptm) } Tval= (int) t; - if (trace > 1) + if (trace(2)) htrc("MakeTime Ival=%d\n", Tval); return false; @@ -2528,14 +2528,14 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) datm.tm_mon=0; datm.tm_year=70; - if (trace > 1) + if (trace(2)) htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n", val[0], val[1], val[2], val[3], val[4], val[5], nval); for (i = 0; i < nval; i++) { n = val[i]; -// if (trace > 1) +// if (trace(2)) // htrc("i=%d n=%d\n", i, n); switch (i) { @@ -2545,7 +2545,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) datm.tm_year = n; -// if (trace > 1) +// if (trace(2)) // htrc("n=%d tm_year=%d\n", n, datm.tm_year); break; @@ -2564,7 +2564,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) datm.tm_mon = m; datm.tm_year += n; -// if (trace > 1) +// if (trace(2)) // htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); break; @@ -2581,7 +2581,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) datm.tm_mday = m; datm.tm_year += n; -// if (trace > 1) +// if (trace(2)) // htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon); break; @@ -2592,7 +2592,7 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) } // endfor i - if (trace > 1) + if (trace(2)) htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n", datm.tm_year, datm.tm_mon, datm.tm_mday, datm.tm_hour, datm.tm_min, datm.tm_sec); @@ -2667,7 +2667,7 @@ bool DTVAL::SetValue_char(const char *p, int n) ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); MakeDate(NULL, dval, ndv); - if (trace > 1) + if (trace(2)) htrc(" setting date: '%s' -> %d\n", Sdate, Tval); Null = (Nullable && ndv == 0); @@ -2694,7 +2694,7 @@ void DTVAL::SetValue_psz(PCSZ p) ndv = ExtractDate(Sdate, Pdtp, DefYear, dval); MakeDate(NULL, dval, ndv); - if (trace > 1) + if (trace(2)) htrc(" setting date: '%s' -> %d\n", Sdate, Tval); Null = (Nullable && ndv == 0); @@ -2849,13 +2849,13 @@ bool DTVAL::FormatValue(PVAL vp, PCSZ fmt) char *buf = (char*)vp->GetTo_Val(); // Should be big enough struct tm tm, *ptm = GetGmTime(&tm); - if (trace > 1) + if (trace(2)) htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen()); if (ptm) { size_t n = strftime(buf, vp->GetValLen(), fmt, ptm); - if (trace > 1) + if (trace(2)) htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???"); return (n == 0); diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index 30dce3b7fef..efefc17b5f5 100644 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -344,7 +344,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) } // endif n - if (trace) + if (trace(1)) htrc("XINDEX Make: n=%d\n", n); // File position must be stored @@ -417,7 +417,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) if (kcp->Init(g, colp, n, true, 0)) return true; - if (trace) + if (trace(1)) htrc("Adding colp=%p Buf_Type=%d size=%d\n", colp, colp->GetResultType(), n); @@ -484,7 +484,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) } else To_Rec[nkey] = Tdbp->GetRecpos(); - if (trace > 1) + if (trace(2)) htrc("Make: To_Rec[%d]=%d\n", nkey, To_Rec[nkey]); /*******************************************************************/ @@ -553,7 +553,7 @@ bool XINDEX::Make(PGLOBAL g, PIXDEF sxp) if ((Ndif = Qsort(g, Num_K)) < 0) goto err; // Error during sort - if (trace) + if (trace(1)) htrc("Make: Nk=%d n=%d Num_K=%d Ndif=%d addcolp=%p BlkFil=%p X=%p\n", Nk, n, Num_K, Ndif, addcolp, Tdbp->To_BlkFil, X); @@ -883,7 +883,7 @@ bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp) n[5] = Nblk; n[6] = Sblk; n[7] = Srtd ? 1 : 0; // Values are sorted in the file - if (trace) { + if (trace(1)) { htrc("Saving index %s\n", Xdp->GetName()); htrc("ID=%d Nk=%d nof=%d Num_K=%d Incr=%d Nblk=%d Sblk=%d Srtd=%d\n", ID, Nk, nof, Num_K, Incr, Nblk, Sblk, Srtd); @@ -926,7 +926,7 @@ bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp) // dup->ProgCur += 5; } // endfor kcp - if (trace) + if (trace(1)) htrc("Index %s saved, Size=%d\n", Xdp->GetName(), size); end: @@ -1016,7 +1016,7 @@ bool XINDEX::Init(PGLOBAL g) PlugSetPath(fn, fn, Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("Index %s file: %s\n", Xdp->GetName(), fn); /*********************************************************************/ @@ -1039,7 +1039,7 @@ bool XINDEX::Init(PGLOBAL g) } else Srtd = false; - if (trace) + if (trace(1)) htrc("nv=%d %d %d %d %d %d %d (%d)\n", nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6], Srtd); @@ -1048,7 +1048,7 @@ bool XINDEX::Init(PGLOBAL g) if (/*nv[0] != ID ||*/ nv[1] != Nk) { sprintf(g->Message, MSG(BAD_INDEX_FILE), fn); - if (trace) + if (trace(1)) htrc("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk); goto err; @@ -1269,7 +1269,7 @@ bool XINDEX::MapInit(PGLOBAL g) PlugSetPath(fn, fn, Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("Index %s file: %s\n", Xdp->GetName(), fn); /*********************************************************************/ @@ -1300,7 +1300,7 @@ bool XINDEX::MapInit(PGLOBAL g) nv0 = nv[0]; } // endif nv - if (trace) + if (trace(1)) htrc("nv=%d %d %d %d %d %d %d %d\n", nv0, nv[1], nv[2], nv[3], nv[4], nv[5], nv[6], Srtd); @@ -1310,7 +1310,7 @@ bool XINDEX::MapInit(PGLOBAL g) // Not this index sprintf(g->Message, MSG(BAD_INDEX_FILE), fn); - if (trace) + if (trace(1)) htrc("nv0=%d ID=%d nv[1]=%d Nk=%d\n", nv0, ID, nv[1], Nk); goto err; @@ -1483,7 +1483,7 @@ bool XINDEX::GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk) PlugSetPath(fn, fn, Tdbp->GetPath()); - if (trace) + if (trace(1)) htrc("Index %s file: %s\n", Xdp->GetName(), fn); /*********************************************************************/ @@ -1500,7 +1500,7 @@ bool XINDEX::GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk) if (X->Read(g, nv, NZ, sizeof(int))) goto err; - if (trace) + if (trace(1)) htrc("nv=%d %d %d %d\n", nv[0], nv[1], nv[2], nv[3]); // The test on ID was suppressed because MariaDB can change an index ID @@ -1508,7 +1508,7 @@ bool XINDEX::GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk) if (/*nv[0] != ID ||*/ nv[1] != Nk) { sprintf(g->Message, MSG(BAD_INDEX_FILE), fn); - if (trace) + if (trace(1)) htrc("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk); goto err; @@ -1770,7 +1770,7 @@ int XINDEX::Fetch(PGLOBAL g) if (Num_K == 0) return -1; // means end of file - if (trace > 1) + if (trace(2)) htrc("XINDEX Fetch: Op=%d\n", Op); /*********************************************************************/ @@ -1834,7 +1834,7 @@ int XINDEX::Fetch(PGLOBAL g) Nth++; - if (trace > 1) + if (trace(2)) htrc("Fetch: Looking for new value Nth=%d\n", Nth); Cur_K = FastFind(); @@ -1907,7 +1907,7 @@ int XINDEX::FastFind(void) sup = To_KeyCol->Ndf; } // endif Nblk - if (trace > 2) + if (trace(4)) htrc("XINDEX FastFind: Nblk=%d Op=%d inf=%d sup=%d\n", Nblk, Op, inf, sup); @@ -1985,7 +1985,7 @@ int XINDEX::FastFind(void) curk = (kcp->Kof) ? kcp->Kof[kcp->Val_K] : kcp->Val_K; } // endfor kcp - if (trace > 2) + if (trace(4)) htrc("XINDEX FastFind: curk=%d\n", curk); return curk; @@ -2123,7 +2123,7 @@ int XINDXS::Fetch(PGLOBAL g) if (Num_K == 0) return -1; // means end of file - if (trace > 1) + if (trace(2)) htrc("XINDXS Fetch: Op=%d\n", Op); /*********************************************************************/ @@ -2176,7 +2176,7 @@ int XINDXS::Fetch(PGLOBAL g) else Nth++; - if (trace > 1) + if (trace(2)) htrc("Fetch: Looking for new value Nth=%d\n", Nth); Cur_K = FastFind(); @@ -2243,7 +2243,7 @@ int XINDXS::FastFind(void) sup = Ndif; } // endif Nblk - if (trace > 2) + if (trace(4)) htrc("XINDXS FastFind: Nblk=%d Op=%d inf=%d sup=%d\n", Nblk, Op, inf, sup); @@ -2269,7 +2269,7 @@ int XINDXS::FastFind(void) n = 0; } // endif sup - if (trace > 2) + if (trace(4)) htrc("XINDXS FastFind: n=%d i=%d\n", n, i); // Loop on kcp because of dynamic indexing @@ -2337,7 +2337,7 @@ bool XFILE::Open(PGLOBAL g, char *filename, int id, MODE mode) } // endswitch mode if (!(Xfile= global_fopen(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, pmod))) { - if (trace) + if (trace(1)) htrc("Open: %s\n", g->Message); return true; @@ -2354,7 +2354,7 @@ bool XFILE::Open(PGLOBAL g, char *filename, int id, MODE mode) NewOff.v.Low = (int)ftell(Xfile); - if (trace) + if (trace(1)) htrc("XFILE Open: NewOff.v.Low=%d\n", NewOff.v.Low); } else if (mode == MODE_WRITE) { @@ -2365,7 +2365,7 @@ bool XFILE::Open(PGLOBAL g, char *filename, int id, MODE mode) fseek(Xfile, 0, SEEK_END); NewOff.v.Low = (int)ftell(Xfile); - if (trace) + if (trace(1)) htrc("XFILE Open: NewOff.v.Low=%d\n", NewOff.v.Low); } // endif id @@ -2377,7 +2377,7 @@ bool XFILE::Open(PGLOBAL g, char *filename, int id, MODE mode) return true; } // endif MAX_INDX - if (trace) + if (trace(1)) htrc("XFILE Open: noff[%d].v.Low=%d\n", id, noff[id].v.Low); // Position the cursor at the offset of this index @@ -2510,7 +2510,7 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) return true; } // endif - if (trace) + if (trace(1)) htrc(" Xopen: filename=%s id=%d mode=%d\n", filename, id, mode); #if defined(__WIN__) @@ -2554,7 +2554,7 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) return true; } // endif Hfile - if (trace) + if (trace(1)) htrc(" access=%p share=%p creation=%d handle=%p fn=%s\n", access, share, creation, Hfile, filename); @@ -2628,13 +2628,13 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) if (Hfile == INVALID_HANDLE_VALUE) { /*rc = errno;*/ - if (trace) + if (trace(1)) htrc("Open: %s\n", g->Message); return true; } // endif Hfile - if (trace) + if (trace(1)) htrc(" oflag=%p mode=%d handle=%d fn=%s\n", oflag, mode, Hfile, filename); @@ -2647,7 +2647,7 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) return true; } // endif - if (trace) + if (trace(1)) htrc("INSERT: NewOff=%lld\n", NewOff.Val); } else if (mode == MODE_WRITE) { @@ -2657,7 +2657,7 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) NewOff.v.Low = write(Hfile, &noff, sizeof(noff)); } // endif id - if (trace) + if (trace(1)) htrc("WRITE: NewOff=%lld\n", NewOff.Val); } else if (mode == MODE_READ && id >= 0) { @@ -2667,7 +2667,7 @@ bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode) return true; } // endif read - if (trace) + if (trace(1)) htrc("noff[%d]=%lld\n", id, noff[id].Val); // Position the cursor at the offset of this index @@ -2705,13 +2705,13 @@ bool XHUGE::Seek(PGLOBAL g, int low, int high, int origin) if (lseek64(Hfile, pos, origin) < 0) { sprintf(g->Message, MSG(ERROR_IN_LSK), errno); - if (trace) + if (trace(1)) htrc("lseek64 error %d\n", errno); return true; } // endif lseek64 - if (trace) + if (trace(1)) htrc("Seek: low=%d high=%d\n", low, high); #endif // UNIX @@ -2750,13 +2750,13 @@ bool XHUGE::Read(PGLOBAL g, void *buf, int n, int size) #else // UNIX ssize_t count = (ssize_t)(n * size); - if (trace) + if (trace(1)) htrc("Hfile=%d n=%d size=%d count=%d\n", Hfile, n, size, count); if (read(Hfile, buf, count) != count) { sprintf(g->Message, MSG(READ_ERROR), "Index file", strerror(errno)); - if (trace) + if (trace(1)) htrc("read error %d\n", errno); rc = true; @@ -2810,7 +2810,7 @@ int XHUGE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc) /***********************************************************************/ void XHUGE::Close(char *fn, int id) { - if (trace) + if (trace(1)) htrc("XHUGE::Close: fn=%s id=%d NewOff=%lld\n", fn, id, NewOff.Val); #if defined(__WIN__) @@ -3022,7 +3022,7 @@ bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln) Prefix = true; } // endif kln - if (trace) + if (trace(1)) htrc("KCOL(%p) Init: col=%s n=%d type=%d sm=%d\n", this, colp->GetName(), n, colp->GetResultType(), sm); @@ -3076,7 +3076,7 @@ BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m) Type = colp->GetResultType(); - if (trace) + if (trace(1)) htrc("MapInit(%p): colp=%p type=%d n=%d len=%d m=%p\n", this, colp, Type, n[0], len, m); @@ -3196,7 +3196,7 @@ bool KXYCOL::InitFind(PGLOBAL g, PXOB xp) Valp->SetValue_pval(xp->GetValue(), false); } // endif Type - if (trace > 1) { + if (trace(2)) { char buf[32]; htrc("KCOL InitFind: value=%s\n", Valp->GetCharString(buf)); @@ -3237,7 +3237,7 @@ int KXYCOL::Compare(int i1, int i2) // Do the actual comparison between values. register int k = Kblp->CompVal(i1, i2); - if (trace > 2) + if (trace(4)) htrc("Compare done result=%d\n", k); return (Asc) ? k : -k; @@ -3249,7 +3249,7 @@ int KXYCOL::Compare(int i1, int i2) int KXYCOL::CompVal(int i) { // Do the actual comparison between numerical values. - if (trace > 2) { + if (trace(4)) { register int k = (int)Kblp->CompVal(Valp, (int)i); htrc("Compare done result=%d\n", k); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index b2b13a9bab3..62a195e8b0f 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -7445,6 +7445,8 @@ buf_page_encrypt_before_write( bpage->real_size = out_len; + /* Workaround for MDEV-15527. */ + memset(tmp + out_len, 0 , srv_page_size - out_len); #ifdef UNIV_DEBUG fil_page_type_validate(tmp); #endif diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 490a66a1f2e..c23ffe306ae 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1633,8 +1633,6 @@ buf_flush_LRU_list_batch( { buf_page_t* bpage; ulint scanned = 0; - ulint evict_count = 0; - ulint count = 0; ulint free_len = UT_LIST_GET_LEN(buf_pool->free); ulint lru_len = UT_LIST_GET_LEN(buf_pool->LRU); ulint withdraw_depth = 0; @@ -1650,7 +1648,7 @@ buf_flush_LRU_list_batch( } for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); - bpage != NULL && count + evict_count < max + bpage != NULL && n->flushed + n->evicted < max && free_len < srv_LRU_scan_depth + withdraw_depth && lru_len > BUF_LRU_MIN_LEN; ++scanned, @@ -1668,7 +1666,7 @@ buf_flush_LRU_list_batch( clean and is not IO-fixed or buffer fixed. */ mutex_exit(block_mutex); if (buf_LRU_free_page(bpage, true)) { - ++evict_count; + ++n->evicted; } } else if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_LRU)) { /* Block is ready for flush. Dispatch an IO @@ -1676,7 +1674,7 @@ buf_flush_LRU_list_batch( free list in IO completion routine. */ mutex_exit(block_mutex); buf_flush_page_and_try_neighbors( - bpage, BUF_FLUSH_LRU, max, &count); + bpage, BUF_FLUSH_LRU, max, &n->flushed); } else { /* Can't evict or dispatch this block. Go to previous. */ @@ -1700,12 +1698,12 @@ buf_flush_LRU_list_batch( ut_ad(buf_pool_mutex_own(buf_pool)); - if (evict_count) { + if (n->evicted) { MONITOR_INC_VALUE_CUMULATIVE( MONITOR_LRU_BATCH_EVICT_TOTAL_PAGE, MONITOR_LRU_BATCH_EVICT_COUNT, MONITOR_LRU_BATCH_EVICT_PAGES, - evict_count); + n->evicted); } if (scanned) { @@ -2147,16 +2145,16 @@ buf_flush_lists( failure. */ success = false; - continue; } + + n_flushed += n.flushed; } if (n_flushed) { buf_flush_stats(n_flushed, 0); - } - - if (n_processed) { - *n_processed = n_flushed; + if (n_processed) { + *n_processed = n_flushed; + } } return(success); @@ -2701,26 +2699,6 @@ buf_flush_page_cleaner_init(void) } /** -Close page_cleaner. */ -static -void -buf_flush_page_cleaner_close(void) -{ - ut_ad(!page_cleaner.is_running); - - /* waiting for all worker threads exit */ - while (page_cleaner.n_workers) { - os_thread_sleep(10000); - } - - mutex_destroy(&page_cleaner.mutex); - - os_event_destroy(page_cleaner.is_finished); - os_event_destroy(page_cleaner.is_requested); - os_event_destroy(page_cleaner.is_started); -} - -/** Requests for all slots to flush all buffer pool instances. @param min_n wished minimum mumber of blocks flushed (it is not guaranteed that the actual number is that big) @@ -3421,9 +3399,18 @@ thread_exit: and no more access to page_cleaner structure by them. Wakes worker threads up just to make them exit. */ page_cleaner.is_running = false; - os_event_set(page_cleaner.is_requested); - buf_flush_page_cleaner_close(); + /* waiting for all worker threads exit */ + while (page_cleaner.n_workers) { + os_event_set(page_cleaner.is_requested); + os_thread_sleep(10000); + } + + mutex_destroy(&page_cleaner.mutex); + + os_event_destroy(page_cleaner.is_finished); + os_event_destroy(page_cleaner.is_requested); + os_event_destroy(page_cleaner.is_started); buf_page_cleaner_is_active = false; diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 2e175731d5f..d1b4eb7a3d4 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -37,6 +37,7 @@ Created 1/8/1996 Heikki Tuuri #include "ut0crc32.h" #include "lock0lock.h" #include "sync0sync.h" +#include "row0row.h" #include <iostream> #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index d965fb06a4c..fa82b4456fb 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -24,9 +24,7 @@ The tablespace memory cache Created 10/25/1995 Heikki Tuuri *******************************************************/ -#include "ha_prototypes.h" -#include "fil0pagecompress.h" -#include "fsp0pagecompress.h" +#include "fil0fil.h" #include "fil0crypt.h" #include "btr0btr.h" @@ -5655,485 +5653,6 @@ fil_close(void) } /********************************************************************//** -Initializes a buffer control block when the buf_pool is created. */ -static -void -fil_buf_block_init( -/*===============*/ - buf_block_t* block, /*!< in: pointer to control block */ - byte* frame) /*!< in: pointer to buffer frame */ -{ - UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE); - - block->frame = frame; - - block->page.io_fix = BUF_IO_NONE; - /* There are assertions that check for this. */ - block->page.buf_fix_count = 1; - block->page.state = BUF_BLOCK_READY_FOR_USE; - - page_zip_des_init(&block->page.zip); -} - -struct fil_iterator_t { - pfs_os_file_t file; /*!< File handle */ - const char* filepath; /*!< File path name */ - os_offset_t start; /*!< From where to start */ - os_offset_t end; /*!< Where to stop */ - os_offset_t file_size; /*!< File size in bytes */ - ulint page_size; /*!< Page size */ - ulint n_io_buffers; /*!< Number of pages to use - for IO */ - byte* io_buffer; /*!< Buffer to use for IO */ - fil_space_crypt_t *crypt_data; /*!< MariaDB Crypt data (if encrypted) */ - byte* crypt_io_buffer; /*!< MariaDB IO buffer when - encrypted */ - dict_table_t* table; /*!< Imported table */ -}; - -/********************************************************************//** -TODO: This can be made parallel trivially by chunking up the file and creating -a callback per thread. Main benefit will be to use multiple CPUs for -checksums and compressed tables. We have to do compressed tables block by -block right now. Secondly we need to decompress/compress and copy too much -of data. These are CPU intensive. - -Iterate over all the pages in the tablespace. -@param iter Tablespace iterator -@param block block to use for IO -@param callback Callback to inspect and update page contents -@retval DB_SUCCESS or error code */ -static -dberr_t -fil_iterate( -/*========*/ - const fil_iterator_t& iter, - buf_block_t* block, - PageCallback& callback) -{ - os_offset_t offset; - ulint page_no = 0; - ulint space_id = callback.get_space_id(); - ulint n_bytes = iter.n_io_buffers * iter.page_size; - - ut_ad(!srv_read_only_mode); - - /* TODO: For compressed tables we do a lot of useless - copying for non-index pages. Unfortunately, it is - required by buf_zip_decompress() */ - const bool row_compressed - = callback.get_page_size().is_compressed(); - - for (offset = iter.start; offset < iter.end; offset += n_bytes) { - - byte* io_buffer = iter.io_buffer; - - block->frame = io_buffer; - - if (row_compressed) { - page_zip_des_init(&block->page.zip); - page_zip_set_size(&block->page.zip, iter.page_size); - - block->page.size.copy_from( - page_size_t(iter.page_size, - univ_page_size.logical(), - true)); - - block->page.zip.data = block->frame + UNIV_PAGE_SIZE; - ut_d(block->page.zip.m_external = true); - ut_ad(iter.page_size - == callback.get_page_size().physical()); - - /* Zip IO is done in the compressed page buffer. */ - io_buffer = block->page.zip.data; - } - - /* We have to read the exact number of bytes. Otherwise the - InnoDB IO functions croak on failed reads. */ - - n_bytes = static_cast<ulint>( - ut_min(static_cast<os_offset_t>(n_bytes), - iter.end - offset)); - - ut_ad(n_bytes > 0); - ut_ad(!(n_bytes % iter.page_size)); - - const bool encrypted = iter.crypt_data != NULL - && iter.crypt_data->should_encrypt(); - /* Use additional crypt io buffer if tablespace is encrypted */ - byte* const readptr = encrypted - ? iter.crypt_io_buffer : io_buffer; - byte* const writeptr = readptr; - IORequest read_request(IORequest::READ); - dberr_t err = os_file_read( - read_request, iter.file, readptr, offset, - (ulint) n_bytes); - - if (err != DB_SUCCESS) { - - ib::error() << "os_file_read() failed"; - - return(err); - } - - bool updated = false; - os_offset_t page_off = offset; - ulint n_pages_read = (ulint) n_bytes / iter.page_size; - bool decrypted = false; - - for (ulint i = 0; i < n_pages_read; ++i) { - ulint size = iter.page_size; - dberr_t err = DB_SUCCESS; - byte* src = readptr + (i * size); - byte* dst = io_buffer + (i * size); - bool frame_changed = false; - - ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE); - - const bool page_compressed - = page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED - || page_type == FIL_PAGE_PAGE_COMPRESSED; - - /* If tablespace is encrypted, we need to decrypt - the page. Note that tablespaces are not in - fil_system during import. */ - if (encrypted) { - decrypted = fil_space_decrypt( - iter.crypt_data, - dst, //dst - callback.get_page_size(), - src, // src - &err); // src - - if (err != DB_SUCCESS) { - return(err); - } - - if (decrypted) { - updated = true; - } else if (!page_compressed - && !row_compressed) { - block->frame = src; - frame_changed = true; - } else { - memcpy(dst, src, size); - } - } - - /* If the original page is page_compressed, we need - to decompress page before we can update it. */ - if (page_compressed) { - fil_decompress_page(NULL, dst, ulong(size), - NULL); - updated = true; - } - - buf_block_set_file_page( - block, page_id_t(space_id, page_no++)); - - if ((err = callback(page_off, block)) != DB_SUCCESS) { - - return(err); - - } else if (!updated) { - updated = buf_block_get_state(block) - == BUF_BLOCK_FILE_PAGE; - } - - buf_block_set_state(block, BUF_BLOCK_NOT_USED); - buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE); - - /* If tablespace is encrypted we use additional - temporary scratch area where pages are read - for decrypting readptr == crypt_io_buffer != io_buffer. - - Destination for decryption is a buffer pool block - block->frame == dst == io_buffer that is updated. - Pages that did not require decryption even when - tablespace is marked as encrypted are not copied - instead block->frame is set to src == readptr. - - For encryption we again use temporary scratch area - writeptr != io_buffer == dst - that is then written to the tablespace - - (1) For normal tables io_buffer == dst == writeptr - (2) For only page compressed tables - io_buffer == dst == writeptr - (3) For encrypted (and page compressed) - readptr != io_buffer == dst != writeptr - */ - - ut_ad(!encrypted && !page_compressed ? - src == dst && dst == writeptr + (i * size):1); - ut_ad(page_compressed && !encrypted ? - src == dst && dst == writeptr + (i * size):1); - ut_ad(encrypted ? - src != dst && dst != writeptr + (i * size):1); - - if (encrypted) { - memcpy(writeptr + (i * size), - row_compressed ? block->page.zip.data : - block->frame, size); - } - - if (frame_changed) { - block->frame = dst; - } - - src = io_buffer + (i * size); - - if (page_compressed) { - ulint len = 0; - - byte * res = fil_compress_page( - NULL, - src, - NULL, - size, - dict_table_page_compression_level(iter.table), - 512,/* FIXME: use proper block size */ - encrypted, - &len); - - if (len != size) { - memset(res+len, 0, size-len); - } - - updated = true; - } - - /* If tablespace is encrypted, encrypt page before we - write it back. Note that we should not encrypt the - buffer that is in buffer pool. */ - /* NOTE: At this stage of IMPORT the - buffer pool is not being used at all! */ - if (decrypted && encrypted) { - byte *dest = writeptr + (i * size); - ulint space = mach_read_from_4( - src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET); - ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN); - - byte* tmp = fil_encrypt_buf( - iter.crypt_data, - space, - offset, - lsn, - src, - callback.get_page_size(), - dest); - - if (tmp == src) { - /* TODO: remove unnecessary memcpy's */ - memcpy(dest, src, iter.page_size); - } - - updated = true; - } - - page_off += iter.page_size; - block->frame += iter.page_size; - } - - IORequest write_request(IORequest::WRITE); - - /* A page was updated in the set, write back to disk. - Note: We don't have the compression algorithm, we write - out the imported file as uncompressed. */ - - if (updated - && (err = os_file_write( - write_request, - iter.filepath, iter.file, writeptr, - offset, (ulint) n_bytes)) != DB_SUCCESS) { - - ib::error() << "os_file_write() failed"; - return(err); - } - - /* Clean up the temporal buffer. */ - memset(writeptr, 0, n_bytes); - } - - return(DB_SUCCESS); -} - -/********************************************************************//** -Iterate over all the pages in the tablespace. -@param table the table definiton in the server -@param n_io_buffers number of blocks to read and write together -@param callback functor that will do the page updates -@return DB_SUCCESS or error code */ -dberr_t -fil_tablespace_iterate( -/*===================*/ - dict_table_t* table, - ulint n_io_buffers, - PageCallback& callback) -{ - dberr_t err; - pfs_os_file_t file; - char* filepath; - bool success; - - ut_a(n_io_buffers > 0); - ut_ad(!srv_read_only_mode); - - DBUG_EXECUTE_IF("ib_import_trigger_corruption_1", - return(DB_CORRUPTION);); - - /* Make sure the data_dir_path is set. */ - dict_get_and_save_data_dir_path(table, false); - - if (DICT_TF_HAS_DATA_DIR(table->flags)) { - ut_a(table->data_dir_path); - - filepath = fil_make_filepath( - table->data_dir_path, table->name.m_name, IBD, true); - } else { - filepath = fil_make_filepath( - NULL, table->name.m_name, IBD, false); - } - - if (filepath == NULL) { - return(DB_OUT_OF_MEMORY); - } - - file = os_file_create_simple_no_error_handling( - innodb_data_file_key, filepath, - OS_FILE_OPEN, OS_FILE_READ_WRITE, srv_read_only_mode, &success); - - if (!success) { - /* The following call prints an error message */ - os_file_get_last_error(true); - - ib::error() << "Trying to import a tablespace, but could not" - " open the tablespace file " << filepath; - - ut_free(filepath); - - return(DB_TABLESPACE_NOT_FOUND); - - } else { - err = DB_SUCCESS; - } - - callback.set_file(filepath, file); - - os_offset_t file_size = os_file_get_size(file); - ut_a(file_size != (os_offset_t) -1); - - /* The block we will use for every physical page */ - buf_block_t* block; - - block = reinterpret_cast<buf_block_t*>(ut_zalloc_nokey(sizeof(*block))); - - mutex_create(LATCH_ID_BUF_BLOCK_MUTEX, &block->mutex); - - /* Allocate a page to read in the tablespace header, so that we - can determine the page size and zip size (if it is compressed). - We allocate an extra page in case it is a compressed table. One - page is to ensure alignement. */ - - void* page_ptr = ut_malloc_nokey(3 * UNIV_PAGE_SIZE); - byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE)); - - fil_buf_block_init(block, page); - - /* Read the first page and determine the page and zip size. */ - - IORequest request(IORequest::READ); - - err = os_file_read(request, file, page, 0, UNIV_PAGE_SIZE); - - if (err != DB_SUCCESS) { - - err = DB_IO_ERROR; - - } else if ((err = callback.init(file_size, block)) == DB_SUCCESS) { - fil_iterator_t iter; - - iter.file = file; - iter.start = 0; - iter.end = file_size; - iter.filepath = filepath; - iter.file_size = file_size; - iter.n_io_buffers = n_io_buffers; - iter.page_size = callback.get_page_size().physical(); - iter.table = table; - - /* read (optional) crypt data */ - iter.crypt_data = fil_space_read_crypt_data( - callback.get_page_size(), page); - - if (err == DB_SUCCESS) { - - /* Compressed pages can't be optimised for block IO - for now. We do the IMPORT page by page. */ - - if (callback.get_page_size().is_compressed()) { - iter.n_io_buffers = 1; - ut_a(iter.page_size - == callback.get_page_size().physical()); - } - - /** Add an extra page for compressed page scratch - area. */ - void* io_buffer = ut_malloc_nokey( - (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE); - - iter.io_buffer = static_cast<byte*>( - ut_align(io_buffer, UNIV_PAGE_SIZE)); - - void* crypt_io_buffer; - if (iter.crypt_data) { - crypt_io_buffer = static_cast<byte*>( - ut_malloc_nokey((2 + iter.n_io_buffers) - * UNIV_PAGE_SIZE)); - iter.crypt_io_buffer = static_cast<byte*>( - ut_align(crypt_io_buffer, - UNIV_PAGE_SIZE)); - } else { - crypt_io_buffer = NULL; - } - - err = fil_iterate(iter, block, callback); - - if (iter.crypt_data) { - fil_space_destroy_crypt_data(&iter.crypt_data); - } - - ut_free(io_buffer); - ut_free(crypt_io_buffer); - } - } - - if (err == DB_SUCCESS) { - - ib::info() << "Sync to disk"; - - if (!os_file_flush(file)) { - ib::info() << "os_file_flush() failed!"; - err = DB_IO_ERROR; - } else { - ib::info() << "Sync to disk - done!"; - } - } - - os_file_close(file); - - ut_free(page_ptr); - ut_free(filepath); - - mutex_free(&block->mutex); - - ut_free(block); - - return(err); -} - -/********************************************************************//** Delete the tablespace file and any related files like .cfg. This should not be called for temporary tables. @param[in] ibd_filepath File path of the IBD tablespace */ diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index fe98ac4f846..4e86c36d005 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -35,7 +35,7 @@ Created 2013/03/27 Allen Lai and Jimmy Yang #include "rem0cmp.h" #include "lock0lock.h" #include "ibuf0ibuf.h" -#include "trx0trx.h" +#include "trx0undo.h" #include "srv0mon.h" #include "gis0geo.h" diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index 65c346d6d36..2f8c9c26288 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -37,6 +37,7 @@ Created 2014/01/16 Jimmy Yang #include "ibuf0ibuf.h" #include "trx0trx.h" #include "srv0mon.h" +#include "que0que.h" #include "gis0geo.h" /** Restore the stored position of a persistent cursor bufferfixing the page */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b4f3a27b5af..b8f626e32ce 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -280,7 +280,7 @@ is_partition( /** Signal to shut down InnoDB (NULL if shutdown was signaled, or if running in innodb_read_only mode, srv_read_only_mode) */ -volatile st_my_thread_var *srv_running; +st_my_thread_var *srv_running; /** Service thread that waits for the server shutdown and stops purge threads. Purge workers have THDs that are needed to calculate virtual columns. This THDs must be destroyed rather early in the server shutdown sequence. @@ -307,12 +307,16 @@ thd_destructor_proxy(void *) myvar->current_cond = &thd_destructor_cond; mysql_mutex_lock(&thd_destructor_mutex); - srv_running = myvar; + my_atomic_storeptr_explicit(reinterpret_cast<void**>(&srv_running), + myvar, + MY_MEMORY_ORDER_RELAXED); /* wait until the server wakes the THD to abort and die */ while (!srv_running->abort) mysql_cond_wait(&thd_destructor_cond, &thd_destructor_mutex); mysql_mutex_unlock(&thd_destructor_mutex); - srv_running = NULL; + my_atomic_storeptr_explicit(reinterpret_cast<void**>(&srv_running), + NULL, + MY_MEMORY_ORDER_RELAXED); while (srv_fast_shutdown == 0 && (trx_sys.any_active_transactions() || @@ -1193,7 +1197,9 @@ innobase_close_connection( THD* thd); /*!< in: MySQL thread handle for which to close the connection */ -static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level); +/** Cancel any pending lock request associated with the current THD. +@sa THD::awake() @sa ha_kill_query() */ +static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels); static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all); /*****************************************************************//** @@ -1639,41 +1645,6 @@ innobase_reset_background_thd(MYSQL_THD thd) } -#if 0 -/** -Check if the transaction can be rolled back -@param[in] requestor Session requesting the lock -@param[in] holder Session that holds the lock -@return the session that will be rolled back, null don't care */ - -THD* -thd_trx_arbitrate(THD* requestor, THD* holder) -{ - /* Non-user (thd==0) transactions by default can't rollback, in - practice DDL transactions should never rollback and that's because - they should never wait on table/record locks either */ - - ut_a(holder != NULL); - ut_a(holder != requestor); - - THD* victim = thd_tx_arbitrate(requestor, holder); - - ut_a(victim == NULL || victim == requestor || victim == holder); - - return(victim); -} - -/** -@param[in] thd Session to check -@return the priority */ - -int -thd_trx_priority(THD* thd) -{ - return(thd == NULL ? 0 : thd_tx_priority(thd)); -} -#endif - /******************************************************************//** Check if the transaction is an auto-commit transaction. TRUE also implies that it is a SELECT (read-only) transaction. @@ -1975,7 +1946,6 @@ convert_error_code_to_mysql( case DB_RECORD_NOT_FOUND: return(HA_ERR_NO_ACTIVE_RECORD); - case DB_FORCED_ABORT: case DB_DEADLOCK: /* Since we rolled back the whole transaction, we must tell it also to MySQL so that MySQL knows to empty the @@ -2797,10 +2767,6 @@ check_trx_exists( return trx; } else { trx = innobase_trx_allocate(thd); - /* User trx can be forced to rollback, - so we unset the disable flag. */ - ut_ad(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE); - trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK; thd_set_ha_data(thd, innodb_hton_ptr, trx); return trx; } @@ -3018,11 +2984,8 @@ ha_innobase::update_thd( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - - ut_ad(trx_in_innodb.is_aborted() - || (trx->dict_operation_lock_mode == 0 - && trx->dict_operation == TRX_DICT_OP_NONE)); + ut_ad(trx->dict_operation_lock_mode == 0); + ut_ad(trx->dict_operation == TRX_DICT_OP_NONE); if (m_prebuilt->trx != trx) { @@ -3488,8 +3451,6 @@ ha_innobase::init_table_handle_for_HANDLER(void) trx_start_if_not_started_xa(m_prebuilt->trx, false); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - /* Assign a read view if the transaction does not have it yet */ m_prebuilt->trx->read_view.open(m_prebuilt->trx); @@ -4194,7 +4155,9 @@ innobase_change_buffering_inited_ok: mysql_thread_create(thd_destructor_thread_key, &thd_destructor_thread, NULL, thd_destructor_proxy, NULL); - while (!srv_running) + while (!my_atomic_loadptr_explicit(reinterpret_cast<void**> + (&srv_running), + MY_MEMORY_ORDER_RELAXED)) os_thread_sleep(20); } @@ -4285,10 +4248,14 @@ innobase_end(handlerton*, ha_panic_function) hash_table_free(innobase_open_tables); innobase_open_tables = NULL; - if (!abort_loop && srv_running) { + st_my_thread_var* running = reinterpret_cast<st_my_thread_var*>( + my_atomic_loadptr_explicit( + reinterpret_cast<void**>(&srv_running), + MY_MEMORY_ORDER_RELAXED)); + if (!abort_loop && running) { // may be UNINSTALL PLUGIN statement - srv_running->abort = 1; - mysql_cond_broadcast(srv_running->current_cond); + running->abort = 1; + mysql_cond_broadcast(running->current_cond); } if (!srv_read_only_mode) { @@ -4362,8 +4329,6 @@ innobase_start_trx_and_assign_read_view( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - innobase_srv_conc_force_exit_innodb(trx); /* The transaction should not be active yet, start it */ @@ -4500,7 +4465,6 @@ innobase_commit_ordered( DBUG_ASSERT(hton == innodb_hton_ptr); trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { /* We cannot throw error here; instead we will catch this error @@ -4544,16 +4508,6 @@ innobase_commit( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(hton, thd, commit_trx); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, thd)); - } - ut_ad(trx->dict_operation_lock_mode == 0); ut_ad(trx->dict_operation == TRX_DICT_OP_NONE); @@ -4645,11 +4599,8 @@ innobase_rollback( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - - ut_ad(trx_in_innodb.is_aborted() - || (trx->dict_operation_lock_mode == 0 - && trx->dict_operation == TRX_DICT_OP_NONE)); + ut_ad(trx->dict_operation_lock_mode == 0); + ut_ad(trx->dict_operation == TRX_DICT_OP_NONE); innobase_srv_conc_force_exit_innodb(trx); @@ -4660,10 +4611,7 @@ innobase_rollback( /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ - - if (!trx_in_innodb.is_aborted()) { - lock_unlock_table_autoinc(trx); - } + lock_unlock_table_autoinc(trx); /* This is a statement level variable. */ @@ -4676,18 +4624,6 @@ innobase_rollback( error = trx_rollback_for_mysql(trx); - if (trx->state == TRX_STATE_FORCED_ROLLBACK) { -#ifndef DBUG_OFF - char buffer[1024]; - - DBUG_LOG("trx", "Forced rollback: " - << thd_get_error_context_description( - thd, buffer, sizeof buffer, 512)); -#endif /* !DBUG_OFF */ - - trx->state = TRX_STATE_NOT_STARTED; - } - trx_deregister_from_2pc(trx); } else { @@ -4714,9 +4650,7 @@ innobase_rollback_trx( /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ - if (!TrxInInnoDB::is_aborted(trx)) { - lock_unlock_table_autoinc(trx); - } + lock_unlock_table_autoinc(trx); if (!trx->has_logged()) { trx->will_lock = 0; @@ -4888,8 +4822,6 @@ innobase_rollback_to_savepoint( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - innobase_srv_conc_force_exit_innodb(trx); /* TODO: use provided savepoint data area to store savepoint data */ @@ -4930,8 +4862,6 @@ innobase_rollback_to_savepoint_can_release_mdl( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - /* If transaction has not acquired any locks then it is safe to release MDL after rollback to savepoint */ if (UT_LIST_GET_LEN(trx->lock.trx_locks) == 0) { @@ -4965,8 +4895,6 @@ innobase_release_savepoint( trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - /* TODO: use provided savepoint data area to store savepoint data */ longlong2str((ulint) savepoint, name, 36); @@ -5000,8 +4928,6 @@ innobase_savepoint( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - innobase_srv_conc_force_exit_innodb(trx); /* Cannot happen outside of transaction */ @@ -5037,7 +4963,6 @@ innobase_close_connection( DBUG_ASSERT(hton == innodb_hton_ptr); trx_t* trx = thd_to_trx(thd); - bool free_trx = false; /* During server initialization MySQL layer will try to open some of the master-slave tables those residing in InnoDB. @@ -5054,16 +4979,6 @@ innobase_close_connection( if (trx) { - TrxInInnoDB trx_in_innodb(trx); - - if (trx_in_innodb.is_aborted()) { - - while (trx_is_started(trx)) { - - os_thread_sleep(20); - } - } - if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { sql_print_error("Transaction not registered for MariaDB 2PC, " @@ -5081,9 +4996,8 @@ innobase_close_connection( if (trx->has_logged_persistent()) { trx_disconnect_prepared(trx); } else { - trx_rollback_for_mysql(trx); trx_deregister_from_2pc(trx); - free_trx = true; + goto rollback_and_free; } } else { sql_print_warning( @@ -5091,44 +5005,25 @@ innobase_close_connection( "InnoDB transaction. " TRX_ID_FMT " row modifications " "will roll back.", trx->undo_no); - ut_d(ib::warn() - << "trx: " << trx << " started on: " - << innobase_basename(trx->start_file) - << ":" << trx->start_line); - innobase_rollback_trx(trx); - free_trx = true; + goto rollback_and_free; } } else { +rollback_and_free: innobase_rollback_trx(trx); - free_trx = true; + trx_free_for_mysql(trx); } } - /* Free trx only after TrxInInnoDB is deleted. */ - if (free_trx) { - trx_free_for_mysql(trx); - } - DBUG_RETURN(0); } UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock); -/*****************************************************************//** -Cancel any pending lock request associated with the current THD. */ -static -void -innobase_kill_query( -/*================*/ - handlerton* hton, /*!< in: innobase handlerton */ - THD* thd, /*!< in: MySQL thread being killed */ - enum thd_kill_levels level) /*!< in: kill level */ +/** Cancel any pending lock request associated with the current THD. +@sa THD::awake() @sa ha_kill_query() */ +static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels) { - trx_t* trx; - DBUG_ENTER("innobase_kill_query"); - DBUG_ASSERT(hton == innodb_hton_ptr); - #ifdef WITH_WSREP wsrep_thd_LOCK(thd); if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) { @@ -5144,43 +5039,10 @@ innobase_kill_query( wsrep_thd_UNLOCK(thd); #endif /* WITH_WSREP */ - trx = thd_to_trx(thd); - - if (trx != NULL) { + if (trx_t* trx = thd_to_trx(thd)) { + ut_ad(trx->mysql_thd == thd); /* Cancel a pending lock request if there are any */ - bool lock_mutex_taken = false; - bool trx_mutex_taken = false; - - if (trx->lock.wait_lock) { - WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " IB_ID_FMT " ABORT %d thd %p" - " current_thd %p BF %d", - trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE), - wsrep_thd_is_BF(thd, FALSE), - trx->id, trx->abort_type, - trx->mysql_thd, - current_thd, - wsrep_thd_is_BF(current_thd, FALSE)); - } - - if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && trx->abort_type != TRX_WSREP_ABORT) { - lock_mutex_enter(); - lock_mutex_taken = true; - } - - if (trx->abort_type != TRX_WSREP_ABORT) { - trx_mutex_enter(trx); - trx_mutex_taken = true; - } - - lock_trx_handle_wait(trx, true, true); - - if (lock_mutex_taken) { - lock_mutex_exit(); - } - - if (trx_mutex_taken) { - trx_mutex_exit(trx); - } + lock_trx_handle_wait(trx); } DBUG_VOID_RETURN; @@ -8171,17 +8033,8 @@ ha_innobase::write_row( DBUG_ENTER("ha_innobase::write_row"); trx_t* trx = thd_to_trx(m_user_thd); - TrxInInnoDB trx_in_innodb(trx); ins_mode_t vers_set_fields; - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - /* Validation checks before we commence write_row operation. */ if (high_level_read_only) { ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); @@ -9016,14 +8869,6 @@ ha_innobase::update_row( goto func_exit; } - if (TrxInInnoDB::is_aborted(trx)) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - { const bool vers_set_fields = m_prebuilt->versioned_write && m_prebuilt->upd_node->update->affects_versioned(); @@ -9135,18 +8980,9 @@ ha_innobase::delete_row( { dberr_t error; trx_t* trx = thd_to_trx(m_user_thd); - TrxInInnoDB trx_in_innodb(trx); DBUG_ENTER("ha_innobase::delete_row"); - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - ut_a(m_prebuilt->trx == trx); if (high_level_read_only) { @@ -9219,19 +9055,7 @@ ha_innobase::unlock_row(void) DBUG_VOID_RETURN; } - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - - if (trx_in_innodb.is_aborted()) { - DBUG_VOID_RETURN; - } - - /* Ideally, this assert must be in the beginning of the function. - But there are some calls to this function from the SQL layer when the - transaction is in state TRX_STATE_NOT_STARTED. The check on - m_prebuilt->select_lock_type above gets around this issue. */ - - ut_ad(trx_state_eq(m_prebuilt->trx, TRX_STATE_ACTIVE) - || trx_state_eq(m_prebuilt->trx, TRX_STATE_FORCED_ROLLBACK)); + ut_ad(trx_state_eq(m_prebuilt->trx, TRX_STATE_ACTIVE, true)); switch (m_prebuilt->row_read_type) { case ROW_READ_WITH_LOCKS: @@ -9513,14 +9337,6 @@ ha_innobase::index_read( innobase_srv_conc_enter_innodb(m_prebuilt); - if (TrxInInnoDB::is_aborted(m_prebuilt->trx)) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - ret = row_search_mvcc( buf, mode, m_prebuilt, match_mode, 0); @@ -9701,16 +9517,6 @@ ha_innobase::change_active_index( ut_ad(m_user_thd == ha_thd()); ut_a(m_prebuilt->trx == thd_to_trx(m_user_thd)); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - active_index = keynr; m_prebuilt->index = innobase_get_index(keynr); @@ -9829,14 +9635,6 @@ ha_innobase::general_fetch( ut_ad(trx == thd_to_trx(m_user_thd)); - if (TrxInInnoDB::is_aborted(trx)) { - - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - if (m_prebuilt->table->is_readable()) { } else if (m_prebuilt->table->corrupted) { DBUG_RETURN(HA_ERR_CRASHED); @@ -10003,7 +9801,6 @@ ha_innobase::rnd_init( /*==================*/ bool scan) /*!< in: true if table/index scan FALSE otherwise */ { - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); int err; /* Store the active index value so that we can restore the original @@ -10053,8 +9850,6 @@ ha_innobase::rnd_next( DBUG_ENTER("rnd_next"); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - if (m_start_of_scan) { error = index_first(buf); @@ -10178,21 +9973,6 @@ ha_innobase::ft_init_ext( trx_t* trx = m_prebuilt->trx; - TrxInInnoDB trx_in_innodb(trx); - - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(ht, m_user_thd, false); - - int err; - err = convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd); - - my_error(err, MYF(0)); - - return(NULL); - } - /* FTS queries are not treated as autocommit non-locking selects. This is because the FTS implementation can acquire locks behind the scenes. This has not been verified but it is safer to treat @@ -10334,16 +10114,6 @@ ha_innobase::ft_read( /*=================*/ uchar* buf) /*!< in/out: buf contain result row */ { - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(ht, m_user_thd, false); - - return(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - row_prebuilt_t* ft_prebuilt; ft_prebuilt = reinterpret_cast<NEW_FT_INFO*>(ft_handler)->ft_prebuilt; @@ -13096,15 +12866,6 @@ ha_innobase::discard_or_import_tablespace( DBUG_RETURN(HA_ERR_TABLE_NEEDS_UPGRADE); } - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - - if (trx_in_innodb.is_aborted()) { - innobase_rollback(ht, m_user_thd, false); - - DBUG_RETURN(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, m_user_thd)); - } - trx_start_if_not_started(m_prebuilt->trx, true); /* Obtain an exclusive lock on the table. */ @@ -13204,8 +12965,6 @@ ha_innobase::truncate() update_thd(ha_thd()); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - m_prebuilt->trx->ddl = true; trx_start_if_not_started(m_prebuilt->trx, true); @@ -13282,8 +13041,6 @@ ha_innobase::delete_table( trx_t* parent_trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(parent_trx); - /* Remove the to-be-dropped table from the list of modified tables by parent_trx. Otherwise we may end up with an orphaned pointer to the table object from parent_trx::mod_tables. This could happen in: @@ -13527,8 +13284,6 @@ innobase_rename_table( DEBUG_SYNC_C("innodb_rename_table_ready"); - TrxInInnoDB trx_in_innodb(trx); - trx_start_if_not_started(trx, true); ut_ad(trx->will_lock > 0); @@ -13616,13 +13371,6 @@ ha_innobase::rename_table( DBUG_RETURN(HA_ERR_TABLE_READONLY); } - /* Get the transaction associated with the current thd, or create one - if not yet created */ - - trx_t* parent_trx = check_trx_exists(thd); - - TrxInInnoDB trx_in_innodb(parent_trx); - trx_t* trx = innobase_trx_allocate(thd); /* We are doing a DDL operation. */ @@ -13706,8 +13454,6 @@ ha_innobase::records_in_range( m_prebuilt->trx->op_info = "estimating records in index range"; - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - active_index = keynr; key = table->key_info + active_index; @@ -13839,8 +13585,6 @@ ha_innobase::estimate_rows_upper_bound() update_thd(ha_thd()); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - m_prebuilt->trx->op_info = "calculating upper bound for table rows"; index = dict_table_get_first_index(m_prebuilt->table); @@ -14682,8 +14426,6 @@ ha_innobase::optimize( HA_CHECK_OPT* check_opt) /*!< in: currently ignored */ { - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - /* FTS-FIXME: Since MySQL doesn't support engine-specific commands, we have to hijack some existing command in order to be able to test the new admin commands added in InnoDB's FTS support. For now, we @@ -14752,8 +14494,6 @@ ha_innobase::check( ut_a(m_prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(m_prebuilt->trx == thd_to_trx(thd)); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - if (m_prebuilt->mysql_template == NULL) { /* Build the template; we will use a dummy template in index scans done in checking */ @@ -15244,8 +14984,6 @@ ha_innobase::get_foreign_key_list( { update_thd(ha_thd()); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - m_prebuilt->trx->op_info = "getting list of foreign keys"; mutex_enter(&dict_sys->mutex); @@ -15284,8 +15022,6 @@ ha_innobase::get_parent_foreign_key_list( { update_thd(ha_thd()); - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - m_prebuilt->trx->op_info = "getting list of referencing foreign keys"; mutex_enter(&dict_sys->mutex); @@ -15382,8 +15118,6 @@ ha_innobase::get_cascade_foreign_key_table_list( THD* thd, List<st_handler_tablename>* fk_table_list) { - TrxInInnoDB trx_in_innodb(m_prebuilt->trx); - m_prebuilt->trx->op_info = "getting cascading foreign keys"; std::list<table_list_item, ut_allocator<table_list_item> > table_list; @@ -15643,15 +15377,6 @@ ha_innobase::end_stmt() /* This is a statement level counter. */ m_prebuilt->autoinc_last_value = 0; - /* This transaction had called ha_innobase::start_stmt() */ - trx_t* trx = m_prebuilt->trx; - - if (trx->lock.start_stmt) { - TrxInInnoDB::end_stmt(trx); - - trx->lock.start_stmt = false; - } - return(0); } @@ -15691,8 +15416,6 @@ ha_innobase::start_stmt( ut_ad(m_prebuilt->table != NULL); - TrxInInnoDB trx_in_innodb(trx); - trx = m_prebuilt->trx; innobase_srv_conc_force_exit_innodb(trx); @@ -15765,14 +15488,6 @@ ha_innobase::start_stmt( ++trx->will_lock; } - /* Only do it once per transaction. */ - if (!trx->lock.start_stmt && lock_type != TL_UNLOCK) { - - TrxInInnoDB::begin_stmt(trx); - - trx->lock.start_stmt = true; - } - DBUG_RETURN(0); } @@ -16007,13 +15722,8 @@ ha_innobase::external_lock( ++trx->will_lock; } - TrxInInnoDB::begin_stmt(trx); - DBUG_RETURN(0); } else { - - TrxInInnoDB::end_stmt(trx); - DEBUG_SYNC_C("ha_innobase_end_statement"); } @@ -16102,8 +15812,6 @@ innodb_show_status( innobase_srv_conc_force_exit_innodb(trx); - TrxInInnoDB trx_in_innodb(trx); - /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE bytes of text. */ @@ -16688,8 +16396,6 @@ ha_innobase::store_lock( trx_t* trx = check_trx_exists(thd); - TrxInInnoDB trx_in_innodb(trx); - /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE! Be careful to ignore TL_IGNORE if we are going to do something with only 'real' locks! */ @@ -17009,8 +16715,6 @@ ha_innobase::get_auto_increment( trx = m_prebuilt->trx; - TrxInInnoDB trx_in_innodb(trx); - /* Note: We can't rely on *first_value since some MySQL engines, in particular the partition engine, don't initialize it to 0 when invoking this method. So we are not sure if it's guaranteed to @@ -17411,16 +17115,6 @@ innobase_xa_prepare( innobase_srv_conc_force_exit_innodb(trx); - TrxInInnoDB trx_in_innodb(trx); - - if (trx_in_innodb.is_aborted()) { - - innobase_rollback(hton, thd, prepare_trx); - - return(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, thd)); - } - if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { sql_print_error("Transaction not registered for MariaDB 2PC," @@ -17435,18 +17129,7 @@ innobase_xa_prepare( ut_ad(trx_is_registered_for_2pc(trx)); - dberr_t err = trx_prepare_for_mysql(trx); - - ut_ad(err == DB_SUCCESS || err == DB_FORCED_ABORT); - - if (err == DB_FORCED_ABORT) { - - innobase_rollback(hton, thd, prepare_trx); - - return(convert_error_code_to_mysql( - DB_FORCED_ABORT, 0, thd)); - } - + trx_prepare_for_mysql(trx); } else { /* We just mark the SQL statement ended and do not do a transaction prepare */ @@ -17523,14 +17206,10 @@ innobase_commit_by_xid( } if (trx_t* trx = trx_get_trx_by_xid(xid)) { - ut_ad(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE); /* use cases are: disconnected xa, slave xa, recovery */ - { - TrxInInnoDB trx_in_innodb(trx); - innobase_commit_low(trx); - ut_ad(trx->mysql_thd == NULL); - trx_deregister_from_2pc(trx); - } + innobase_commit_low(trx); + ut_ad(trx->mysql_thd == NULL); + trx_deregister_from_2pc(trx); ut_ad(!trx->will_lock); /* trx cache requirement */ trx_free_for_background(trx); @@ -17559,14 +17238,9 @@ innobase_rollback_by_xid( } if (trx_t* trx = trx_get_trx_by_xid(xid)) { - int ret; - ut_ad(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE); - { - TrxInInnoDB trx_in_innodb(trx); - ret = innobase_rollback_trx(trx); - trx_deregister_from_2pc(trx); - ut_ad(!trx->will_lock); - } + int ret = innobase_rollback_trx(trx); + trx_deregister_from_2pc(trx); + ut_ad(!trx->will_lock); trx_free_for_background(trx); return(ret); @@ -17781,7 +17455,10 @@ fast_shutdown_validate( uint new_val = *reinterpret_cast<uint*>(save); - if (srv_fast_shutdown && !new_val && !srv_running) { + if (srv_fast_shutdown && !new_val + && !my_atomic_loadptr_explicit(reinterpret_cast<void**> + (&srv_running), + MY_MEMORY_ORDER_RELAXED)) { return(1); } @@ -19578,7 +19255,7 @@ wsrep_innobase_kill_one_trx( thd_get_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", thd_get_thread_id(thd)); - /* Note that innobase_kill_connection will take lock_mutex + /* Note that innobase_kill_query will take lock_mutex and trx_mutex */ wsrep_thd_UNLOCK(thd); wsrep_thd_awake(thd, signal); @@ -19655,12 +19332,10 @@ wsrep_abort_transaction( if (victim_trx) { lock_mutex_enter(); trx_mutex_enter(victim_trx); - victim_trx->abort_type = TRX_WSREP_ABORT; int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, victim_trx, signal); - trx_mutex_exit(victim_trx); lock_mutex_exit(); - victim_trx->abort_type = TRX_SERVER_ABORT; + trx_mutex_exit(victim_trx); wsrep_srv_conc_cancel_wait(victim_trx); DBUG_RETURN(rcode); } else { diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index b775bfa40ee..b331d9e549c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2955,8 +2955,7 @@ online_retry_drop_indexes_with_trx( dict_table_t* table, /*!< in/out: table */ trx_t* trx) /*!< in/out: transaction */ { - ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED) - || trx_state_eq(trx, TRX_STATE_FORCED_ROLLBACK)); + ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 857b2d3acef..e9b33e556c8 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2017, MariaDB Corporation. +Copyright (c) 2014, 2018, MariaDB Corporation. 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 @@ -8617,12 +8617,6 @@ i_s_tablespaces_encryption_fill_table( TABLE_LIST* tables, /*!< in/out: tables to fill */ Item* ) /*!< in: condition (not used) */ { - btr_pcur_t pcur; - const rec_t* rec; - mem_heap_t* heap; - mtr_t mtr; - bool found_space_0 = false; - DBUG_ENTER("i_s_tablespaces_encryption_fill_table"); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); @@ -8631,68 +8625,24 @@ i_s_tablespaces_encryption_fill_table( DBUG_RETURN(0); } - heap = mem_heap_create(1000); - mutex_enter(&dict_sys->mutex); - mtr_start(&mtr); - - rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES); - - while (rec) { - const char* err_msg; - ulint space_id; - const char* name; - ulint flags; - - /* Extract necessary information from a SYS_TABLESPACES row */ - err_msg = dict_process_sys_tablespaces( - heap, rec, &space_id, &name, &flags); - - mtr_commit(&mtr); - mutex_exit(&dict_sys->mutex); - - if (space_id == 0) { - found_space_0 = true; - } - - fil_space_t* space = fil_space_acquire_silent(space_id); - - if (!err_msg && space) { - i_s_dict_fill_tablespaces_encryption( - thd, space, tables->table); - } else { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_CANT_FIND_SYSTEM_REC, "%s", - err_msg); - } - - if (space) { - fil_space_release(space); + mutex_enter(&fil_system->mutex); + + for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system->space_list); + space; space = UT_LIST_GET_NEXT(space_list, space)) { + if (space->purpose == FIL_TYPE_TABLESPACE) { + space->n_pending_ops++; + mutex_exit(&fil_system->mutex); + if (int err = i_s_dict_fill_tablespaces_encryption( + thd, space, tables->table)) { + fil_space_release(space); + DBUG_RETURN(err); + } + mutex_enter(&fil_system->mutex); + space->n_pending_ops--; } - - mem_heap_empty(heap); - - /* Get the next record */ - mutex_enter(&dict_sys->mutex); - mtr_start(&mtr); - rec = dict_getnext_system(&pcur, &mtr); - } - - mtr_commit(&mtr); - mutex_exit(&dict_sys->mutex); - mem_heap_free(heap); - - if (found_space_0 == false) { - /* space 0 does for what ever unknown reason not show up - * in iteration above, add it manually */ - - fil_space_t* space = fil_space_acquire_silent(0); - - i_s_dict_fill_tablespaces_encryption( - thd, space, tables->table); - - fil_space_release(space); } + mutex_exit(&fil_system->mutex); DBUG_RETURN(0); } /*******************************************************************//** @@ -8938,12 +8888,6 @@ i_s_tablespaces_scrubbing_fill_table( TABLE_LIST* tables, /*!< in/out: tables to fill */ Item* ) /*!< in: condition (not used) */ { - btr_pcur_t pcur; - const rec_t* rec; - mem_heap_t* heap; - mtr_t mtr; - bool found_space_0 = false; - DBUG_ENTER("i_s_tablespaces_scrubbing_fill_table"); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); @@ -8952,67 +8896,24 @@ i_s_tablespaces_scrubbing_fill_table( DBUG_RETURN(0); } - heap = mem_heap_create(1000); - mutex_enter(&dict_sys->mutex); - mtr_start(&mtr); - - rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES); - - while (rec) { - const char* err_msg; - ulint space_id; - const char* name; - ulint flags; - - /* Extract necessary information from a SYS_TABLESPACES row */ - err_msg = dict_process_sys_tablespaces( - heap, rec, &space_id, &name, &flags); - - mtr_commit(&mtr); - mutex_exit(&dict_sys->mutex); - - if (space_id == 0) { - found_space_0 = true; - } - - fil_space_t* space = fil_space_acquire_silent(space_id); - - if (!err_msg && space) { - i_s_dict_fill_tablespaces_scrubbing( - thd, space, tables->table); - } else { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_CANT_FIND_SYSTEM_REC, "%s", - err_msg); - } - - if (space) { - fil_space_release(space); + mutex_enter(&fil_system->mutex); + + for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system->space_list); + space; space = UT_LIST_GET_NEXT(space_list, space)) { + if (space->purpose == FIL_TYPE_TABLESPACE) { + space->n_pending_ops++; + mutex_exit(&fil_system->mutex); + if (int err = i_s_dict_fill_tablespaces_scrubbing( + thd, space, tables->table)) { + fil_space_release(space); + DBUG_RETURN(err); + } + mutex_enter(&fil_system->mutex); + space->n_pending_ops--; } - - mem_heap_empty(heap); - - /* Get the next record */ - mutex_enter(&dict_sys->mutex); - mtr_start(&mtr); - rec = dict_getnext_system(&pcur, &mtr); - } - - mtr_commit(&mtr); - mutex_exit(&dict_sys->mutex); - mem_heap_free(heap); - - if (found_space_0 == false) { - /* space 0 does for what ever unknown reason not show up - * in iteration above, add it manually */ - fil_space_t* space = fil_space_acquire_silent(0); - - i_s_dict_fill_tablespaces_scrubbing( - thd, space, tables->table); - - fil_space_release(space); } + mutex_exit(&fil_system->mutex); DBUG_RETURN(0); } /*******************************************************************//** diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index ef6f8b39abb..ec8e29d458c 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2017, MariaDB Corporation. +Copyright (c) 2015, 2018, MariaDB Corporation. 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 @@ -43,7 +43,6 @@ enum dberr_t { DB_DEADLOCK, DB_ROLLBACK, DB_DUPLICATE_KEY, - DB_QUE_THR_SUSPENDED, DB_MISSING_HISTORY, /*!< required history data has been deleted due to lack of space in rollback segment */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index a3fac6d4096..cc2a6c1b447 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1404,90 +1404,6 @@ fil_delete_file( /*============*/ const char* path); /*!< in: filepath of the ibd tablespace */ -/** Callback functor. */ -struct PageCallback { - - /** Default constructor */ - PageCallback() - : - m_page_size(0, 0, false), - m_filepath() UNIV_NOTHROW {} - - virtual ~PageCallback() UNIV_NOTHROW {} - - /** Called for page 0 in the tablespace file at the start. - @param file_size size of the file in bytes - @param block contents of the first page in the tablespace file - @retval DB_SUCCESS or error code. */ - virtual dberr_t init( - os_offset_t file_size, - const buf_block_t* block) UNIV_NOTHROW = 0; - - /** Called for every page in the tablespace. If the page was not - updated then its state must be set to BUF_PAGE_NOT_USED. For - compressed tables the page descriptor memory will be at offset: - block->frame + UNIV_PAGE_SIZE; - @param offset physical offset within the file - @param block block read from file, note it is not from the buffer pool - @retval DB_SUCCESS or error code. */ - virtual dberr_t operator()( - os_offset_t offset, - buf_block_t* block) UNIV_NOTHROW = 0; - - /** Set the name of the physical file and the file handle that is used - to open it for the file that is being iterated over. - @param filename the name of the tablespace file - @param file OS file handle */ - void set_file(const char* filename, pfs_os_file_t file) UNIV_NOTHROW - { - m_file = file; - m_filepath = filename; - } - - /** - @return the space id of the tablespace */ - virtual ulint get_space_id() const UNIV_NOTHROW = 0; - - /** - @retval the space flags of the tablespace being iterated over */ - virtual ulint get_space_flags() const UNIV_NOTHROW = 0; - - /** The compressed page size - @return the compressed page size */ - const page_size_t& get_page_size() const - { - return(m_page_size); - } - - /** The tablespace page size. */ - page_size_t m_page_size; - - /** File handle to the tablespace */ - pfs_os_file_t m_file; - - /** Physical file path. */ - const char* m_filepath; - -protected: - // Disable copying - PageCallback(const PageCallback&); - PageCallback& operator=(const PageCallback&); -}; - -/********************************************************************//** -Iterate over all the pages in the tablespace. -@param table the table definiton in the server -@param n_io_buffers number of blocks to read and write together -@param callback functor that will do the page updates -@return DB_SUCCESS or error code */ -dberr_t -fil_tablespace_iterate( -/*===================*/ - dict_table_t* table, - ulint n_io_buffers, - PageCallback& callback) - MY_ATTRIBUTE((warn_unused_result)); - /********************************************************************//** Looks for a pre-existing fil_space_t with the given tablespace ID and, if found, returns the name and filepath in newly allocated buffers that the caller must free. diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 5b97b4b3a88..86defe9b166 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. 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 @@ -361,27 +361,6 @@ thd_trx_is_read_only( /*=================*/ THD* thd); /*!< in/out: thread handle */ -#if 0 -/** -Check if the transaction can be rolled back -@param[in] requestor Session requesting the lock -@param[in] holder Session that holds the lock -@return the session that will be rolled back, null don't care */ - -THD* -thd_trx_arbitrate(THD* requestor, THD* holder); - -/** -@param[in] thd Session to check -@return the priority */ - -int -thd_trx_priority(THD* thd); - -#else -static inline THD* thd_trx_arbitrate(THD*, THD*) { return NULL; } -static inline int thd_trx_priority(THD*) { return 0; } -#endif /******************************************************************//** Check if the transaction is an auto-commit transaction. TRUE also implies that it is a SELECT (read-only) transaction. diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 3d099cd2f3a..cbb6da488b5 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -122,7 +123,6 @@ do {\ }\ } while (0) -#ifdef WITH_WSREP /*******************************************************************//** Inserts a struct to the head of hash table. */ @@ -148,7 +148,6 @@ do { \ cell3333->node = DATA; \ } \ } while (0) -#endif /*WITH_WSREP */ #ifdef UNIV_HASH_DEBUG # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 diff --git a/storage/innobase/include/ib0mutex.h b/storage/innobase/include/ib0mutex.h index 20703a4a933..d75893ec4d4 100644 --- a/storage/innobase/include/ib0mutex.h +++ b/storage/innobase/include/ib0mutex.h @@ -527,7 +527,9 @@ struct TTASEventMutex { int32 state() const UNIV_NOTHROW { - return(m_lock_word); + return(my_atomic_load32_explicit(const_cast<int32*> + (&m_lock_word), + MY_MEMORY_ORDER_RELAXED)); } /** The event that the mutex will wait in sync0arr.cc diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 462d0cd4051..2159f56d018 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -268,7 +268,7 @@ a record. If they do, first tests if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a gap x-lock to the lock queue. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_rec_insert_check_and_lock( /*===========================*/ @@ -292,7 +292,7 @@ first tests if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record x-lock to the lock queue. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_modify_check_and_lock( /*=================================*/ @@ -308,7 +308,7 @@ lock_clust_rec_modify_check_and_lock( /*********************************************************************//** Checks if locks of other transactions prevent an immediate modify (delete mark or delete unmark) of a secondary index record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_sec_rec_modify_check_and_lock( /*===============================*/ @@ -328,8 +328,7 @@ lock_sec_rec_modify_check_and_lock( /*********************************************************************//** Like lock_clust_rec_read_check_and_lock(), but reads a secondary index record. -@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, -or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_sec_rec_read_check_and_lock( /*=============================*/ @@ -357,8 +356,7 @@ if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. -@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, -or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_read_check_and_lock( /*===============================*/ @@ -388,7 +386,7 @@ waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. This is an alternative version of lock_clust_rec_read_check_and_lock() that does not require the parameter "offsets". -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_read_check_and_lock_alt( /*===================================*/ @@ -443,7 +441,7 @@ lock_sec_rec_cons_read_sees( /*********************************************************************//** Locks the specified database table in the mode given. If the lock cannot be granted immediately, the query thread is put to wait. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_table( /*=======*/ @@ -752,9 +750,7 @@ the wait lock. dberr_t lock_trx_handle_wait( /*=================*/ - trx_t* trx, /*!< in/out: trx lock state */ - bool lock_mutex_taken, - bool trx_mutex_taken); + trx_t* trx); /*!< in/out: trx lock state */ /*********************************************************************//** Get the number of locks on a table. @return number of locks */ @@ -956,6 +952,30 @@ public: void close(); }; +/*********************************************************************//** +Creates a new record lock and inserts it to the lock queue. Does NOT check +for deadlocks or lock compatibility! +@return created lock */ +UNIV_INLINE +lock_t* +lock_rec_create( +/*============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< conflicting lock */ + que_thr_t* thr, /*!< thread owning trx */ +#endif + ulint type_mode,/*!< in: lock mode and wait + flag, type is ignored and + replaced by LOCK_REC */ + const buf_block_t* block, /*!< in: buffer block containing + the record */ + ulint heap_no,/*!< in: heap number of the record */ + dict_index_t* index, /*!< in: index of record */ + trx_t* trx, /*!< in,out: transaction */ + bool caller_owns_trx_mutex); + /*!< in: true if caller owns + trx mutex */ + /*************************************************************//** Removes a record lock request, waiting or granted, from the queue. */ void @@ -965,6 +985,61 @@ lock_rec_discard( record locks which are contained in this lock object are removed */ +/** Create a new record lock and inserts it to the lock queue, +without checking for deadlocks or conflicts. +@param[in] type_mode lock mode and wait flag; type will be replaced + with LOCK_REC +@param[in] space tablespace id +@param[in] page_no index page number +@param[in] page R-tree index page, or NULL +@param[in] heap_no record heap number in the index page +@param[in] index the index tree +@param[in,out] trx transaction +@param[in] holds_trx_mutex whether the caller holds trx->mutex +@return created lock */ +lock_t* +lock_rec_create_low( +#ifdef WITH_WSREP + lock_t* c_lock, /*!< conflicting lock */ + que_thr_t* thr, /*!< thread owning trx */ +#endif + ulint type_mode, + ulint space, + ulint page_no, + const page_t* page, + ulint heap_no, + dict_index_t* index, + trx_t* trx, + bool holds_trx_mutex); +/** Enqueue a waiting request for a lock which cannot be granted immediately. +Check for deadlocks. +@param[in] type_mode the requested lock mode (LOCK_S or LOCK_X) + possibly ORed with LOCK_GAP or + LOCK_REC_NOT_GAP, ORed with + LOCK_INSERT_INTENTION if this + waiting lock request is set + when performing an insert of + an index record +@param[in] block leaf page in the index +@param[in] heap_no record heap number in the block +@param[in] index index tree +@param[in,out] thr query thread +@param[in] prdt minimum bounding box (spatial index) +@retval DB_LOCK_WAIT if the waiting lock was enqueued +@retval DB_DEADLOCK if this transaction was chosen as the victim +@retval DB_SUCCESS_LOCKED_REC if the other transaction was chosen as a victim + (or it happened to commit) */ +dberr_t +lock_rec_enqueue_waiting( +#ifdef WITH_WSREP + lock_t* c_lock, /*!< conflicting lock */ +#endif + ulint type_mode, + const buf_block_t* block, + ulint heap_no, + dict_index_t* index, + que_thr_t* thr, + lock_prdt_t* prdt); /*************************************************************//** Moves the explicit locks on user records to another page if a record list start is moved to another page. */ @@ -987,16 +1062,6 @@ lock_rec_free_all_from_discard_page( /*================================*/ const buf_block_t* block); /*!< in: page to be discarded */ -/** Reset the nth bit of a record lock. -@param[in,out] lock record lock -@param[in] i index of the bit that will be reset -@param[in] type whether the lock is in wait mode */ -void -lock_rec_trx_wait( - lock_t* lock, - ulint i, - ulint type); - /** The lock system */ extern lock_sys_t lock_sys; diff --git a/storage/innobase/include/lock0lock.ic b/storage/innobase/include/lock0lock.ic index dad62c9685c..c1c886f6832 100644 --- a/storage/innobase/include/lock0lock.ic +++ b/storage/innobase/include/lock0lock.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2018, MariaDB Corporation. 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 @@ -24,18 +24,9 @@ The transaction lock system Created 5/7/1996 Heikki Tuuri *******************************************************/ -#include "srv0srv.h" #include "dict0dict.h" -#include "row0row.h" -#include "trx0sys.h" -#include "trx0trx.h" #include "buf0buf.h" #include "page0page.h" -#include "page0cur.h" -#include "row0vers.h" -#include "que0que.h" -#include "btr0cur.h" -#include "log0recv.h" /*********************************************************************//** Calculates the fold value of a page file address: used in inserting or @@ -107,3 +98,37 @@ lock_hash_get( } } +/*********************************************************************//** +Creates a new record lock and inserts it to the lock queue. Does NOT check +for deadlocks or lock compatibility! +@return created lock */ +UNIV_INLINE +lock_t* +lock_rec_create( +/*============*/ +#ifdef WITH_WSREP + lock_t* c_lock, /*!< conflicting lock */ + que_thr_t* thr, /*!< thread owning trx */ +#endif + ulint type_mode,/*!< in: lock mode and wait + flag, type is ignored and + replaced by LOCK_REC */ + const buf_block_t* block, /*!< in: buffer block containing + the record */ + ulint heap_no,/*!< in: heap number of the record */ + dict_index_t* index, /*!< in: index of record */ + trx_t* trx, /*!< in,out: transaction */ + bool caller_owns_trx_mutex) + /*!< in: TRUE if caller owns + trx mutex */ +{ + btr_assert_not_corrupted(block, index); + return lock_rec_create_low( +#ifdef WITH_WSREP + c_lock, thr, +#endif + type_mode, + block->page.id.space(), block->page.id.page_no(), + block->frame, heap_no, + index, trx, caller_owns_trx_mutex); +} diff --git a/storage/innobase/include/lock0prdt.h b/storage/innobase/include/lock0prdt.h index 878d575ddc7..e4e37776d22 100644 --- a/storage/innobase/include/lock0prdt.h +++ b/storage/innobase/include/lock0prdt.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -36,7 +37,7 @@ typedef struct lock_prdt { /*********************************************************************//** Acquire a predicate lock on a block -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_prdt_lock( /*===========*/ @@ -56,7 +57,7 @@ lock_prdt_lock( /*********************************************************************//** Acquire a "Page" lock on a block -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_place_prdt_page_lock( /*======================*/ @@ -129,7 +130,7 @@ lock_prdt_update_parent( /*********************************************************************//** Checks if locks of other transactions prevent an immediate insert of a predicate record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_prdt_insert_check_and_lock( /*============================*/ diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h index ec596f6ca5b..f5b2b51acfc 100644 --- a/storage/innobase/include/lock0priv.h +++ b/storage/innobase/include/lock0priv.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2016, MariaDB Corporation +Copyright (c) 2015, 2018, MariaDB Corporation. 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 @@ -35,9 +35,8 @@ those functions in lock/ */ #endif #include "univ.i" -#include "dict0types.h" #include "hash0hash.h" -#include "trx0types.h" +#include "trx0trx.h" #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) @@ -562,407 +561,6 @@ enum lock_rec_req_status { LOCK_REC_SUCCESS_CREATED }; -/** -Record lock ID */ -struct RecID { - - RecID(ulint space_id, ulint page_no, ulint heap_no) - : - m_space_id(static_cast<uint32_t>(space_id)), - m_page_no(static_cast<uint32_t>(page_no)), - m_heap_no(static_cast<uint32_t>(heap_no)), - m_fold(lock_rec_fold(m_space_id, m_page_no)) - { - ut_ad(space_id < UINT32_MAX); - ut_ad(page_no < UINT32_MAX); - ut_ad(heap_no < UINT32_MAX); - } - - RecID(const buf_block_t* block, ulint heap_no) - : - m_space_id(block->page.id.space()), - m_page_no(block->page.id.page_no()), - m_heap_no(static_cast<uint32_t>(heap_no)), - m_fold(lock_rec_fold(m_space_id, m_page_no)) - { - ut_ad(heap_no < UINT32_MAX); - } - - /** - @return the "folded" value of {space, page_no} */ - ulint fold() const - { - return(m_fold); - } - - /** - Tablespace ID */ - uint32_t m_space_id; - - /** - Page number within the space ID */ - uint32_t m_page_no; - - /** - Heap number within the page */ - uint32_t m_heap_no; - - /** - Hashed key value */ - ulint m_fold; -}; - -/** -Create record locks */ -class RecLock { -public: - - /** - @param[in,out] thr Transaction query thread requesting the record - lock - @param[in] index Index on which record lock requested - @param[in] rec_id Record lock tuple {space, page_no, heap_no} - @param[in] mode The lock mode */ - RecLock(que_thr_t* thr, - dict_index_t* index, - const RecID& rec_id, - ulint mode) - : - m_thr(thr), - m_trx(thr_get_trx(thr)), - m_mode(mode), - m_index(index), - m_rec_id(rec_id) - { - ut_ad(is_predicate_lock(m_mode)); - - init(NULL); - } - - /** - @param[in,out] thr Transaction query thread requesting the record - lock - @param[in] index Index on which record lock requested - @param[in] block Buffer page containing record - @param[in] heap_no Heap number within the block - @param[in] mode The lock mode - @param[in] prdt The predicate for the rtree lock */ - RecLock(que_thr_t* thr, - dict_index_t* index, - const buf_block_t* - block, - ulint heap_no, - ulint mode, - lock_prdt_t* prdt = NULL) - : - m_thr(thr), - m_trx(thr_get_trx(thr)), - m_mode(mode), - m_index(index), - m_rec_id(block, heap_no) - { - btr_assert_not_corrupted(block, index); - - init(block->frame); - } - - /** - @param[in] index Index on which record lock requested - @param[in] rec_id Record lock tuple {space, page_no, heap_no} - @param[in] mode The lock mode */ - RecLock(dict_index_t* index, - const RecID& rec_id, - ulint mode) - : - m_thr(), - m_trx(), - m_mode(mode), - m_index(index), - m_rec_id(rec_id) - { - ut_ad(is_predicate_lock(m_mode)); - - init(NULL); - } - - /** - @param[in] index Index on which record lock requested - @param[in] block Buffer page containing record - @param[in] heap_no Heap number withing block - @param[in] mode The lock mode */ - RecLock(dict_index_t* index, - const buf_block_t* - block, - ulint heap_no, - ulint mode) - : - m_thr(), - m_trx(), - m_mode(mode), - m_index(index), - m_rec_id(block, heap_no) - { - btr_assert_not_corrupted(block, index); - - init(block->frame); - } - - /** - Enqueue a lock wait for a transaction. If it is a high priority - transaction (cannot rollback) then jump ahead in the record lock wait - queue and if the transaction at the head of the queue is itself waiting - roll it back. - @param[in, out] wait_for The lock that the the joining - transaction is waiting for - @param[in] prdt Predicate [optional] - @return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or - DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that - there was a deadlock, but another transaction was chosen - as a victim, and we got the lock immediately: no need to - wait then */ - dberr_t add_to_waitq( - lock_t* wait_for, - const lock_prdt_t* - prdt = NULL); - - /** - Create a lock for a transaction and initialise it. - @param[in, out] trx Transaction requesting the new lock - @param[in] owns_trx_mutex true if caller owns the trx_t::mutex - @param[in] add_to_hash add the lock to hash table - @param[in] prdt Predicate lock (optional) - @param[in,out] c_lock Conflicting lock request or NULL - in Galera conflicting lock is selected - as deadlock victim if requester - is BF transaction. - @return new lock instance */ - lock_t* create( - trx_t* trx, - bool owns_trx_mutex, - bool add_to_hash, - const lock_prdt_t* - prdt = NULL -#ifdef WITH_WSREP - ,lock_t* c_lock = NULL -#endif /* WITH_WSREP */ - ) const; - - /** - Check of the lock is on m_rec_id. - @param[in] lock Lock to compare with - @return true if the record lock is on m_rec_id*/ - bool is_on_row(const lock_t* lock) const; - - /** - Create the lock instance - @param[in, out] trx The transaction requesting the lock - @param[in, out] index Index on which record lock is required - @param[in] mode The lock mode desired - @param[in] rec_id The record id - @param[in] size Size of the lock + bitmap requested - @return a record lock instance */ - static lock_t* lock_alloc( - trx_t* trx, - dict_index_t* index, - ulint mode, - const RecID& rec_id, - ulint size); - -private: - /* - @return the record lock size in bytes */ - size_t lock_size() const - { - return(m_size); - } - - /** - Do some checks and prepare for creating a new record lock */ - void prepare() const; - - /** - Collect the transactions that will need to be rolled back asynchronously - @param[in, out] trx Transaction to be rolled back */ - void mark_trx_for_rollback(trx_t* trx); - - /** - Jump the queue for the record over all low priority transactions and - add the lock. If all current granted locks are compatible, grant the - lock. Otherwise, mark all granted transaction for asynchronous - rollback and add to hit list. - @param[in, out] lock Lock being requested - @param[in] conflict_lock First conflicting lock from the head - @return true if the lock is granted */ - bool jump_queue(lock_t* lock, const lock_t* conflict_lock); - - /** Find position in lock queue and add the high priority transaction - lock. Intention and GAP only locks can be granted even if there are - waiting locks in front of the queue. To add the High priority - transaction in a safe position we keep the following rule. - - 1. If the lock can be granted, add it before the first waiting lock - in the queue so that all currently waiting locks need to do conflict - check before getting granted. - - 2. If the lock has to wait, add it after the last granted lock or the - last waiting high priority transaction in the queue whichever is later. - This ensures that the transaction is granted only after doing conflict - check with all granted transactions. - @param[in] lock Lock being requested - @param[in] conflict_lock First conflicting lock from the head - @param[out] high_priority high priority transaction ahead in queue - @return true if the lock can be granted */ - bool - lock_add_priority( - lock_t* lock, - const lock_t* conflict_lock, - bool* high_priority); - - /** Iterate over the granted locks and prepare the hit list for ASYNC Rollback. - If the transaction is waiting for some other lock then wake up with deadlock error. - Currently we don't mark following transactions for ASYNC Rollback. - 1. Read only transactions - 2. Background transactions - 3. Other High priority transactions - @param[in] lock Lock being requested - @param[in] conflict_lock First conflicting lock from the head */ - void make_trx_hit_list(lock_t* lock, const lock_t* conflict_lock); - - /** - Setup the requesting transaction state for lock grant - @param[in,out] lock Lock for which to change state */ - void set_wait_state(lock_t* lock); - - /** - Add the lock to the record lock hash and the transaction's lock list - @param[in,out] lock Newly created record lock to add to the - rec hash and the transaction lock list - @param[in] add_to_hash If the lock should be added to the hash table */ - void lock_add(lock_t* lock, bool add_to_hash) const; - - /** - Check and resolve any deadlocks - @param[in, out] lock The lock being acquired - @return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or - DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that - there was a deadlock, but another transaction was chosen - as a victim, and we got the lock immediately: no need to - wait then */ - dberr_t deadlock_check(lock_t* lock); - - /** - Check the outcome of the deadlock check - @param[in,out] victim_trx Transaction selected for rollback - @param[in,out] lock Lock being requested - @return DB_LOCK_WAIT, DB_DEADLOCK or DB_SUCCESS_LOCKED_REC */ - dberr_t check_deadlock_result(const trx_t* victim_trx, lock_t* lock); - - /** - Setup the context from the requirements */ - void init(const page_t* page) - { - ut_ad(lock_mutex_own()); - ut_ad(!srv_read_only_mode); - ut_ad(dict_index_is_clust(m_index) - || !dict_index_is_online_ddl(m_index)); - ut_ad(m_thr == NULL || m_trx == thr_get_trx(m_thr)); - - m_size = is_predicate_lock(m_mode) - ? lock_size(m_mode) : lock_size(page); - - /** If rec is the supremum record, then we reset the - gap and LOCK_REC_NOT_GAP bits, as all locks on the - supremum are automatically of the gap type */ - - if (m_rec_id.m_heap_no == PAGE_HEAP_NO_SUPREMUM) { - ut_ad(!(m_mode & LOCK_REC_NOT_GAP)); - - m_mode &= ~(LOCK_GAP | LOCK_REC_NOT_GAP); - } - } - - /** - Calculate the record lock physical size required for a predicate lock. - @param[in] mode For predicate locks the lock mode - @return the size of the lock data structure required in bytes */ - static size_t lock_size(ulint mode) - { - ut_ad(is_predicate_lock(mode)); - - /* The lock is always on PAGE_HEAP_NO_INFIMUM(0), - so we only need 1 bit (which is rounded up to 1 - byte) for lock bit setting */ - - size_t n_bytes; - - if (mode & LOCK_PREDICATE) { - const ulint align = UNIV_WORD_SIZE - 1; - - /* We will attach the predicate structure - after lock. Make sure the memory is - aligned on 8 bytes, the mem_heap_alloc - will align it with MEM_SPACE_NEEDED - anyway. */ - - n_bytes = (1 + sizeof(lock_prdt_t) + align) & ~align; - - /* This should hold now */ - - ut_ad(n_bytes == sizeof(lock_prdt_t) + UNIV_WORD_SIZE); - - } else { - n_bytes = 1; - } - - return(n_bytes); - } - - /** - Calculate the record lock physical size required, non-predicate lock. - @param[in] page For non-predicate locks the buffer page - @return the size of the lock data structure required in bytes */ - static size_t lock_size(const page_t* page) - { - ulint n_recs = page_dir_get_n_heap(page); - - /* Make lock bitmap bigger by a safety margin */ - - return(1 + ((n_recs + LOCK_PAGE_BITMAP_MARGIN) / 8)); - } - - /** - @return true if the requested lock mode is for a predicate - or page lock */ - static bool is_predicate_lock(ulint mode) - { - return(mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE)); - } - -private: - /** The query thread of the transaction */ - que_thr_t* m_thr; - - /** - Transaction requesting the record lock */ - trx_t* m_trx; - - /** - Lock mode requested */ - ulint m_mode; - - /** - Size of the record lock in bytes */ - size_t m_size; - - /** - Index on which the record lock is required */ - dict_index_t* m_index; - - /** - The record lock tuple {space, page_no, heap_no} */ - RecID m_rec_id; -}; - #ifdef UNIV_DEBUG /** The count of the types of locks. */ static const ulint lock_types = UT_ARR_SIZE(lock_compatibility_matrix); @@ -1044,6 +642,28 @@ lock_rec_set_nth_bit( lock_t* lock, /*!< in: record lock */ ulint i); /*!< in: index of the bit */ +/** Reset the nth bit of a record lock. +@param[in,out] lock record lock +@param[in] i index of the bit that will be reset +@return previous value of the bit */ +inline byte lock_rec_reset_nth_bit(lock_t* lock, ulint i) +{ + ut_ad(lock_get_type_low(lock) == LOCK_REC); + ut_ad(i < lock->un_member.rec_lock.n_bits); + + byte* b = reinterpret_cast<byte*>(&lock[1]) + (i >> 3); + byte mask = byte(1U << (i & 7)); + byte bit = *b & mask; + *b &= ~mask; + + if (bit != 0) { + ut_ad(lock->trx->lock.n_rec_locks > 0); + --lock->trx->lock.n_rec_locks; + } + + return(bit); +} + /*********************************************************************//** Gets the first or next record lock on a page. @return next lock, NULL if none exists */ @@ -1171,6 +791,33 @@ lock_table_has( const dict_table_t* table, /*!< in: table */ enum lock_mode mode); /*!< in: lock mode */ +/** Set the wait status of a lock. +@param[in,out] lock lock that will be waited for +@param[in,out] trx transaction that will wait for the lock */ +inline void lock_set_lock_and_trx_wait(lock_t* lock, trx_t* trx) +{ + ut_ad(lock); + ut_ad(lock->trx == trx); + ut_ad(trx->lock.wait_lock == NULL); + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(trx)); + + trx->lock.wait_lock = lock; + lock->type_mode |= LOCK_WAIT; +} + +/** Reset the wait status of a lock. +@param[in,out] lock lock that was possibly being waited for */ +inline void lock_reset_lock_and_trx_wait(lock_t* lock) +{ + ut_ad(lock_get_wait(lock)); + ut_ad(lock_mutex_own()); + ut_ad(lock->trx->lock.wait_lock == NULL + || lock->trx->lock.wait_lock == lock); + lock->trx->lock.wait_lock = NULL; + lock->type_mode &= ~LOCK_WAIT; +} + #include "lock0priv.ic" #endif /* lock0priv_h */ diff --git a/storage/innobase/include/lock0priv.ic b/storage/innobase/include/lock0priv.ic index f6e5f7acb8f..150a80b7be4 100644 --- a/storage/innobase/include/lock0priv.ic +++ b/storage/innobase/include/lock0priv.ic @@ -32,6 +32,8 @@ methods but they are used only in that file. */ #error Do not include lock0priv.ic outside of the lock/ module #endif +#include "row0row.h" + /*********************************************************************//** Gets the type of a lock. @return LOCK_TABLE or LOCK_REC */ diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index 8bab2408605..50a8d741806 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -122,6 +122,41 @@ recv_sys_var_init(void); void recv_apply_hashed_log_recs(bool last_batch); +/** Whether to store redo log records to the hash table */ +enum store_t { + /** Do not store redo log records. */ + STORE_NO, + /** Store redo log records. */ + STORE_YES, + /** Store redo log records if the tablespace exists. */ + STORE_IF_EXISTS +}; + + +/** Adds data from a new log block to the parsing buffer of recv_sys if +recv_sys->parse_start_lsn is non-zero. +@param[in] log_block log block to add +@param[in] scanned_lsn lsn of how far we were able to find + data in this log block +@return true if more data added */ +bool recv_sys_add_to_parsing_buf(const byte* log_block, lsn_t scanned_lsn); + +/** Parse log records from a buffer and optionally store them to a +hash table to wait merging to file pages. +@param[in] checkpoint_lsn the LSN of the latest checkpoint +@param[in] store whether to store page operations +@param[in] apply whether to apply the records +@return whether MLOG_CHECKPOINT record was seen the first time, +or corruption was noticed */ +bool recv_parse_log_recs(lsn_t checkpoint_lsn, store_t store, bool apply); + +/** Moves the parsing buffer data left to the buffer start. */ +void recv_sys_justify_left_parsing_buf(); + +/** Backup function checks whether the space id belongs to +the skip table list given in the mariabackup option. */ +extern bool(*check_if_backup_includes)(ulint space_id); + /** Block of log record data */ struct recv_data_t{ recv_data_t* next; /*!< pointer to the next block or NULL */ @@ -257,6 +292,9 @@ struct recv_sys_t{ recv_dblwr_t dblwr; + /** Lastly added LSN to the hash table of log records. */ + lsn_t last_stored_lsn; + /** Determine whether redo log recovery progress should be reported. @param[in] time the current time @return whether progress should be reported diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic index 6cb67af94ca..a7e4f2695da 100644 --- a/storage/innobase/include/os0file.ic +++ b/storage/innobase/include/os0file.ic @@ -372,9 +372,9 @@ pfs_os_file_read_no_error_handling_int_fd_func( locker, n, __FILE__, __LINE__); } - ulint fulfilled; + bool success = DB_SUCCESS == os_file_read_no_error_handling_func( - type, OS_FILE_FROM_FD(file), buf, offset, n, &fulfilled); + type, OS_FILE_FROM_FD(file), buf, offset, n, NULL); if (locker != NULL) { PSI_FILE_CALL(end_file_wait)(locker, n); diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index be29b184387..d16d7c94a8b 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -459,7 +459,7 @@ extern uint srv_fast_shutdown; /*!< If this is 1, do not do a /** Signal to shut down InnoDB (NULL if shutdown was signaled, or if running in innodb_read_only mode, srv_read_only_mode) */ -extern volatile st_my_thread_var *srv_running; +extern st_my_thread_var *srv_running; extern ibool srv_innodb_status; diff --git a/storage/innobase/include/trx0rseg.ic b/storage/innobase/include/trx0rseg.ic index dd0ce8b3719..f344f23a9dc 100644 --- a/storage/innobase/include/trx0rseg.ic +++ b/storage/innobase/include/trx0rseg.ic @@ -42,9 +42,11 @@ trx_rsegf_get( buf_block_t* block; trx_rsegf_t* header; - ut_ad(space <= srv_undo_tablespaces_active || space == SRV_TMP_SPACE_ID + ut_ad(space <= srv_undo_space_id_start + srv_undo_tablespaces_active + || space == SRV_TMP_SPACE_ID || !srv_was_started); - ut_ad(space <= TRX_SYS_MAX_UNDO_SPACES || space == SRV_TMP_SPACE_ID); + ut_ad(space <= srv_undo_space_id_start + TRX_SYS_MAX_UNDO_SPACES + || space == SRV_TMP_SPACE_ID); block = buf_page_get( page_id_t(space, page_no), univ_page_size, RW_X_LATCH, mtr); diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 5e3a1dd4a7e..7dbe2d3d486 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -28,13 +28,11 @@ Created 3/26/1996 Heikki Tuuri #define trx0trx_h #include <set> -#include <list> #include "ha_prototypes.h" #include "dict0types.h" #include "trx0types.h" -#include "ut0new.h" #include "lock0types.h" #include "log0log.h" @@ -43,7 +41,6 @@ Created 3/26/1996 Heikki Tuuri #include "trx0xa.h" #include "ut0vec.h" #include "fts0fts.h" -#include "srv0srv.h" #include "read0types.h" // Forward declaration @@ -244,14 +241,9 @@ dberr_t trx_commit_for_mysql( /*=================*/ trx_t* trx); /*!< in/out: transaction */ - -/** -Does the transaction prepare for MySQL. -@param[in, out] trx Transaction instance to prepare */ - -dberr_t -trx_prepare_for_mysql(trx_t* trx); - +/** XA PREPARE a transaction. +@param[in,out] trx transaction to prepare */ +void trx_prepare_for_mysql(trx_t* trx); /**********************************************************************//** This function is used to find number of prepared transactions and their transaction objects for a recovery. @@ -475,29 +467,6 @@ trx_set_rw_mode( trx_t* trx); /** -@param[in] requestor Transaction requesting the lock -@param[in] holder Transaction holding the lock -@return the transaction that will be rolled back, null don't care */ - -UNIV_INLINE -const trx_t* -trx_arbitrate(const trx_t* requestor, const trx_t* holder); - -/** -@param[in] trx Transaction to check -@return true if the transaction is a high priority transaction.*/ -UNIV_INLINE -bool -trx_is_high_priority(const trx_t* trx); - -/** -Kill all transactions that are blocking this transaction from acquiring locks. -@param[in,out] trx High priority transaction */ - -void -trx_kill_blocking(trx_t* trx); - -/** Transactions that aren't started by the MySQL server don't set the trx_t::mysql_thd field. For such transactions we set the lock wait timeout to 0 instead of the user configured value that comes @@ -536,7 +505,6 @@ Check transaction state */ case TRX_STATE_COMMITTED_IN_MEMORY: \ continue; \ case TRX_STATE_NOT_STARTED: \ - case TRX_STATE_FORCED_ROLLBACK: \ break; \ } \ ut_error; \ @@ -545,8 +513,7 @@ Check transaction state */ /** Check if transaction is free so that it can be re-initialized. @param t transaction handle */ #define assert_trx_is_free(t) do { \ - ut_ad(trx_state_eq((t), TRX_STATE_NOT_STARTED) \ - || trx_state_eq((t), TRX_STATE_FORCED_ROLLBACK)); \ + ut_ad(trx_state_eq((t), TRX_STATE_NOT_STARTED)); \ ut_ad(!trx->has_logged()); \ ut_ad(!(t)->read_view.is_open()); \ ut_ad((t)->lock.wait_thr == NULL); \ @@ -575,7 +542,6 @@ The tranasction must be in the mysql_trx_list. */ ut_ad(!(t)->is_recovered); \ ut_ad((t)->in_mysql_trx_list); \ ut_ad(t_state == TRX_STATE_NOT_STARTED \ - || t_state == TRX_STATE_FORCED_ROLLBACK \ || t_state == TRX_STATE_ACTIVE); \ } else { \ check_trx_state(t); \ @@ -682,10 +648,6 @@ struct trx_lock_t { Protected by both the lock sys mutex and the trx_t::mutex. */ ulint n_rec_locks; /*!< number of rec locks in this trx */ - - /** The transaction called ha_innobase::start_stmt() to - lock a table. Most likely a temporary table. */ - bool start_stmt; }; /** Logical first modification time of a table in a transaction */ @@ -799,11 +761,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated to other connections. The locks of transactions are protected by lock_sys.mutex and sometimes by trx->mutex. */ -typedef enum { - TRX_SERVER_ABORT = 0, - TRX_WSREP_ABORT = 1 -} trx_abort_t; - /** Represents an instance of rollback segment along with its state variables.*/ struct trx_undo_ptr_t { trx_rseg_t* rseg; /*!< rollback segment assigned to the @@ -837,22 +794,6 @@ struct trx_rsegs_t { trx_temp_undo_t m_noredo; }; -struct TrxVersion { - TrxVersion(trx_t* trx); - - /** - @return true if the trx_t instance is the same */ - bool operator==(const TrxVersion& rhs) const - { - return(rhs.m_trx == m_trx); - } - - trx_t* m_trx; - ulint m_version; -}; - -typedef std::list<TrxVersion, ut_allocator<TrxVersion> > hit_list_t; - struct trx_t { private: /** @@ -872,25 +813,6 @@ public: of lock, which are protected by lock_sys.mutex) */ - /* Note: in_depth was split from in_innodb for fixing a RO - performance issue. Acquiring the trx_t::mutex for each row - costs ~3% in performance. It is not required for correctness. - Therefore we increment/decrement in_depth without holding any - mutex. The assumption is that the Server will only ever call - the handler from one thread. This is not true for kill_connection. - Therefore in innobase_kill_connection. We don't increment this - counter via TrxInInnoDB. */ - - ib_uint32_t in_depth; /*!< Track nested TrxInInnoDB - count */ - - ib_uint32_t in_innodb; /*!< if the thread is executing - in the InnoDB context count > 0. */ - - bool abort; /*!< if this flag is set then - this transaction must abort when - it can */ - trx_id_t id; /*!< transaction id */ trx_id_t no; /*!< transaction serialization number: @@ -907,7 +829,6 @@ public: Possible states: TRX_STATE_NOT_STARTED - TRX_STATE_FORCED_ROLLBACK TRX_STATE_ACTIVE TRX_STATE_PREPARED TRX_STATE_COMMITTED_IN_MEMORY (alias below COMMITTED) @@ -981,22 +902,6 @@ public: protected by trx_sys.mutex when trx is in rw_trx_hash */ - hit_list_t hit_list; /*!< List of transactions to kill, - when a high priority transaction - is blocked on a lock wait. */ - - os_thread_id_t killed_by; /*!< The thread ID that wants to - kill this transaction asynchronously. - This is required because we recursively - enter the handlerton methods and need - to distinguish between the kill thread - and the transaction thread. - - Note: We need to be careful w.r.t the - Thread Pool. The thread doing the kill - should not leave InnoDB between the - mark and the actual async kill because - the running thread can change. */ /* These fields are not protected by any mutex. */ const char* op_info; /*!< English text describing the @@ -1068,7 +973,6 @@ public: /*------------------------------*/ THD* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ - trx_abort_t abort_type; /*!< Transaction abort type*/ const char* mysql_log_file_name; /*!< if MySQL binlog is used, this field @@ -1193,12 +1097,6 @@ public: const char* start_file; /*!< Filename where it was started */ #endif /* UNIV_DEBUG */ - /** Version of this instance. It is incremented each time the - instance is re-used in trx_start_low(). It is used to track - whether a transaction has been restarted since it was tagged - for asynchronous rollback. */ - ulint version; - XID* xid; /*!< X/Open XA transaction identification to identify a transaction branch */ @@ -1298,13 +1196,9 @@ private: Check if transaction is started. @param[in] trx Transaction whose state we need to check @reutrn true if transaction is in state started */ -inline -bool -trx_is_started( - const trx_t* trx) +inline bool trx_is_started(const trx_t* trx) { - return(trx->state != TRX_STATE_NOT_STARTED - && trx->state != TRX_STATE_FORCED_ROLLBACK); + return trx->state != TRX_STATE_NOT_STARTED; } /* Transaction isolation levels (trx->isolation_level) */ @@ -1377,224 +1271,6 @@ struct commit_node_t{ mutex_exit(&t->mutex); \ } while (0) -/** Track if a transaction is executing inside InnoDB code. It acts -like a gate between the Server and InnoDB. */ -class TrxInInnoDB { -public: - /** - @param[in,out] trx Transaction entering InnoDB via the handler - @param[in] disable true if called from COMMIT/ROLLBACK method */ - TrxInInnoDB(trx_t* trx, bool disable = false) - : - m_trx(trx) - { - enter(trx, disable); - } - - /** - Destructor */ - ~TrxInInnoDB() - { - exit(m_trx); - } - - /** - @return true if the transaction has been marked for asynchronous - rollback */ - bool is_aborted() const - { - return(is_aborted(m_trx)); - } - - /** - @return true if the transaction can't be rolled back asynchronously */ - bool is_rollback_disabled() const - { - return((m_trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE) > 0); - } - - /** - @return true if the transaction has been marked for asynchronous - rollback */ - static bool is_aborted(const trx_t* trx) - { - if (trx->state == TRX_STATE_NOT_STARTED) { - return(false); - } - - ut_ad(srv_read_only_mode || trx->in_depth > 0); - ut_ad(srv_read_only_mode || trx->in_innodb > 0); - - return(trx->abort - || trx->state == TRX_STATE_FORCED_ROLLBACK); - } - - /** - Start statement requested for transaction. - @param[in, out] trx Transaction at the start of a SQL statement */ - static void begin_stmt(trx_t* trx) - { - enter(trx, false); - } - - /** - Note an end statement for transaction - @param[in, out] trx Transaction at end of a SQL statement */ - static void end_stmt(trx_t* trx) - { - exit(trx); - } - - /** - @return true if the rollback is being initiated by the thread that - marked the transaction for asynchronous rollback */ - static bool is_async_rollback(const trx_t* trx) - { - return(trx->killed_by == os_thread_get_curr_id()); - } - -private: - /** - Note that we have crossed into InnoDB code. - @param[in] disable true if called from COMMIT/ROLLBACK method */ - static void enter(trx_t* trx, bool disable) - { - if (srv_read_only_mode) { - - return; - } - - ut_ad(!is_async_rollback(trx)); - - /* If it hasn't already been marked for async rollback. - and it will be committed/rolled back. */ - if (disable) { - - trx_mutex_enter(trx); - if (!is_forced_rollback(trx) - && is_started(trx) - && !trx_is_autocommit_non_locking(trx)) { - - ut_ad(trx->killed_by == 0); - - /* This transaction has crossed the point of - no return and cannot be rolled back - asynchronously now. It must commit or rollback - synhronously. */ - - trx->in_innodb |= TRX_FORCE_ROLLBACK_DISABLE; - } - trx_mutex_exit(trx); - } - - /* Avoid excessive mutex acquire/release */ - ++trx->in_depth; - - /* If trx->in_depth is greater than 1 then - transaction is already in InnoDB. */ - if (trx->in_depth > 1) { - - return; - } - - trx_mutex_enter(trx); - - wait(trx); - - ut_ad((trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) == 0); - - ++trx->in_innodb; - - trx_mutex_exit(trx); - } - - /** - Note that we are exiting InnoDB code */ - static void exit(trx_t* trx) - { - if (srv_read_only_mode) { - - return; - } - - /* Avoid excessive mutex acquire/release */ - - ut_ad(trx->in_depth > 0); - - --trx->in_depth; - - if (trx->in_depth > 0) { - - return; - } - - trx_mutex_enter(trx); - - ut_ad((trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0); - - --trx->in_innodb; - - trx_mutex_exit(trx); - } - - /* - @return true if it is a forced rollback, asynchronously */ - static bool is_forced_rollback(const trx_t* trx) - { - ut_ad(trx_mutex_own(trx)); - - return((trx->in_innodb & TRX_FORCE_ROLLBACK)) > 0; - } - - /** - Wait for the asynchronous rollback to complete, if it is in progress */ - static void wait(trx_t* trx) - { - ut_ad(trx_mutex_own(trx)); - - ulint loop_count = 0; - /* start with optimistic sleep time - 20 micro seconds. */ - ulint sleep_time = 20; - - while (is_forced_rollback(trx)) { - - /* Wait for the async rollback to complete */ - - trx_mutex_exit(trx); - - loop_count++; - /* If the wait is long, don't hog the cpu. */ - if (loop_count < 100) { - /* 20 microseconds */ - sleep_time = 20; - } else if (loop_count < 1000) { - /* 1 millisecond */ - sleep_time = 1000; - } else { - /* 100 milliseconds */ - sleep_time = 100000; - } - - os_thread_sleep(sleep_time); - - trx_mutex_enter(trx); - } - } - - /** - @return true if transaction is started */ - static bool is_started(const trx_t* trx) - { - ut_ad(trx_mutex_own(trx)); - - return(trx_is_started(trx)); - } -private: - /** - Transaction instance crossing the handler boundary from the Server. */ - trx_t* m_trx; -}; - #include "trx0trx.ic" #endif diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic index 6372a02db17..6589aca4e77 100644 --- a/storage/innobase/include/trx0trx.ic +++ b/storage/innobase/include/trx0trx.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2016, 2018, MariaDB Corporation. 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 @@ -62,11 +62,8 @@ trx_state_eq( return(state == trx->state); case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - /* These states are not allowed for running transactions. */ ut_a(state == TRX_STATE_NOT_STARTED - || state == TRX_STATE_FORCED_ROLLBACK || (relaxed && thd_get_error_number(trx->mysql_thd))); @@ -208,67 +205,3 @@ ok: trx->ddl = true; trx->dict_operation = op; } - -/** -@param[in] trx Transaction to check -@return true if the transaction is a high priority transaction.*/ -UNIV_INLINE -bool -trx_is_high_priority(const trx_t* trx) -{ - if (trx->mysql_thd == NULL) { - return(false); - } - - return(thd_trx_priority(trx->mysql_thd) > 0); -} - -/** -@param[in] requestor Transaction requesting the lock -@param[in] holder Transaction holding the lock -@return the transaction that will be rolled back, null don't care */ -UNIV_INLINE -const trx_t* -trx_arbitrate(const trx_t* requestor, const trx_t* holder) -{ - ut_ad(!trx_is_autocommit_non_locking(holder)); - ut_ad(!trx_is_autocommit_non_locking(requestor)); - - /* Note: Background stats collection transactions also acquire - locks on user tables. They don't have an associated MySQL session - instance. */ - - if (requestor->mysql_thd == NULL) { - - ut_ad(!trx_is_high_priority(requestor)); - - if (trx_is_high_priority(holder)) { - return(requestor); - } else { - return(NULL); - } - - } else if (holder->mysql_thd == NULL) { - - ut_ad(!trx_is_high_priority(holder)); - - if (trx_is_high_priority(requestor)) { - return(holder); - } - - return(NULL); - } - - const THD* victim = thd_trx_arbitrate( - requestor->mysql_thd, holder->mysql_thd); - - ut_ad(victim == NULL - || victim == requestor->mysql_thd - || victim == holder->mysql_thd); - - if (victim != NULL) { - return(victim == requestor->mysql_thd ? requestor : holder); - } - - return(NULL); -} diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index 29139172c92..5100b8b978d 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2018, MariaDB Corporation. 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 @@ -50,21 +50,6 @@ static const ulint TRX_SYS_SPACE = 0; /** Random value to check for corruption of trx_t */ static const ulint TRX_MAGIC_N = 91118598; -/** If this flag is set then the transaction cannot be rolled back -asynchronously. */ -static const ib_uint32_t TRX_FORCE_ROLLBACK_DISABLE = 1 << 29; - -/** Was the transaction rolled back asynchronously or by the -owning thread. This flag is relevant only if TRX_FORCE_ROLLBACK -is set. */ -static const ib_uint32_t TRX_FORCE_ROLLBACK_ASYNC = 1 << 30; - -/** Mark the transaction for forced rollback */ -static const ib_uint32_t TRX_FORCE_ROLLBACK = 1U << 31; - -/** For masking out the above four flags */ -static const ib_uint32_t TRX_FORCE_ROLLBACK_MASK = 0x1FFFFFFF; - /** Transaction execution states when trx->state == TRX_STATE_ACTIVE */ enum trx_que_t { TRX_QUE_RUNNING, /*!< transaction is running */ @@ -76,13 +61,8 @@ enum trx_que_t { /** Transaction states (trx_t::state) */ enum trx_state_t { - TRX_STATE_NOT_STARTED, - /** Same as not started but with additional semantics that it - was rolled back asynchronously the last time it was active. */ - TRX_STATE_FORCED_ROLLBACK, - TRX_STATE_ACTIVE, /** Support for 2PC/XA */ diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index b9e5d72866b..09bffb5662e 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -28,12 +28,7 @@ Created 3/26/1996 Heikki Tuuri #define trx0undo_h #ifndef UNIV_INNOCHECKSUM -#include "univ.i" -#include "trx0types.h" -#include "mtr0mtr.h" #include "trx0sys.h" -#include "page0types.h" -#include "trx0xa.h" /** The LSB of the "is insert" flag in DB_ROLL_PTR */ #define ROLL_PTR_INSERT_FLAG_POS 55 diff --git a/storage/innobase/include/ut0new.h b/storage/innobase/include/ut0new.h index d61d3072d3d..68acccbee97 100644 --- a/storage/innobase/include/ut0new.h +++ b/storage/innobase/include/ut0new.h @@ -238,7 +238,7 @@ struct ut_new_pfx_t { #endif }; -static void ut_allocate_trace_dontdump(void * ptr, +static inline void ut_allocate_trace_dontdump(void * ptr, size_t bytes, bool dontdump, ut_new_pfx_t* pfx, @@ -262,7 +262,7 @@ static void ut_allocate_trace_dontdump(void * ptr, } } -static void ut_dodump(void* ptr, size_t m_size) +static inline void ut_dodump(void* ptr, size_t m_size) { #if defined(DBUG_OFF) && defined(HAVE_MADVISE) && defined(MADV_DODUMP) if (ptr && madvise(ptr, m_size, MADV_DODUMP)) { diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 089ae5b8a3f..25755354385 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -44,6 +44,7 @@ Created 5/7/1996 Heikki Tuuri #include "ut0new.h" #include "row0sel.h" #include "row0mysql.h" +#include "row0vers.h" #include "pars0pars.h" #include <set> @@ -79,15 +80,9 @@ lock_rec_has_to_wait_in_queue( /*==========================*/ const lock_t* wait_lock); /*!< in: waiting record lock */ -/*************************************************************//** -Grants a lock to a waiting lock request and releases the waiting transaction. -The caller must hold lock_sys.mutex. */ -static -void -lock_grant( -/*=======*/ - lock_t* lock, /*!< in/out: waiting lock request */ - bool owns_trx_mutex); /*!< in: whether lock->trx->mutex is owned */ +/** Grant a lock to a waiting lock request and release the waiting transaction +after lock_reset_lock_and_trx_wait() has been called. */ +static void lock_grant_after_reset(lock_t* lock); extern "C" void thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd); extern "C" int thd_need_wait_reports(const MYSQL_THD thd); @@ -304,8 +299,8 @@ private: /** This is to avoid malloc/free calls. */ static state_t s_states[MAX_STACK_SIZE]; - /** Set if thd_rpl_deadlock_check() should be called for waits. */ - bool m_report_waiters; + /** Set if thd_rpl_deadlock_check() should be called for waits. */ + const bool m_report_waiters; }; /** Counter to mark visited nodes during deadlock search. */ @@ -613,76 +608,10 @@ lock_get_size(void) return((ulint) sizeof(lock_t)); } -/*********************************************************************//** -Sets the wait flag of a lock and the back pointer in trx to lock. */ -UNIV_INLINE -void -lock_set_lock_and_trx_wait( -/*=======================*/ - lock_t* lock, /*!< in: lock */ - trx_t* trx) /*!< in/out: trx */ -{ - ut_ad(lock); - ut_ad(lock->trx == trx); - ut_ad(trx->lock.wait_lock == NULL); - ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(trx)); - - trx->lock.wait_lock = lock; - lock->type_mode |= LOCK_WAIT; -} - -/**********************************************************************//** -The back pointer to a waiting lock request in the transaction is set to NULL -and the wait bit in lock type_mode is reset. */ -UNIV_INLINE -void -lock_reset_lock_and_trx_wait( -/*=========================*/ - lock_t* lock) /*!< in/out: record lock */ +static inline void lock_grant_have_trx_mutex(lock_t* lock) { - ut_ad(lock_get_wait(lock)); - ut_ad(lock_mutex_own()); - - if (lock->trx->lock.wait_lock && - lock->trx->lock.wait_lock != lock) { - const char* stmt=NULL; - const char* stmt2=NULL; - size_t stmt_len; - trx_id_t trx_id = 0; - stmt = lock->trx->mysql_thd - ? innobase_get_stmt_unsafe( - lock->trx->mysql_thd, &stmt_len) - : NULL; - - if (lock->trx->lock.wait_lock && - lock->trx->lock.wait_lock->trx) { - trx_id = lock->trx->lock.wait_lock->trx->id; - stmt2 = lock->trx->lock.wait_lock->trx->mysql_thd - ? innobase_get_stmt_unsafe( - lock->trx->lock.wait_lock - ->trx->mysql_thd, &stmt_len) - : NULL; - } - - ib::error() << - "Trx id " << ib::hex(lock->trx->id) - << " is waiting a lock " - << " for this trx id " << ib::hex(trx_id) - << " wait_lock " << lock->trx->lock.wait_lock; - if (stmt) { - ib::info() << " SQL1: " << stmt; - } - - if (stmt2) { - ib::info() << " SQL2: " << stmt2; - } - - ut_ad(0); - } - - lock->trx->lock.wait_lock = NULL; - lock->type_mode &= ~LOCK_WAIT; + lock_reset_lock_and_trx_wait(lock); + lock_grant_after_reset(lock); } /*********************************************************************//** @@ -969,49 +898,6 @@ lock_rec_find_set_bit( return(ULINT_UNDEFINED); } -/** Reset the nth bit of a record lock. -@param[in,out] lock record lock -@param[in] i index of the bit that will be reset -@return previous value of the bit */ -UNIV_INLINE -byte -lock_rec_reset_nth_bit( - lock_t* lock, - ulint i) -{ - ut_ad(lock_get_type_low(lock) == LOCK_REC); - ut_ad(i < lock->un_member.rec_lock.n_bits); - - byte* b = reinterpret_cast<byte*>(&lock[1]) + (i >> 3); - byte mask = static_cast<byte>(1U << (i & 7)); - byte bit = *b & mask; - *b &= ~mask; - - if (bit != 0) { - ut_ad(lock->trx->lock.n_rec_locks > 0); - --lock->trx->lock.n_rec_locks; - } - - return(bit); -} - -/** Reset the nth bit of a record lock. -@param[in,out] lock record lock -@param[in] i index of the bit that will be reset -@param[in] type whether the lock is in wait mode */ -void -lock_rec_trx_wait( - lock_t* lock, - ulint i, - ulint type) -{ - lock_rec_reset_nth_bit(lock, i); - - if (type & LOCK_WAIT) { - lock_reset_lock_and_trx_wait(lock); - } -} - /*********************************************************************//** Determines if there are explicit record locks on a page. @return an explicit record lock on the page, or NULL if there are none */ @@ -1274,10 +1160,8 @@ wsrep_kill_victim( << wsrep_thd_query(lock->trx->mysql_thd); } - lock->trx->abort_type = TRX_WSREP_ABORT; wsrep_innobase_kill_one_trx(trx->mysql_thd, - (const trx_t*) trx, lock->trx, TRUE); - lock->trx->abort_type = TRX_SERVER_ABORT; + trx, lock->trx, TRUE); } } } @@ -1451,128 +1335,203 @@ wsrep_print_wait_locks( } #endif /* WITH_WSREP */ -/** -Check of the lock is on m_rec_id. -@param[in] lock Lock to compare with -@return true if the record lock is on m_rec_id*/ -/** -@param[in] rhs Lock to compare with -@return true if the record lock equals rhs */ -bool -RecLock::is_on_row(const lock_t* lock) const -{ - ut_ad(lock_get_type_low(lock) == LOCK_REC); - - const lock_rec_t& other = lock->un_member.rec_lock; - - return(other.space == m_rec_id.m_space_id - && other.page_no == m_rec_id.m_page_no - && lock_rec_get_nth_bit(lock, m_rec_id.m_heap_no)); -} - -/** -Do some checks and prepare for creating a new record lock */ -void -RecLock::prepare() const -{ - ut_ad(lock_mutex_own()); - ut_ad(m_trx == thr_get_trx(m_thr)); - - /* Test if there already is some other reason to suspend thread: - we do not enqueue a lock request if the query thread should be - stopped anyway */ - - if (que_thr_stop(m_thr)) { - ut_error; - } - - switch (trx_get_dict_operation(m_trx)) { - case TRX_DICT_OP_NONE: - break; - case TRX_DICT_OP_TABLE: - case TRX_DICT_OP_INDEX: - ib::error() << "A record lock wait happens in a dictionary" - " operation. index " << m_index->name - << " of table " << m_index->table->name - << ". " << BUG_REPORT_MSG; - ut_ad(0); - } - - ut_ad(m_index->table->n_ref_count > 0 - || !m_index->table->can_be_evicted); -} - -/** -Create the lock instance -@param[in, out] trx The transaction requesting the lock -@param[in, out] index Index on which record lock is required -@param[in] mode The lock mode desired -@param[in] rec_id The record id -@param[in] size Size of the lock + bitmap requested -@return a record lock instance */ +/** Create a new record lock and inserts it to the lock queue, +without checking for deadlocks or conflicts. +@param[in] type_mode lock mode and wait flag; type will be replaced + with LOCK_REC +@param[in] space tablespace id +@param[in] page_no index page number +@param[in] page R-tree index page, or NULL +@param[in] heap_no record heap number in the index page +@param[in] index the index tree +@param[in,out] trx transaction +@param[in] holds_trx_mutex whether the caller holds trx->mutex +@return created lock */ lock_t* -RecLock::lock_alloc( - trx_t* trx, +lock_rec_create_low( +#ifdef WITH_WSREP + lock_t* c_lock, /*!< conflicting lock */ + que_thr_t* thr, /*!< thread owning trx */ +#endif + ulint type_mode, + ulint space, + ulint page_no, + const page_t* page, + ulint heap_no, dict_index_t* index, - ulint mode, - const RecID& rec_id, - ulint size) + trx_t* trx, + bool holds_trx_mutex) { + lock_t* lock; + ulint n_bits; + ulint n_bytes; + ut_ad(lock_mutex_own()); + ut_ad(holds_trx_mutex == trx_mutex_own(trx)); + ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index)); - lock_t* lock; +#ifdef UNIV_DEBUG + /* Non-locking autocommit read-only transactions should not set + any locks. See comment in trx_set_rw_mode explaining why this + conditional check is required in debug code. */ + if (holds_trx_mutex) { + check_trx_state(trx); + } +#endif /* UNIV_DEBUG */ - if (trx->lock.rec_cached >= trx->lock.rec_pool.size() - || sizeof(*lock) + size > REC_LOCK_SIZE) { + /* If rec is the supremum record, then we reset the gap and + LOCK_REC_NOT_GAP bits, as all locks on the supremum are + automatically of the gap type */ - ulint n_bytes = size + sizeof(*lock); - mem_heap_t* heap = trx->lock.lock_heap; + if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) { + ut_ad(!(type_mode & LOCK_REC_NOT_GAP)); + type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP); + } - lock = reinterpret_cast<lock_t*>(mem_heap_alloc(heap, n_bytes)); + if (UNIV_LIKELY(!(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE)))) { + /* Make lock bitmap bigger by a safety margin */ + n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; + n_bytes = 1 + n_bits / 8; } else { + ut_ad(heap_no == PRDT_HEAPNO); + + /* The lock is always on PAGE_HEAP_NO_INFIMUM (0), so + we only need 1 bit (which round up to 1 byte) for + lock bit setting */ + n_bytes = 1; + + if (type_mode & LOCK_PREDICATE) { + ulint tmp = UNIV_WORD_SIZE - 1; + + /* We will attach predicate structure after lock. + Make sure the memory is aligned on 8 bytes, + the mem_heap_alloc will align it with + MEM_SPACE_NEEDED anyway. */ + n_bytes = (n_bytes + sizeof(lock_prdt_t) + tmp) & ~tmp; + ut_ad(n_bytes == sizeof(lock_prdt_t) + UNIV_WORD_SIZE); + } + } - lock = trx->lock.rec_pool[trx->lock.rec_cached]; - ++trx->lock.rec_cached; + if (trx->lock.rec_cached >= trx->lock.rec_pool.size() + || sizeof *lock + n_bytes > REC_LOCK_SIZE) { + lock = static_cast<lock_t*>( + mem_heap_alloc(trx->lock.lock_heap, + sizeof *lock + n_bytes)); + } else { + lock = trx->lock.rec_pool[trx->lock.rec_cached++]; } lock->trx = trx; - + lock->type_mode = (type_mode & ~LOCK_TYPE_MASK) | LOCK_REC; lock->index = index; + lock->un_member.rec_lock.space = uint32_t(space); + lock->un_member.rec_lock.page_no = uint32_t(page_no); - /* Setup the lock attributes */ - - lock->type_mode = uint32_t(LOCK_REC | (mode & ~LOCK_TYPE_MASK)); - - lock_rec_t& rec_lock = lock->un_member.rec_lock; + if (UNIV_LIKELY(!(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE)))) { + lock->un_member.rec_lock.n_bits = uint32_t(n_bytes * 8); + } else { + /* Predicate lock always on INFIMUM (0) */ + lock->un_member.rec_lock.n_bits = 8; + } + lock_rec_bitmap_reset(lock); + lock_rec_set_nth_bit(lock, heap_no); + index->table->n_rec_locks++; + ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); - /* Predicate lock always on INFIMUM (0) */ +#ifdef WITH_WSREP + if (c_lock && wsrep_on_trx(trx) + && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + lock_t *hash = (lock_t *)c_lock->hash; + lock_t *prev = NULL; - if (is_predicate_lock(mode)) { + while (hash && wsrep_thd_is_BF(hash->trx->mysql_thd, TRUE) + && wsrep_trx_order_before(hash->trx->mysql_thd, + trx->mysql_thd)) { + prev = hash; + hash = (lock_t *)hash->hash; + } + lock->hash = hash; + if (prev) { + prev->hash = lock; + } else { + c_lock->hash = lock; + } + /* + * delayed conflict resolution '...kill_one_trx' was not called, + * if victim was waiting for some other lock + */ + trx_mutex_enter(c_lock->trx); + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - rec_lock.n_bits = 8; + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - memset(&lock[1], 0x0, 1); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } - } else { - ut_ad(8 * size < UINT32_MAX); - rec_lock.n_bits = static_cast<uint32_t>(8 * size); + trx->lock.que_state = TRX_QUE_LOCK_WAIT; + lock_set_lock_and_trx_wait(lock, trx); + UT_LIST_ADD_LAST(trx->lock.trx_locks, lock); - memset(&lock[1], 0x0, size); - } + trx->lock.wait_thr = thr; + thr->state = QUE_THR_LOCK_WAIT; - rec_lock.space = rec_id.m_space_id; + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + if (holds_trx_mutex) { + trx_mutex_exit(trx); + } + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); - rec_lock.page_no = rec_id.m_page_no; + if (holds_trx_mutex) { + trx_mutex_enter(trx); + } - /* Set the bit corresponding to rec */ + trx_mutex_exit(c_lock->trx); - lock_rec_set_nth_bit(lock, rec_id.m_heap_no); + if (wsrep_debug) { + ib::info() << "WSREP: c_lock canceled " + << ib::hex(c_lock->trx->id) + << " SQL: " + << wsrep_thd_query( + c_lock->trx->mysql_thd); + } - MONITOR_INC(MONITOR_NUM_RECLOCK); + /* have to bail out here to avoid lock_set_lock... */ + return(lock); + } + trx_mutex_exit(c_lock->trx); + } else +#endif /* WITH_WSREP */ + if (!(type_mode & (LOCK_WAIT | LOCK_PREDICATE | LOCK_PRDT_PAGE)) + && innodb_lock_schedule_algorithm + == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS + && !thd_is_replication_slave_thread(trx->mysql_thd)) { + HASH_PREPEND(lock_t, hash, lock_sys.rec_hash, + lock_rec_fold(space, page_no), lock); + } else { + HASH_INSERT(lock_t, hash, lock_hash_get(type_mode), + lock_rec_fold(space, page_no), lock); + } + if (!holds_trx_mutex) { + trx_mutex_enter(trx); + } + ut_ad(trx_mutex_own(trx)); + if (type_mode & LOCK_WAIT) { + lock_set_lock_and_trx_wait(lock, trx); + } + UT_LIST_ADD_LAST(trx->lock.trx_locks, lock); + if (!holds_trx_mutex) { + trx_mutex_exit(trx); + } MONITOR_INC(MONITOR_RECLOCK_CREATED); + MONITOR_INC(MONITOR_NUM_RECLOCK); - return(lock); + return lock; } /*********************************************************************//** @@ -1583,6 +1542,7 @@ If only one of them is a wait lock, it has lower priority. If either is a high priority transaction, the lock has higher priority. Otherwise, the one with an older transaction has higher priority. @returns true if lock1 has higher priority, false otherwise. */ +static bool has_higher_priority( lock_t *lock1, @@ -1599,9 +1559,6 @@ has_higher_priority( } else if (!lock_get_wait(lock2)) { return false; } - if (trx_is_high_priority(lock1->trx)) { - return false; - } return lock1->trx->start_time_micro <= lock2->trx->start_time_micro; } @@ -1636,7 +1593,7 @@ lock_rec_insert_by_trx_age( cell->node = in_lock; in_lock->hash = node; if (lock_get_wait(in_lock)) { - lock_grant(in_lock, true); + lock_grant_have_trx_mutex(in_lock); return DB_SUCCESS_LOCKED_REC; } return DB_SUCCESS; @@ -1650,7 +1607,7 @@ lock_rec_insert_by_trx_age( in_lock->hash = next; if (lock_get_wait(in_lock) && !lock_rec_has_to_wait_in_queue(in_lock)) { - lock_grant(in_lock, true); + lock_grant_have_trx_mutex(in_lock); if (cell->node != in_lock) { // Move it to the front of the queue node->hash = in_lock->hash; @@ -1726,394 +1683,123 @@ lock_rec_insert_to_head( } } -/** -Add the lock to the record lock hash and the transaction's lock list -@param[in,out] lock Newly created record lock to add to the rec hash -@param[in] add_to_hash If the lock should be added to the hash table */ -void -RecLock::lock_add(lock_t* lock, bool add_to_hash) const -{ - ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(lock->trx)); - - bool wait_lock = m_mode & LOCK_WAIT; - - if (add_to_hash) { - ulint key = m_rec_id.fold(); - hash_table_t *lock_hash = lock_hash_get(m_mode); - - ++lock->index->table->n_rec_locks; - - if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS - && !thd_is_replication_slave_thread(lock->trx->mysql_thd)) { - if (wait_lock) { - HASH_INSERT(lock_t, hash, lock_hash, key, lock); - } else { - lock_rec_insert_to_head(lock, m_rec_id.fold()); - } - } else { - HASH_INSERT(lock_t, hash, lock_hash, key, lock); - } - } - - if (wait_lock) { - lock_set_lock_and_trx_wait(lock, lock->trx); - } - - UT_LIST_ADD_LAST(lock->trx->lock.trx_locks, lock); -} - -/** -Create a new lock. -@param[in,out] trx Transaction requesting the lock -@param[in] owns_trx_mutex true if caller owns the trx_t::mutex -@param[in] add_to_hash add the lock to hash table -@param[in] prdt Predicate lock (optional) -@param[in,out] c_lock Conflicting lock request or NULL - in Galera conflicting lock is selected - as deadlock victim if requester - is BF transaction. -@return a new lock instance */ -lock_t* -RecLock::create( - trx_t* trx, - bool owns_trx_mutex, - bool add_to_hash, - const lock_prdt_t* prdt +/** Enqueue a waiting request for a lock which cannot be granted immediately. +Check for deadlocks. +@param[in] type_mode the requested lock mode (LOCK_S or LOCK_X) + possibly ORed with LOCK_GAP or + LOCK_REC_NOT_GAP, ORed with + LOCK_INSERT_INTENTION if this + waiting lock request is set + when performing an insert of + an index record +@param[in] block leaf page in the index +@param[in] heap_no record heap number in the block +@param[in] index index tree +@param[in,out] thr query thread +@param[in] prdt minimum bounding box (spatial index) +@retval DB_LOCK_WAIT if the waiting lock was enqueued +@retval DB_DEADLOCK if this transaction was chosen as the victim +@retval DB_SUCCESS_LOCKED_REC if the other transaction was chosen as a victim + (or it happened to commit) */ +dberr_t +lock_rec_enqueue_waiting( #ifdef WITH_WSREP - ,lock_t* c_lock -#endif /* WITH_WSREP */ -) const + lock_t* c_lock, /*!< conflicting lock */ +#endif + ulint type_mode, + const buf_block_t* block, + ulint heap_no, + dict_index_t* index, + que_thr_t* thr, + lock_prdt_t* prdt) { ut_ad(lock_mutex_own()); - ut_ad(owns_trx_mutex == trx_mutex_own(trx)); - - /* Create the explicit lock instance and initialise it. */ - - lock_t* lock = lock_alloc(trx, m_index, m_mode, m_rec_id, m_size); + ut_ad(!srv_read_only_mode); + ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index)); - if (prdt != NULL && (m_mode & LOCK_PREDICATE)) { + trx_t* trx = thr_get_trx(thr); - lock_prdt_set_prdt(lock, prdt); + if (trx->mysql_thd && thd_lock_wait_timeout(trx->mysql_thd) == 0) { + //trx->error_state = DB_LOCK_WAIT_TIMEOUT; + return DB_LOCK_WAIT_TIMEOUT; } -#ifdef WITH_WSREP - if (c_lock && wsrep_on_trx(trx) && - wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - lock_t *hash = (lock_t *)c_lock->hash; - lock_t *prev = NULL; - - while (hash && - wsrep_thd_is_BF(((lock_t *)hash)->trx->mysql_thd, TRUE) && - wsrep_trx_order_before( - ((lock_t *)hash)->trx->mysql_thd, - trx->mysql_thd)) { - prev = hash; - hash = (lock_t *)hash->hash; - } - - lock->hash = hash; - - if (prev) { - prev->hash = lock; - } else { - c_lock->hash = lock; - } - /* - * delayed conflict resolution '...kill_one_trx' was not called, - * if victim was waiting for some other lock - */ - trx_mutex_enter(c_lock->trx); - if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - - if (wsrep_debug) { - wsrep_print_wait_locks(c_lock); - } - - trx->lock.que_state = TRX_QUE_LOCK_WAIT; - lock_set_lock_and_trx_wait(lock, trx); - UT_LIST_ADD_LAST(trx->lock.trx_locks, lock); - - ut_ad(m_thr != NULL); - trx->lock.wait_thr = m_thr; - m_thr->state = QUE_THR_LOCK_WAIT; - - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - if (owns_trx_mutex) { - trx_mutex_exit(trx); - } - - lock_cancel_waiting_and_release( - c_lock->trx->lock.wait_lock); - - if (owns_trx_mutex) { - trx_mutex_enter(trx); - } - - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - if (wsrep_debug) { - ib::info() << - "victim trx waits for some other lock than c_lock"; - } - lock_reset_lock_and_trx_wait(lock); - } - - trx_mutex_exit(c_lock->trx); - - if (wsrep_debug) { - ib::info() << "WSREP: c_lock canceled " << ib::hex(c_lock->trx->id); - ib::info() << " SQL1: " - << wsrep_thd_query(c_lock->trx->mysql_thd); - ib::info() << " SQL2: " - << wsrep_thd_query(trx->mysql_thd); - } - - ++lock->index->table->n_rec_locks; - /* have to bail out here to avoid lock_set_lock... */ - return(lock); - } - trx_mutex_exit(c_lock->trx); - /* we don't want to add to hash anymore, but need other updates from lock_add */ - ++lock->index->table->n_rec_locks; - lock_add(lock, false); - } else { -#endif /* WITH_WSREP */ - - /* Ensure that another transaction doesn't access the trx - lock state and lock data structures while we are adding the - lock and changing the transaction state to LOCK_WAIT */ + ut_ad(trx_mutex_own(trx)); + ut_a(!que_thr_stop(thr)); - if (!owns_trx_mutex) { - trx_mutex_enter(trx); + switch (trx_get_dict_operation(trx)) { + case TRX_DICT_OP_NONE: + break; + case TRX_DICT_OP_TABLE: + case TRX_DICT_OP_INDEX: + ib::error() << "A record lock wait happens in a dictionary" + " operation. index " + << index->name + << " of table " + << index->table->name + << ". " << BUG_REPORT_MSG; + ut_ad(0); } - lock_add(lock, add_to_hash); - - if (!owns_trx_mutex) { - trx_mutex_exit(trx); - } + /* Enqueue the lock request that will wait to be granted, note that + we already own the trx mutex. */ + lock_t* lock = lock_rec_create( #ifdef WITH_WSREP - } -#endif /* WITH_WSREP */ - - return(lock); -} - -/** -Check the outcome of the deadlock check -@param[in,out] victim_trx Transaction selected for rollback -@param[in,out] lock Lock being requested -@return DB_LOCK_WAIT, DB_DEADLOCK or DB_SUCCESS_LOCKED_REC */ -dberr_t -RecLock::check_deadlock_result(const trx_t* victim_trx, lock_t* lock) -{ - ut_ad(lock_mutex_own()); - ut_ad(m_trx == lock->trx); - ut_ad(trx_mutex_own(m_trx)); - - if (victim_trx != NULL) { + c_lock, thr, +#endif + type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE); - ut_ad(victim_trx == m_trx); + if (prdt && type_mode & LOCK_PREDICATE) { + lock_prdt_set_prdt(lock, prdt); + } + if (const trx_t* victim = + DeadlockChecker::check_and_resolve(lock, trx)) { + ut_ad(victim == trx); lock_reset_lock_and_trx_wait(lock); + lock_rec_reset_nth_bit(lock, heap_no); + return DB_DEADLOCK; + } - lock_rec_reset_nth_bit(lock, m_rec_id.m_heap_no); - - return(DB_DEADLOCK); - - } else if (m_trx->lock.wait_lock == NULL) { - + if (!trx->lock.wait_lock) { /* If there was a deadlock but we chose another transaction as a victim, it is possible that we already have the lock now granted! */ - - return(DB_SUCCESS_LOCKED_REC); - } - - return(DB_LOCK_WAIT); -} - -/** -Check and resolve any deadlocks -@param[in, out] lock The lock being acquired -@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or - DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that - there was a deadlock, but another transaction was chosen - as a victim, and we got the lock immediately: no need to - wait then */ -dberr_t -RecLock::deadlock_check(lock_t* lock) -{ - ut_ad(lock_mutex_own()); - ut_ad(lock->trx == m_trx); - ut_ad(trx_mutex_own(m_trx)); - - const trx_t* victim_trx = - DeadlockChecker::check_and_resolve(lock, m_trx); - - /* Check the outcome of the deadlock test. It is possible that - the transaction that blocked our lock was rolled back and we - were granted our lock. */ - - dberr_t err = check_deadlock_result(victim_trx, lock); - - if (err == DB_LOCK_WAIT) { - - set_wait_state(lock); - - MONITOR_INC(MONITOR_LOCKREC_WAIT); - } - - return(err); -} - -/** -Collect the transactions that will need to be rolled back asynchronously -@param[in, out] trx Transaction to be rolled back */ -void -RecLock::mark_trx_for_rollback(trx_t* trx) -{ - trx->abort = true; - - ut_ad(!trx->read_only); - ut_ad(trx_mutex_own(m_trx)); - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK)); - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC)); - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE)); - - /* Note that we will attempt an async rollback. The _ASYNC - flag will be cleared if the transaction is rolled back - synchronously before we get a chance to do it. */ - - trx->in_innodb |= TRX_FORCE_ROLLBACK | TRX_FORCE_ROLLBACK_ASYNC; - - ut_a(!trx->killed_by); - my_atomic_storelong(&trx->killed_by, (long) os_thread_get_curr_id()); - - m_trx->hit_list.push_back(hit_list_t::value_type(trx)); - -#ifdef UNIV_DEBUG - THD* thd = trx->mysql_thd; - - if (thd != NULL) { - - char buffer[1024]; - ib::info() << "Blocking transaction: ID: " << ib::hex(trx->id) << " - " - << " Blocked transaction ID: "<< ib::hex(m_trx->id) << " - " - << thd_get_error_context_description(thd, buffer, sizeof(buffer), - 512); - } -#endif /* UNIV_DEBUG */ -} - -/** -Setup the requesting transaction state for lock grant -@param[in,out] lock Lock for which to change state */ -void -RecLock::set_wait_state(lock_t* lock) -{ - ut_ad(lock_mutex_own()); - ut_ad(m_trx == lock->trx); - ut_ad(trx_mutex_own(m_trx)); - ut_ad(lock_get_wait(lock)); - - m_trx->lock.wait_started = ut_time(); - - m_trx->lock.que_state = TRX_QUE_LOCK_WAIT; - - m_trx->lock.was_chosen_as_deadlock_victim = false; - - bool stopped = que_thr_stop(m_thr); - ut_a(stopped); -} - -/** -Enqueue a lock wait for normal transaction. If it is a high priority transaction -then jump the record lock wait queue and if the transaction at the head of the -queue is itself waiting roll it back, also do a deadlock check and resolve. -@param[in, out] wait_for The lock that the joining transaction is - waiting for -@param[in] prdt Predicate [optional] -@return DB_LOCK_WAIT, DB_LOCK_WAIT_TIMEOUT, DB_DEADLOCK, or - DB_QUE_THR_SUSPENDED, or DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC - means that there was a deadlock, but another transaction was chosen - as a victim, and we got the lock immediately: no need to wait then; - DB_LOCK_WAIT_TIMEOUT means no need to wait */ -dberr_t -RecLock::add_to_waitq(lock_t* wait_for, const lock_prdt_t* prdt) -{ - ut_ad(lock_mutex_own()); - ut_ad(m_trx == thr_get_trx(m_thr)); - ut_ad(trx_mutex_own(m_trx)); - - if (m_trx->mysql_thd && thd_lock_wait_timeout(m_trx->mysql_thd) == 0) { - m_trx->error_state = DB_LOCK_WAIT_TIMEOUT; - return(DB_LOCK_WAIT_TIMEOUT); - } - - DEBUG_SYNC_C("rec_lock_add_to_waitq"); - - m_mode |= LOCK_WAIT; - - /* Do the preliminary checks, and set query thread state */ - - prepare(); - - bool high_priority = trx_is_high_priority(m_trx); - - /* Don't queue the lock to hash table, if high priority transaction. */ - lock_t* lock = create( - m_trx, true, !high_priority, prdt #ifdef WITH_WSREP - ,wait_for -#endif /* WITH_WSREP */ - ); + if (wsrep_debug) { + ib::info() << "WSREP: BF thread got lock granted early, ID " << ib::hex(trx->id) + << " query: " << wsrep_thd_query(trx->mysql_thd); + } +#endif + return DB_SUCCESS_LOCKED_REC; + } - /* Attempt to jump over the low priority waiting locks. */ - if (high_priority && jump_queue(lock, wait_for)) { + trx->lock.que_state = TRX_QUE_LOCK_WAIT; - /* Lock is granted */ - return(DB_SUCCESS); - } + trx->lock.was_chosen_as_deadlock_victim = false; + trx->lock.wait_started = ut_time(); -#ifdef WITH_WSREP - if (!lock_get_wait(lock) && wsrep_thd_is_BF(m_trx->mysql_thd, FALSE)) { - if (wsrep_debug) { - ib::info() << "WSREP: BF thread got lock granted early, ID " << ib::hex(lock->trx->id) - << " query: " << wsrep_thd_query(m_trx->mysql_thd); - } - return(DB_SUCCESS); - } -#endif /* WITH_WSREP */ - ut_ad(lock_get_wait(lock)); + ut_a(que_thr_stop(thr)); - dberr_t err = deadlock_check(lock); - ut_ad(trx_mutex_own(m_trx)); + DBUG_LOG("ib_lock", "trx " << ib::hex(trx->id) + << " waits for lock in index " << index->name + << " of table " << index->table->name); - // Move it only when it does not cause a deadlock. - if (err != DB_DEADLOCK - && innodb_lock_schedule_algorithm - == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS - && !thd_is_replication_slave_thread(lock->trx->mysql_thd) - && !trx_is_high_priority(lock->trx)) { + MONITOR_INC(MONITOR_LOCKREC_WAIT); - HASH_DELETE(lock_t, hash, lock_hash_get(lock->type_mode), - m_rec_id.fold(), lock); + if (innodb_lock_schedule_algorithm + == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS + && !prdt + && !thd_is_replication_slave_thread(lock->trx->mysql_thd)) { + HASH_DELETE(lock_t, hash, lock_sys.rec_hash, + lock_rec_lock_fold(lock), lock); dberr_t res = lock_rec_insert_by_trx_age(lock); if (res != DB_SUCCESS) { return res; } } - return(err); + return DB_LOCK_WAIT; } /*********************************************************************//** @@ -2238,9 +1924,11 @@ lock_rec_add_to_queue( } } - RecLock rec_lock(index, block, heap_no, type_mode); - - rec_lock.create(trx, caller_owns_trx_mutex, true); + lock_rec_create( +#ifdef WITH_WSREP + NULL, NULL, +#endif + type_mode, block, heap_no, index, trx, caller_owns_trx_mutex); } /*********************************************************************//** @@ -2249,8 +1937,7 @@ possible, enqueues a waiting lock request. This is a low-level function which does NOT look at implicit locks! Checks lock compatibility within explicit locks. This function sets a normal next-key lock, or in the case of a page supremum record, a gap type lock. -@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, -or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ static dberr_t lock_rec_lock( @@ -2297,17 +1984,19 @@ lock_rec_lock( /* Do nothing if the trx already has a strong enough lock on rec */ if (!lock_rec_has_expl(mode, block, heap_no, trx)) { - if (lock_t *wait_for= lock_rec_other_has_conflicting(mode, block, - heap_no, trx)) + if (lock_t *c_lock= lock_rec_other_has_conflicting(mode, block, + heap_no, trx)) { /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the - record, we may have to wait. - */ - RecLock rec_lock(thr, index, block, heap_no, mode); - err= rec_lock.add_to_waitq(wait_for); + record, we have to wait. */ + err = lock_rec_enqueue_waiting( +#ifdef WITH_WSREP + c_lock, +#endif /* WITH_WSREP */ + mode, block, heap_no, index, thr, NULL); } else if (!impl) { @@ -2339,7 +2028,12 @@ lock_rec_lock( Note that we don't own the trx mutex. */ if (!impl) - RecLock(index, block, heap_no, mode).create(trx, false, true); + lock_rec_create( +#ifdef WITH_WSREP + NULL, NULL, +#endif + mode, block, heap_no, index, trx, false); + err= DB_SUCCESS_LOCKED_REC; } lock_mutex_exit(); @@ -2409,24 +2103,12 @@ lock_rec_has_to_wait_in_queue( return(NULL); } -/*************************************************************//** -Grants a lock to a waiting lock request and releases the waiting transaction. -The caller must hold lock_sys.mutex but not lock->trx->mutex. */ -static -void -lock_grant( -/*=======*/ - lock_t* lock, /*!< in/out: waiting lock request */ - bool owns_trx_mutex) /*!< in: whether lock->trx->mutex is owned */ +/** Grant a lock to a waiting lock request and release the waiting transaction +after lock_reset_lock_and_trx_wait() has been called. */ +static void lock_grant_after_reset(lock_t* lock) { ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(lock->trx) == owns_trx_mutex); - - lock_reset_lock_and_trx_wait(lock); - - if (!owns_trx_mutex) { - trx_mutex_enter(lock->trx); - } + ut_ad(trx_mutex_own(lock->trx)); if (lock_get_mode(lock) == LOCK_AUTO_INC) { dict_table_t* table = lock->un_member.tab_lock.table; @@ -2458,238 +2140,15 @@ lock_grant( lock_wait_release_thread_if_suspended(thr); } } - - if (!owns_trx_mutex) { - trx_mutex_exit(lock->trx); - } } -/** -Jump the queue for the record over all low priority transactions and -add the lock. If all current granted locks are compatible, grant the -lock. Otherwise, mark all granted transaction for asynchronous -rollback and add to hit list. -@param[in, out] lock Lock being requested -@param[in] conflict_lock First conflicting lock from the head -@return true if the lock is granted */ -bool -RecLock::jump_queue( - lock_t* lock, - const lock_t* conflict_lock) -{ - ut_ad(m_trx == lock->trx); - ut_ad(trx_mutex_own(m_trx)); - ut_ad(conflict_lock->trx != m_trx); - ut_ad(trx_is_high_priority(m_trx)); - ut_ad(m_rec_id.m_heap_no != ULINT32_UNDEFINED); - - bool high_priority = false; - - /* Find out the position to add the lock. If there are other high - priority transactions in waiting state then we should add it after - the last high priority transaction. Otherwise, we can add it after - the last granted lock jumping over the wait queue. */ - bool grant_lock = lock_add_priority(lock, conflict_lock, - &high_priority); - - if (grant_lock) { - - ut_ad(conflict_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT); - ut_ad(conflict_lock->trx->lock.wait_lock == conflict_lock); - - DBUG_LOG("trx", - "Granting High Priority Transaction " - << ib::hex(lock->trx->id) << " a lock jumping over" - << " waiting Transaction " << ib::hex(conflict_lock->trx->id)); - - lock_reset_lock_and_trx_wait(lock); - return(true); - } - - /* If another high priority transaction is found waiting - victim transactions are already marked for rollback. */ - if (high_priority) { - - return(false); - } - - /* The lock is placed after the last granted lock in the queue. Check and add - low priority transactinos to hit list for ASYNC rollback. */ - make_trx_hit_list(lock, conflict_lock); - - return(false); -} - -/** Find position in lock queue and add the high priority transaction -lock. Intention and GAP only locks can be granted even if there are -waiting locks in front of the queue. To add the High priority -transaction in a safe position we keep the following rule. - -1. If the lock can be granted, add it before the first waiting lock -in the queue so that all currently waiting locks need to do conflict -check before getting granted. - -2. If the lock has to wait, add it after the last granted lock or the -last waiting high priority transaction in the queue whichever is later. -This ensures that the transaction is granted only after doing conflict -check with all granted transactions. -@param[in] lock Lock being requested -@param[in] conflict_lock First conflicting lock from the head -@param[out] high_priority high priority transaction ahead in queue -@return true if the lock can be granted */ -bool -RecLock::lock_add_priority( - lock_t* lock, - const lock_t* conflict_lock, - bool* high_priority) +/** Grant a lock to a waiting lock request and release the waiting transaction. */ +static void lock_grant(lock_t* lock) { - ut_ad(high_priority); - - *high_priority = false; - - /* If the first conflicting lock is waiting for the current row, - then all other granted locks are compatible and the lock can be - directly granted if no other high priority transactions are - waiting. We need to recheck with all granted transaction as there - could be granted GAP or Intention locks down the queue. */ - bool grant_lock = (conflict_lock->is_waiting()); - lock_t* lock_head = NULL; - lock_t* grant_position = NULL; - lock_t* add_position = NULL; - - /* Different lock (such as predicate lock) are on different hash */ - hash_table_t* lock_hash = lock_hash_get(m_mode); - - HASH_SEARCH(hash, lock_hash, m_rec_id.fold(), lock_t*, - lock_head, ut_ad(lock_head->is_record_lock()), true); - - ut_ad(lock_head); - - for (lock_t* next = lock_head; next != NULL; next = next->hash) { - - /* check only for locks on the current row */ - if (!is_on_row(next)) { - continue; - } - - if (next->is_waiting()) { - /* grant lock position is the granted lock just before - the first wait lock in the queue. */ - if (grant_position == NULL) { - grant_position = add_position; - } - - if (trx_is_high_priority(next->trx)) { - - *high_priority = true; - grant_lock = false; - add_position = next; - } - } else { - - add_position = next; - /* Cannot grant lock if there is any conflicting - granted lock. */ - if (grant_lock && lock_has_to_wait(lock, next)) { - grant_lock = false; - } - } - } - - /* If the lock is to be granted it is safe to add before the first - waiting lock in the queue. */ - if (grant_lock) { - - ut_ad(!lock_has_to_wait(lock, grant_position)); - add_position = grant_position; - } - - ut_ad(add_position != NULL); - - /* Add the lock to lock hash table. */ - lock->hash = add_position->hash; - add_position->hash = lock; - ++lock->index->table->n_rec_locks; - - return(grant_lock); -} - -/** Iterate over the granted locks and prepare the hit list for ASYNC Rollback. -If the transaction is waiting for some other lock then wake up with deadlock error. -Currently we don't mark following transactions for ASYNC Rollback. -1. Read only transactions -2. Background transactions -3. Other High priority transactions -@param[in] lock Lock being requested -@param[in] conflict_lock First conflicting lock from the head */ -void -RecLock::make_trx_hit_list( - lock_t* lock, - const lock_t* conflict_lock) -{ - const lock_t* next; - - for (next = conflict_lock; next != NULL; next = next->hash) { - - /* All locks ahead in the queue are checked. */ - if (next == lock) { - - ut_ad(next->is_waiting()); - break; - } - - trx_t* trx = next->trx; - /* Check only for conflicting, granted locks on the current row. - Currently, we don't rollback read only transactions, transactions - owned by background threads. */ - if (trx == lock->trx - || !is_on_row(next) - || next->is_waiting() - || trx->read_only - || trx->mysql_thd == NULL - || !lock_has_to_wait(lock, next)) { - - continue; - } - - trx_mutex_enter(trx); - - /* Skip high priority transactions, if already marked for abort - by some other transaction or if ASYNC rollback is disabled. A - transaction must complete kill/abort of a victim transaction once - marked and added to hit list. */ - if (trx_is_high_priority(trx) - || (trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE) != 0 - || trx->abort) { - - trx_mutex_exit(trx); - continue; - } - - /* If the transaction is waiting on some other resource then - wake it up with DEAD_LOCK error so that it can rollback. */ - if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - /* Assert that it is not waiting for current record. */ - ut_ad(trx->lock.wait_lock != next); - - DBUG_LOG("trx", "High Priority Transaction " - << ib::hex(lock->trx->id) - << " waking up blocking transaction " - << ib::hex(trx->id)); - - trx->lock.was_chosen_as_deadlock_victim = true; - lock_cancel_waiting_and_release(trx->lock.wait_lock); - trx_mutex_exit(trx); - continue; - } - - /* Mark for ASYNC Rollback and add to hit list. */ - mark_trx_for_rollback(trx); - trx_mutex_exit(trx); - } - - ut_ad(next == lock); + lock_reset_lock_and_trx_wait(lock); + trx_mutex_enter(lock->trx); + lock_grant_after_reset(lock); + trx_mutex_exit(lock->trx); } /*************************************************************//** @@ -2729,17 +2188,13 @@ lock_rec_cancel( static void -lock_grant_and_move_on_page( - hash_table_t* lock_hash, - ulint space, - ulint page_no) +lock_grant_and_move_on_page(ulint rec_fold, ulint space, ulint page_no) { lock_t* lock; - lock_t* previous; - ulint rec_fold = lock_rec_fold(space, page_no); - - previous = (lock_t *) hash_get_nth_cell(lock_hash, - hash_calc_hash(rec_fold, lock_hash))->node; + lock_t* previous = static_cast<lock_t*>( + hash_get_nth_cell(lock_sys.rec_hash, + hash_calc_hash(rec_fold, lock_sys.rec_hash)) + ->node); if (previous == NULL) { return; } @@ -2759,27 +2214,13 @@ lock_grant_and_move_on_page( ut_ad(previous->hash == lock || previous == lock); /* Grant locks if there are no conflicting locks ahead. Move granted locks to the head of the list. */ - for (;lock != NULL;) { + while (lock) { /* If the lock is a wait lock on this page, and it does not need to wait. */ - if ((lock->un_member.rec_lock.space == space) - && (lock->un_member.rec_lock.page_no == page_no) - && lock_get_wait(lock) - && !lock_rec_has_to_wait_in_queue(lock)) { - - bool exit_trx_mutex = false; - - if (lock->trx->abort_type != TRX_SERVER_ABORT) { - ut_ad(trx_mutex_own(lock->trx)); - trx_mutex_exit(lock->trx); - exit_trx_mutex = true; - } - - lock_grant(lock, false); - - if (exit_trx_mutex) { - ut_ad(!trx_mutex_own(lock->trx)); - trx_mutex_enter(lock->trx); - } + if (lock_get_wait(lock) + && lock->un_member.rec_lock.space == space + && lock->un_member.rec_lock.page_no == page_no + && !lock_rec_has_to_wait_in_queue(lock)) { + lock_grant(lock); if (previous != NULL) { /* Move the lock to the head of the list. */ @@ -2798,86 +2239,57 @@ lock_grant_and_move_on_page( } } -/*************************************************************//** -Removes a record lock request, waiting or granted, from the queue and -grants locks to other transactions in the queue if they now are entitled -to a lock. NOTE: all record locks contained in in_lock are removed. */ -static -void -lock_rec_dequeue_from_page( -/*=======================*/ - lock_t* in_lock) /*!< in: record lock object: all - record locks which are contained in - this lock object are removed; - transactions waiting behind will - get their lock requests granted, - if they are now qualified to it */ +/** Remove a record lock request, waiting or granted, from the queue and +grant locks to other transactions in the queue if they now are entitled +to a lock. NOTE: all record locks contained in in_lock are removed. +@param[in,out] in_lock record lock */ +static void lock_rec_dequeue_from_page(lock_t* in_lock) { ulint space; ulint page_no; - lock_t* lock; - trx_lock_t* trx_lock; hash_table_t* lock_hash; ut_ad(lock_mutex_own()); ut_ad(lock_get_type_low(in_lock) == LOCK_REC); /* We may or may not be holding in_lock->trx->mutex here. */ - trx_lock = &in_lock->trx->lock; - space = in_lock->un_member.rec_lock.space; page_no = in_lock->un_member.rec_lock.page_no; - ut_ad(in_lock->index->table->n_rec_locks > 0); in_lock->index->table->n_rec_locks--; lock_hash = lock_hash_get(in_lock->type_mode); - HASH_DELETE(lock_t, hash, lock_hash, - lock_rec_fold(space, page_no), in_lock); + ulint rec_fold = lock_rec_fold(space, page_no); - UT_LIST_REMOVE(trx_lock->trx_locks, in_lock); + HASH_DELETE(lock_t, hash, lock_hash, rec_fold, in_lock); + UT_LIST_REMOVE(in_lock->trx->lock.trx_locks, in_lock); MONITOR_INC(MONITOR_RECLOCK_REMOVED); MONITOR_DEC(MONITOR_NUM_RECLOCK); if (innodb_lock_schedule_algorithm - == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS || - thd_is_replication_slave_thread(in_lock->trx->mysql_thd)) { - + == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS + || lock_hash != lock_sys.rec_hash + || thd_is_replication_slave_thread(in_lock->trx->mysql_thd)) { /* Check if waiting locks in the queue can now be granted: grant locks if there are no conflicting locks ahead. Stop at the first X lock that is waiting or has been granted. */ - for (lock = lock_rec_get_first_on_page_addr(lock_hash, space, - page_no); - lock != NULL; - lock = lock_rec_get_next_on_page(lock)) { + for (lock_t* lock = lock_rec_get_first_on_page_addr( + lock_hash, space, page_no); + lock != NULL; + lock = lock_rec_get_next_on_page(lock)) { if (lock_get_wait(lock) - && !lock_rec_has_to_wait_in_queue(lock)) { - + && !lock_rec_has_to_wait_in_queue(lock)) { /* Grant the lock */ ut_ad(lock->trx != in_lock->trx); - - bool exit_trx_mutex = false; - - if (lock->trx->abort_type != TRX_SERVER_ABORT) { - ut_ad(trx_mutex_own(lock->trx)); - trx_mutex_exit(lock->trx); - exit_trx_mutex = true; - } - - lock_grant(lock, false); - - if (exit_trx_mutex) { - ut_ad(!trx_mutex_own(lock->trx)); - trx_mutex_enter(lock->trx); - } + lock_grant(lock); } } } else { - lock_grant_and_move_on_page(lock_hash, space, page_no); + lock_grant_and_move_on_page(rec_fold, space, page_no); } } @@ -2902,7 +2314,6 @@ lock_rec_discard( space = in_lock->un_member.rec_lock.space; page_no = in_lock->un_member.rec_lock.page_no; - ut_ad(in_lock->index->table->n_rec_locks > 0); in_lock->index->table->n_rec_locks--; HASH_DELETE(lock_t, hash, lock_hash_get(in_lock->type_mode), @@ -3711,10 +3122,10 @@ lock_update_merge_right( #ifdef UNIV_DEBUG /* there should exist no page lock on the left page, otherwise, it will be blocked from merge */ - ulint space = left_block->page.id.space(); - ulint page_no = left_block->page.id.page_no(); + ulint space = left_block->page.id.space(); + ulint page_no = left_block->page.id.page_no(); ut_ad(lock_rec_get_first_on_page_addr( - lock_sys.prdt_page_hash, space, page_no) == NULL); + lock_sys.prdt_page_hash, space, page_no) == NULL); #endif /* UNIV_DEBUG */ lock_rec_free_all_from_discard_page(left_block); @@ -3886,9 +3297,9 @@ lock_update_discard( const buf_block_t* block) /*!< in: index page which will be discarded */ { + const page_t* page = block->frame; const rec_t* rec; ulint heap_no; - const page_t* page = block->frame; lock_mutex_enter(); @@ -4078,12 +3489,15 @@ UNIV_INLINE lock_t* lock_table_create( /*==============*/ - lock_t* c_lock, /*!< in: conflicting lock or NULL */ dict_table_t* table, /*!< in/out: database table in dictionary cache */ ulint type_mode,/*!< in: lock mode possibly ORed with LOCK_WAIT */ - trx_t* trx) /*!< in: trx */ + trx_t* trx /*!< in: trx */ +#ifdef WITH_WSREP + , lock_t* c_lock = NULL /*!< in: conflicting lock */ +#endif + ) { lock_t* lock; @@ -4127,58 +3541,50 @@ lock_table_create( UT_LIST_ADD_LAST(trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - ut_list_insert(table->locks, c_lock, lock, TableLockGetNode()); - if (wsrep_debug) { - ib::info() << "table lock BF conflict for " << - ib::hex(c_lock->trx->id); - ib::info() << " SQL: " - << wsrep_thd_query(c_lock->trx->mysql_thd); - } - } else { - ut_list_append(table->locks, lock, TableLockGetNode()); - } if (c_lock) { - ut_ad(!trx_mutex_own(c_lock->trx)); - trx_mutex_enter(c_lock->trx); - } + if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + ut_list_insert(table->locks, c_lock, lock, + TableLockGetNode()); + if (wsrep_debug) { + ib::info() << "table lock BF conflict for " + << ib::hex(c_lock->trx->id) + << " SQL: " + << wsrep_thd_query( + c_lock->trx->mysql_thd); + } + } else { + ut_list_append(table->locks, lock, TableLockGetNode()); + } - if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + trx_mutex_enter(c_lock->trx); - if (wsrep_debug) { - wsrep_print_wait_locks(c_lock); - } + if (c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - /* caller has trx_mutex, have to release for lock cancel */ - trx_mutex_exit(trx); - lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); - trx_mutex_enter(trx); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - lock_reset_lock_and_trx_wait(lock); - } + /* The lock release will call lock_grant(), + which would acquire trx->mutex again. */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release( + c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); - if (wsrep_debug) { - ib::info() << "WSREP: c_lock canceled " << ib::hex(c_lock->trx->id); - ib::info() << " SQL: " - << wsrep_thd_query(c_lock->trx->mysql_thd); + if (wsrep_debug) { + ib::info() << "WSREP: c_lock canceled " + << ib::hex(c_lock->trx->id) + << " SQL: " + << wsrep_thd_query( + c_lock->trx->mysql_thd); + } } - } - if (c_lock) { trx_mutex_exit(c_lock->trx); - } -#else - ut_list_append(table->locks, lock, TableLockGetNode()); + } else #endif /* WITH_WSREP */ + ut_list_append(table->locks, lock, TableLockGetNode()); if (type_mode & LOCK_WAIT) { @@ -4192,18 +3598,6 @@ lock_table_create( return(lock); } -UNIV_INLINE -lock_t* -lock_table_create( -/*==============*/ - dict_table_t* table, /*!< in/out: database table - in dictionary cache */ - ulint type_mode,/*!< in: lock mode possibly ORed with - LOCK_WAIT */ - trx_t* trx) /*!< in: trx */ -{ - return (lock_table_create(NULL, table, type_mode, trx)); -} /*************************************************************//** Pops autoinc lock requests from the transaction's autoinc_locks. We @@ -4339,19 +3733,21 @@ lock_table_remove_low( /*********************************************************************//** Enqueues a waiting request for a table lock which cannot be granted immediately. Checks for deadlocks. -@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or -DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another -transaction was chosen as a victim, and we got the lock immediately: -no need to wait then */ +@retval DB_LOCK_WAIT if the waiting lock was enqueued +@retval DB_DEADLOCK if this transaction was chosen as the victim +@retval DB_SUCCESS if the other transaction committed or aborted */ static dberr_t lock_table_enqueue_waiting( /*=======================*/ - lock_t* c_lock, /*!< in: conflicting lock or NULL */ ulint mode, /*!< in: lock mode this transaction is requesting */ dict_table_t* table, /*!< in/out: table */ - que_thr_t* thr) /*!< in: query thread */ + que_thr_t* thr /*!< in: query thread */ +#ifdef WITH_WSREP + , lock_t* c_lock /*!< in: conflicting lock or NULL */ +#endif +) { trx_t* trx; lock_t* lock; @@ -4361,16 +3757,7 @@ lock_table_enqueue_waiting( trx = thr_get_trx(thr); ut_ad(trx_mutex_own(trx)); - - /* Test if there already is some other reason to suspend thread: - we do not enqueue a lock request if the query thread should be - stopped anyway */ - - if (que_thr_stop(thr)) { - ut_error; - - return(DB_QUE_THR_SUSPENDED); - } + ut_a(!que_thr_stop(thr)); switch (trx_get_dict_operation(trx)) { case TRX_DICT_OP_NONE: @@ -4390,7 +3777,11 @@ lock_table_enqueue_waiting( #endif /* WITH_WSREP */ /* Enqueue the lock request that will wait to be granted */ - lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); + lock = lock_table_create(table, mode | LOCK_WAIT, trx +#ifdef WITH_WSREP + , c_lock +#endif + ); const trx_t* victim_trx = DeadlockChecker::check_and_resolve(lock, trx); @@ -4476,7 +3867,7 @@ lock_table_other_has_incompatible( /*********************************************************************//** Locks the specified database table in the mode given. If the lock cannot be granted immediately, the query thread is put to wait. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_table( /*=======*/ @@ -4545,9 +3936,13 @@ lock_table( mode: this trx may have to wait */ if (wait_for != NULL) { - err = lock_table_enqueue_waiting(wait_for, mode | flags, table, thr); + err = lock_table_enqueue_waiting(mode | flags, table, thr +#ifdef WITH_WSREP + , wait_for +#endif + ); } else { - lock_table_create(wait_for, table, mode | flags, trx); + lock_table_create(table, mode | flags, trx); ut_a(!flags || mode == LOCK_S || mode == LOCK_X); @@ -4650,7 +4045,7 @@ lock_table_dequeue( /* Grant the lock */ ut_ad(in_lock->trx != lock->trx); - lock_grant(lock, false); + lock_grant(lock); } } } @@ -4698,32 +4093,8 @@ run_again: } else { que_thr_stop_for_mysql(thr); - if (err != DB_QUE_THR_SUSPENDED) { - bool was_lock_wait; - - was_lock_wait = row_mysql_handle_errors( - &err, trx, thr, NULL); - - if (was_lock_wait) { - goto run_again; - } - } else { - que_thr_t* run_thr; - que_node_t* parent; - - parent = que_node_get_parent(thr); - - run_thr = que_fork_start_command( - static_cast<que_fork_t*>(parent)); - - ut_a(run_thr == thr); - - /* There was a lock wait but the thread was not - in a ready to run or running state. */ - trx->error_state = DB_LOCK_WAIT; - + if (row_mysql_handle_errors(&err, trx, thr, NULL)) { goto run_again; - } } @@ -4776,7 +4147,7 @@ lock_grant_and_move_on_rec( && lock_get_wait(lock) && !lock_rec_has_to_wait_in_queue(lock)) { - lock_grant(lock, false); + lock_grant(lock); if (previous != NULL) { /* Move the lock to the head of the list. */ @@ -4869,7 +4240,7 @@ released: /* Grant the lock */ ut_ad(trx != lock->trx); - lock_grant(lock, false); + lock_grant(lock); } } } else { @@ -4965,7 +4336,7 @@ lock_release( } if (count == LOCK_RELEASE_INTERVAL) { - /* Release the mutex for a while, so that we + /* Release the mutex for a while, so that we do not monopolize it */ lock_mutex_exit(); @@ -5606,22 +4977,20 @@ lock_rec_queue_validate( /* impl_trx cannot be committed until lock_mutex_exit() because lock_trx_release_locks() acquires lock_sys.mutex */ - if (impl_trx != NULL) { - const lock_t* other_lock - = lock_rec_other_has_expl_req( - LOCK_S, block, true, heap_no, - impl_trx); - + if (!impl_trx) { + } else if (const lock_t* other_lock + = lock_rec_other_has_expl_req( + LOCK_S, block, true, heap_no, + impl_trx)) { /* The impl_trx is holding an implicit lock on the given record 'rec'. So there cannot be another explicit granted lock. Also, there can be another explicit waiting lock only if the impl_trx has an explicit granted lock. */ - if (other_lock != NULL) { #ifdef WITH_WSREP - if (wsrep_on(other_lock->trx->mysql_thd) && !lock_get_wait(other_lock) ) { - + if (wsrep_on(other_lock->trx->mysql_thd)) { + if (!lock_get_wait(other_lock) ) { ib::info() << "WSREP impl BF lock conflict for my impl lock:\n BF:" << ((wsrep_thd_is_BF(impl_trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << wsrep_thd_exec_mode(impl_trx->mysql_thd) << " conflict: " << @@ -5639,18 +5008,16 @@ lock_rec_queue_validate( wsrep_thd_query(otrx->mysql_thd); } - if (wsrep_on(other_lock->trx->mysql_thd) && !lock_rec_has_expl( - LOCK_X | LOCK_REC_NOT_GAP, - block, heap_no, impl_trx)) { + if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, + block, heap_no, + impl_trx)) { ib::info() << "WSREP impl BF lock conflict"; } -#else /* !WITH_WSREP */ - ut_a(lock_get_wait(other_lock)); - ut_a(lock_rec_has_expl( - LOCK_X | LOCK_REC_NOT_GAP, - block, heap_no, impl_trx)); + } else #endif /* WITH_WSREP */ - } + ut_ad(lock_get_wait(other_lock)); + ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, + block, heap_no, impl_trx)); } } @@ -5966,7 +5333,7 @@ a record. If they do, first tests if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a gap x-lock to the lock queue. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_rec_insert_check_and_lock( /*===========================*/ @@ -6053,19 +5420,21 @@ lock_rec_insert_check_and_lock( const ulint type_mode = LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION; - lock_t* wait_for = lock_rec_other_has_conflicting( - type_mode, block, heap_no, trx); - - if (wait_for != NULL) { - - RecLock rec_lock(thr, index, block, heap_no, type_mode); - + if ( +#ifdef WITH_WSREP + lock_t* c_lock = +#endif /* WITH_WSREP */ + lock_rec_other_has_conflicting(type_mode, block, heap_no, trx)) { + /* Note that we may get DB_SUCCESS also here! */ trx_mutex_enter(trx); - err = rec_lock.add_to_waitq(wait_for); + err = lock_rec_enqueue_waiting( +#ifdef WITH_WSREP + c_lock, +#endif /* WITH_WSREP */ + type_mode, block, heap_no, index, thr, NULL); trx_mutex_exit(trx); - } else { err = DB_SUCCESS; } @@ -6279,7 +5648,7 @@ first tests if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record x-lock to the lock queue. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_modify_check_and_lock( /*=================================*/ @@ -6332,7 +5701,7 @@ lock_clust_rec_modify_check_and_lock( /*********************************************************************//** Checks if locks of other transactions prevent an immediate modify (delete mark or delete unmark) of a secondary index record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_sec_rec_modify_check_and_lock( /*===============================*/ @@ -6411,8 +5780,7 @@ lock_sec_rec_modify_check_and_lock( /*********************************************************************//** Like lock_clust_rec_read_check_and_lock(), but reads a secondary index record. -@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, -or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_sec_rec_read_check_and_lock( /*=============================*/ @@ -6481,8 +5849,7 @@ if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. -@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, -or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_read_check_and_lock( /*===============================*/ @@ -6548,7 +5915,7 @@ waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. This is an alternative version of lock_clust_rec_read_check_and_lock() that does not require the parameter "offsets". -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_clust_rec_read_check_and_lock_alt( /*===================================*/ @@ -6918,7 +6285,6 @@ lock_unlock_table_autoinc( but not COMMITTED transactions. */ ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED) - || trx_state_eq(trx, TRX_STATE_FORCED_ROLLBACK) || !trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY)); /* This function is invoked for a running transaction by the @@ -7019,6 +6385,23 @@ lock_trx_release_locks( mem_heap_empty(trx->lock.lock_heap); } +static inline dberr_t lock_trx_handle_wait_low(trx_t* trx) +{ + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(trx)); + + if (trx->lock.was_chosen_as_deadlock_victim) { + return DB_DEADLOCK; + } + if (!trx->lock.wait_lock) { + /* The lock was probably granted before we got here. */ + return DB_SUCCESS; + } + + lock_cancel_waiting_and_release(trx->lock.wait_lock); + return DB_LOCK_WAIT; +} + /*********************************************************************//** Check whether the transaction has already been rolled back because it was selected as a deadlock victim, or if it has to wait then cancel @@ -7027,71 +6410,14 @@ the wait lock. dberr_t lock_trx_handle_wait( /*=================*/ - trx_t* trx, /*!< in/out: trx lock state */ - bool lock_mutex_taken, - bool trx_mutex_taken) + trx_t* trx) /*!< in/out: trx lock state */ { - dberr_t err=DB_SUCCESS; - bool take_lock_mutex = false; - bool take_trx_mutex = false; - - if (!lock_mutex_taken) { - ut_ad(!lock_mutex_own()); - lock_mutex_enter(); - take_lock_mutex = true; - } - - if (!trx_mutex_taken) { - ut_ad(!trx_mutex_own(trx)); - trx_mutex_enter(trx); - take_trx_mutex = true; - } - - if (trx->lock.was_chosen_as_deadlock_victim) { - err = DB_DEADLOCK; - } else if (trx->lock.wait_lock != NULL) { - bool take_wait_trx_mutex = false; - trx_t* wait_trx = trx->lock.wait_lock->trx; - - /* We take trx mutex for waiting trx if we have not yet - already taken it or we know that waiting trx and parameter - trx are not same and we are not already holding trx mutex. */ - if ((wait_trx && wait_trx == trx && !take_trx_mutex && !trx_mutex_taken) || - (wait_trx && wait_trx != trx && wait_trx->abort_type == TRX_SERVER_ABORT)) { - ut_ad(!trx_mutex_own(wait_trx)); - trx_mutex_enter(wait_trx); - take_wait_trx_mutex = true; - } - - ut_ad(trx_mutex_own(wait_trx)); - - lock_cancel_waiting_and_release(trx->lock.wait_lock); - - if (wait_trx && take_wait_trx_mutex) { - ut_ad(trx_mutex_own(wait_trx)); - trx_mutex_exit(wait_trx); - } - - err = DB_LOCK_WAIT; - } else { - /* The lock was probably granted before we got here. */ - err = DB_SUCCESS; - } - - if (take_lock_mutex) { - ut_ad(lock_mutex_own()); - lock_mutex_exit(); - } - - if (take_trx_mutex) { - ut_ad(trx_mutex_own(trx)); - trx_mutex_exit(trx); - } - - ut_ad(err == DB_SUCCESS || err == DB_LOCK_WAIT - || err == DB_DEADLOCK); - - return(err); + lock_mutex_enter(); + trx_mutex_enter(trx); + dberr_t err = lock_trx_handle_wait_low(trx); + lock_mutex_exit(); + trx_mutex_exit(trx); + return err; } /*********************************************************************//** @@ -7520,44 +6846,24 @@ DeadlockChecker::select_victim() const ut_ad(m_start->lock.wait_lock != 0); ut_ad(m_wait_lock->trx != m_start); - if (thd_trx_priority(m_start->mysql_thd) > 0 - || thd_trx_priority(m_wait_lock->trx->mysql_thd) > 0) { - - const trx_t* victim; - - victim = trx_arbitrate(m_start, m_wait_lock->trx); - - if (victim != NULL) { - - return(victim); - } - } - if (trx_weight_ge(m_wait_lock->trx, m_start)) { - /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ - #ifdef WITH_WSREP if (wsrep_thd_is_BF(m_start->mysql_thd, TRUE)) { return(m_wait_lock->trx); - } else { -#endif /* WITH_WSREP */ - return(m_start); -#ifdef WITH_WSREP } -#endif +#endif /* WITH_WSREP */ + return(m_start); } #ifdef WITH_WSREP if (wsrep_thd_is_BF(m_wait_lock->trx->mysql_thd, TRUE)) { return(m_start); - } else { -#endif /* WITH_WSREP */ - return(m_wait_lock->trx); -#ifdef WITH_WSREP } -#endif +#endif /* WITH_WSREP */ + + return(m_wait_lock->trx); } /** Looks iteratively for a deadlock. Note: the joining transaction may @@ -7579,7 +6885,6 @@ DeadlockChecker::search() const lock_t* lock = get_first_lock(&heap_no); for (;;) { - /* We should never visit the same sub-tree more than once. */ ut_ad(lock == NULL || !is_visited(lock)); @@ -7594,7 +6899,9 @@ DeadlockChecker::search() if (lock == NULL) { break; - } else if (lock == m_wait_lock) { + } + + if (lock == m_wait_lock) { /* We can mark this subtree as searched */ ut_ad(lock->trx->lock.deadlock_mark <= m_mark_start); @@ -7609,62 +6916,58 @@ DeadlockChecker::search() /* Backtrack */ lock = NULL; + continue; + } - } else if (!lock_has_to_wait(m_wait_lock, lock)) { - + if (!lock_has_to_wait(m_wait_lock, lock)) { /* No conflict, next lock */ lock = get_next_lock(lock, heap_no); + continue; + } - } else if (lock->trx == m_start) { - + if (lock->trx == m_start) { /* Found a cycle. */ - notify(lock); + return select_victim(); + } - return(select_victim()); - - } else if (is_too_deep()) { - + if (is_too_deep()) { /* Search too deep to continue. */ m_too_deep = true; - return(m_start); - - } else { - /* We do not need to report autoinc locks to the upper - layer. These locks are released before commit, so they - can not cause deadlocks with binlog-fixed commit - order. */ - if (m_report_waiters && - (lock_get_type_low(lock) != LOCK_TABLE || - lock_get_mode(lock) != LOCK_AUTO_INC)) { - thd_rpl_deadlock_check(m_start->mysql_thd, - lock->trx->mysql_thd); - } - - if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - /* Another trx ahead has requested a lock in an - incompatible mode, and is itself waiting for a lock. */ + return m_start; + } - ++m_cost; + /* We do not need to report autoinc locks to the upper + layer. These locks are released before commit, so they + can not cause deadlocks with binlog-fixed commit + order. */ + if (m_report_waiters + && (lock_get_type_low(lock) != LOCK_TABLE + || lock_get_mode(lock) != LOCK_AUTO_INC)) { + thd_rpl_deadlock_check(m_start->mysql_thd, + lock->trx->mysql_thd); + } - if (!push(lock, heap_no)) { - m_too_deep = true; - return(m_start); - } + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + /* Another trx ahead has requested a lock in an + incompatible mode, and is itself waiting for a lock. */ + ++m_cost; - m_wait_lock = lock->trx->lock.wait_lock; + if (!push(lock, heap_no)) { + m_too_deep = true; + return m_start; + } - lock = get_first_lock(&heap_no); + m_wait_lock = lock->trx->lock.wait_lock; - if (is_visited(lock)) { - lock = get_next_lock(lock, heap_no); - } + lock = get_first_lock(&heap_no); - } else { + if (is_visited(lock)) { lock = get_next_lock(lock, heap_no); } + } else { + lock = get_next_lock(lock, heap_no); } } @@ -7736,12 +7039,7 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) check_trx_state(trx); ut_ad(!srv_read_only_mode); - /* If transaction is marked for ASYNC rollback then we should - not allow it to wait for another lock causing possible deadlock. - We return current transaction as deadlock victim here. */ - if (trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC) { - return(trx); - } else if (!innobase_deadlock_detect) { + if (!innobase_deadlock_detect) { return(NULL); } @@ -7756,17 +7054,13 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) trx_mutex_exit(trx); const trx_t* victim_trx; - THD* start_mysql_thd; - bool report_waits = false; - - start_mysql_thd = trx->mysql_thd; - - if (start_mysql_thd && thd_need_wait_reports(start_mysql_thd)) - report_waits = true; + const bool report_waiters = trx->mysql_thd + && thd_need_wait_reports(trx->mysql_thd); /* Try and resolve as many deadlocks as possible. */ do { - DeadlockChecker checker(trx, lock, s_lock_mark_counter, report_waits); + DeadlockChecker checker(trx, lock, s_lock_mark_counter, + report_waiters); victim_trx = checker.search(); diff --git a/storage/innobase/lock/lock0prdt.cc b/storage/innobase/lock/lock0prdt.cc index 6f677347eeb..cf88ebbeaa1 100644 --- a/storage/innobase/lock/lock0prdt.cc +++ b/storage/innobase/lock/lock0prdt.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, MariaDB Corporation. 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 @@ -37,6 +38,7 @@ Created 9/7/2013 Jimmy Yang #include "ut0vec.h" #include "btr0btr.h" #include "dict0boot.h" +#include "que0que.h" #include <set> /*********************************************************************//** @@ -494,15 +496,24 @@ lock_prdt_add_to_queue( } } - RecLock rec_lock(index, block, PRDT_HEAPNO, type_mode); + lock = lock_rec_create( +#ifdef WITH_WSREP + NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */ +#endif + type_mode, block, PRDT_HEAPNO, index, trx, + caller_owns_trx_mutex); - return(rec_lock.create(trx, caller_owns_trx_mutex, true, prdt)); + if (lock->type_mode & LOCK_PREDICATE) { + lock_prdt_set_prdt(lock, prdt); + } + + return lock; } /*********************************************************************//** Checks if locks of other transactions prevent an immediate insert of a predicate record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_prdt_insert_check_and_lock( /*============================*/ @@ -564,7 +575,7 @@ lock_prdt_insert_check_and_lock( const ulint mode = LOCK_X | LOCK_PREDICATE | LOCK_INSERT_INTENTION; - lock_t* wait_for = lock_prdt_other_has_conflicting( + const lock_t* wait_for = lock_prdt_other_has_conflicting( mode, block, prdt, trx); if (wait_for != NULL) { @@ -573,16 +584,17 @@ lock_prdt_insert_check_and_lock( /* Allocate MBR on the lock heap */ lock_init_prdt_from_mbr(prdt, mbr, 0, trx->lock.lock_heap); - RecLock rec_lock(thr, index, block, PRDT_HEAPNO, mode); - /* Note that we may get DB_SUCCESS also here! */ - trx_mutex_enter(trx); - err = rec_lock.add_to_waitq(wait_for, prdt); + err = lock_rec_enqueue_waiting( +#ifdef WITH_WSREP + NULL, /* FIXME: replicate SPATIAL INDEX locks */ +#endif + LOCK_X | LOCK_PREDICATE | LOCK_INSERT_INTENTION, + block, PRDT_HEAPNO, index, thr, prdt); trx_mutex_exit(trx); - } else { err = DB_SUCCESS; } @@ -785,7 +797,7 @@ lock_init_prdt_from_mbr( /*********************************************************************//** Acquire a predicate lock on a block -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_prdt_lock( /*===========*/ @@ -830,13 +842,14 @@ lock_prdt_lock( lock_t* lock = lock_rec_get_first_on_page(hash, block); if (lock == NULL) { - - RecLock rec_lock(index, block, PRDT_HEAPNO, prdt_mode); - - lock = rec_lock.create(trx, false, true); + lock = lock_rec_create( +#ifdef WITH_WSREP + NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */ +#endif + mode | type_mode, block, PRDT_HEAPNO, + index, trx, FALSE); status = LOCK_REC_SUCCESS_CREATED; - } else { trx_mutex_enter(trx); @@ -860,12 +873,14 @@ lock_prdt_lock( if (wait_for != NULL) { - RecLock rec_lock( - thr, index, block, PRDT_HEAPNO, - prdt_mode, prdt); - - err = rec_lock.add_to_waitq(wait_for); - + err = lock_rec_enqueue_waiting( +#ifdef WITH_WSREP + NULL, /* FIXME: replicate + SPATIAL INDEX locks */ +#endif + mode | type_mode, + block, PRDT_HEAPNO, + index, thr, prdt); } else { lock_prdt_add_to_queue( @@ -900,7 +915,7 @@ lock_prdt_lock( /*********************************************************************//** Acquire a "Page" lock on a block -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_place_prdt_page_lock( /*======================*/ @@ -946,10 +961,12 @@ lock_place_prdt_page_lock( } if (lock == NULL) { - RecID rec_id(space, page_no, PRDT_HEAPNO); - RecLock rec_lock(index, rec_id, mode); - - rec_lock.create(trx, false, true); + lock = lock_rec_create_low( +#ifdef WITH_WSREP + NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */ +#endif + mode, space, page_no, NULL, PRDT_HEAPNO, + index, trx, FALSE); #ifdef PRDT_DIAG printf("GIS_DIAGNOSTIC: page lock %d\n", (int) page_no); @@ -1011,7 +1028,8 @@ lock_prdt_rec_move( const ulint type_mode = lock->type_mode; lock_prdt_t* lock_prdt = lock_get_prdt_from_lock(lock); - lock_rec_trx_wait(lock, PRDT_HEAPNO, type_mode); + lock_rec_reset_nth_bit(lock, PRDT_HEAPNO); + lock_reset_lock_and_trx_wait(lock); lock_prdt_add_to_queue( type_mode, receiver, lock->index, lock->trx, @@ -1049,4 +1067,3 @@ lock_prdt_page_free_from_discard( lock = next_lock; } } - diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc index b2ed634e2a4..6ce9e843a43 100644 --- a/storage/innobase/lock/lock0wait.cc +++ b/storage/innobase/lock/lock0wait.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2017, MariaDB Corporation. +Copyright (c) 2014, 2018, MariaDB Corporation. 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 @@ -419,7 +419,7 @@ lock_wait_suspend_thread( && (!wsrep_on_trx(trx) || (!wsrep_is_BF_lock_timeout(trx, false) && trx->error_state != DB_DEADLOCK)) #endif /* WITH_WSREP */ - && !trx_is_high_priority(trx)) { + ) { trx->error_state = DB_LOCK_WAIT_TIMEOUT; @@ -502,7 +502,7 @@ lock_wait_check_and_cancel( trx_mutex_enter(trx); - if (trx->lock.wait_lock != NULL && !trx_is_high_priority(trx)) { + if (trx->lock.wait_lock != NULL) { ut_a(trx->lock.que_state == TRX_QUE_LOCK_WAIT); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 5be52ec0696..e483162d563 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -141,12 +141,23 @@ struct file_name_t { std::string name; /** Tablespace object (NULL if not valid or not found) */ fil_space_t* space; - /** Whether the tablespace has been deleted */ - bool deleted; + + /** Tablespace status. */ + enum fil_status { + /** Normal tablespace */ + NORMAL, + /** Deleted tablespace */ + DELETED, + /** Missing tablespace */ + MISSING + }; + + /** Status of the tablespace */ + fil_status status; /** Constructor */ - file_name_t(std::string name_, bool deleted_) : - name(name_), space(NULL), deleted (deleted_) {} + file_name_t(std::string name_, bool deleted) : + name(name_), space(NULL), status(deleted ? DELETED: NORMAL) {} }; /** Map of dirty tablespaces during recovery */ @@ -158,6 +169,10 @@ typedef std::map< static recv_spaces_t recv_spaces; +/** Backup function checks whether the space id belongs to +the skip table list given in the mariabackup option. */ +bool(*check_if_backup_includes)(ulint space_id); + /** Process a file name from a MLOG_FILE_* record. @param[in,out] name file name @param[in] len length of the file name @@ -173,6 +188,14 @@ fil_name_process( ulint space_id, bool deleted) { + if (srv_operation == SRV_OPERATION_BACKUP) { + return true; + } + + ut_ad(srv_operation == SRV_OPERATION_NORMAL + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT); + bool processed = true; /* We will also insert space=NULL into the map, so that @@ -190,8 +213,8 @@ fil_name_process( if (deleted) { /* Got MLOG_FILE_DELETE */ - if (!p.second && !f.deleted) { - f.deleted = true; + if (!p.second && f.status != file_name_t::DELETED) { + f.status = file_name_t::DELETED; if (f.space != NULL) { fil_space_free(space_id, false); f.space = NULL; @@ -214,7 +237,7 @@ fil_name_process( if (f.space == NULL || f.space == space) { f.name = fname.name; f.space = space; - f.deleted = false; + f.status = file_name_t::NORMAL; } else { ib::error() << "Tablespace " << space_id << " has been found in two places: '" @@ -560,7 +583,6 @@ recv_sys_init() recv_sys->addr_hash = hash_create(size / 512); recv_sys->progress_time = ut_time(); - recv_max_page_lsn = 0; /* Call the constructor for recv_sys_t::dblwr member */ @@ -2233,30 +2255,14 @@ recv_report_corrupt_log( return(true); } -/** Whether to store redo log records to the hash table */ -enum store_t { - /** Do not store redo log records. */ - STORE_NO, - /** Store redo log records. */ - STORE_YES, - /** Store redo log records if the tablespace exists. */ - STORE_IF_EXISTS -}; - /** Parse log records from a buffer and optionally store them to a hash table to wait merging to file pages. @param[in] checkpoint_lsn the LSN of the latest checkpoint @param[in] store whether to store page operations @param[in] apply whether to apply the records -@param[out] err DB_SUCCESS or error code @return whether MLOG_CHECKPOINT record was seen the first time, or corruption was noticed */ -static MY_ATTRIBUTE((warn_unused_result)) -bool -recv_parse_log_recs( - lsn_t checkpoint_lsn, - store_t store, - bool apply) +bool recv_parse_log_recs(lsn_t checkpoint_lsn, store_t store, bool apply) { byte* ptr; byte* end_ptr; @@ -2396,11 +2402,14 @@ loop: } /* fall through */ case MLOG_INDEX_LOAD: - /* Mariabackup FIXME: Report an error - when encountering MLOG_INDEX_LOAD on - --prepare or already on --backup. */ - ut_a(type != MLOG_INDEX_LOAD - || srv_operation == SRV_OPERATION_NORMAL); + if (type == MLOG_INDEX_LOAD) { + if (check_if_backup_includes + && !check_if_backup_includes(space)) { + ut_ad(srv_operation + == SRV_OPERATION_BACKUP); + return true; + } + } /* fall through */ case MLOG_FILE_NAME: case MLOG_FILE_DELETE: @@ -2588,17 +2597,13 @@ loop: goto loop; } -/*******************************************************//** -Adds data from a new log block to the parsing buffer of recv_sys if +/** Adds data from a new log block to the parsing buffer of recv_sys if recv_sys->parse_start_lsn is non-zero. +@param[in] log_block log block to add +@param[in] scanned_lsn lsn of how far we were able to find + data in this log block @return true if more data added */ -static -bool -recv_sys_add_to_parsing_buf( -/*========================*/ - const byte* log_block, /*!< in: log block */ - lsn_t scanned_lsn) /*!< in: lsn of how far we were able - to find data in this log block */ +bool recv_sys_add_to_parsing_buf(const byte* log_block, lsn_t scanned_lsn) { ulint more_len; ulint data_len; @@ -2663,12 +2668,8 @@ recv_sys_add_to_parsing_buf( return(true); } -/*******************************************************//** -Moves the parsing buffer data left to the buffer start. */ -static -void -recv_sys_justify_left_parsing_buf(void) -/*===================================*/ +/** Moves the parsing buffer data left to the buffer start. */ +void recv_sys_justify_left_parsing_buf() { ut_memmove(recv_sys->buf, recv_sys->buf + recv_sys->recovered_offset, recv_sys->len - recv_sys->recovered_offset); @@ -2851,6 +2852,12 @@ recv_scan_log_recs( if (*store_to_hash != STORE_NO && mem_heap_get_size(recv_sys->heap) > available_memory) { + + DBUG_PRINT("ib_log", ("Ran out of memory and last " + "stored lsn " LSN_PF, + recv_sys->recovered_lsn)); + + recv_sys->last_stored_lsn = recv_sys->recovered_lsn; *store_to_hash = STORE_NO; } @@ -2983,15 +2990,99 @@ recv_init_missing_space(dberr_t err, const recv_spaces_t::const_iterator& i) return(err); } +/** Report the missing tablespace and discard the redo logs for the deleted +tablespace. +@param[in] rescan rescan of redo logs is needed + if hash table ran out of memory +@param[out] missing_tablespace missing tablespace exists or not +@return error code or DB_SUCCESS. */ +static MY_ATTRIBUTE((warn_unused_result)) +dberr_t +recv_validate_tablespace(bool rescan, bool& missing_tablespace) +{ + dberr_t err = DB_SUCCESS; + + for (ulint h = 0; h < hash_get_n_cells(recv_sys->addr_hash); h++) { + + for (recv_addr_t* recv_addr = static_cast<recv_addr_t*>( + HASH_GET_FIRST(recv_sys->addr_hash, h)); + recv_addr != 0; + recv_addr = static_cast<recv_addr_t*>( + HASH_GET_NEXT(addr_hash, recv_addr))) { + + const ulint space = recv_addr->space; + + if (is_predefined_tablespace(space)) { + continue; + } + + recv_spaces_t::iterator i + = recv_spaces.find(space); + ut_ad(i != recv_spaces.end()); + + switch(i->second.status) { + case file_name_t::MISSING: + err = recv_init_missing_space(err, i); + i->second.status = file_name_t::DELETED; + case file_name_t::DELETED: + recv_addr->state = RECV_DISCARDED; + case file_name_t::NORMAL: + break; + default: + ut_ad(0); + } + } + } + + if (err != DB_SUCCESS) { + return(err); + } + + /* When rescan is not needed then recv_sys->addr_hash will have + all space id belongs to redo log. If rescan is needed and + innodb_force_recovery > 0 then InnoDB can ignore missing tablespace. */ + for (recv_spaces_t::iterator i = recv_spaces.begin(); + i != recv_spaces.end(); i++) { + + if (i->second.status != file_name_t::MISSING) { + continue; + } + + missing_tablespace = true; + + if (srv_force_recovery > 0) { + ib::warn() << "Tablespace " << i->first + <<" was not found at " << i->second.name + <<", and innodb_force_recovery was set." + <<" All redo log for this tablespace" + <<" will be ignored!"; + continue; + } + + if (!rescan) { + ib::info() << "Tablespace " << i->first + << " was not found at '" + << i->second.name << "', but there" + <<" were no modifications either."; + } + } + + if (!rescan || srv_force_recovery > 0) { + missing_tablespace = false; + } + + return DB_SUCCESS; +} + /** Check if all tablespaces were found for crash recovery. +@param[in] rescan rescan of redo logs is needed +@param[out] missing_tablespace missing table exists @return error code or DB_SUCCESS */ static MY_ATTRIBUTE((warn_unused_result)) dberr_t -recv_init_crash_recovery_spaces() +recv_init_crash_recovery_spaces(bool rescan, bool& missing_tablespace) { - typedef std::set<ulint> space_set_t; bool flag_deleted = false; - space_set_t missing_spaces; ut_ad(!srv_read_only_mode); ut_ad(recv_needed_recovery); @@ -2999,9 +3090,9 @@ recv_init_crash_recovery_spaces() for (recv_spaces_t::iterator i = recv_spaces.begin(); i != recv_spaces.end(); i++) { ut_ad(!is_predefined_tablespace(i->first)); - ut_ad(!i->second.deleted || !i->second.space); + ut_ad(i->second.status != file_name_t::DELETED || !i->second.space); - if (i->second.deleted) { + if (i->second.status == file_name_t::DELETED) { /* The tablespace was deleted, so we can ignore any redo log for it. */ flag_deleted = true; @@ -3017,84 +3108,18 @@ recv_init_crash_recovery_spaces() recv_sys->found_corrupt_log = true; return(DB_CORRUPTION); } else { - missing_spaces.insert(i->first); + i->second.status = file_name_t::MISSING; flag_deleted = true; } - ut_ad(i->second.deleted || i->second.name != ""); + ut_ad(i->second.status == file_name_t::DELETED || i->second.name != ""); } if (flag_deleted) { - dberr_t err = DB_SUCCESS; - - for (ulint h = 0; - h < hash_get_n_cells(recv_sys->addr_hash); - h++) { - for (recv_addr_t* recv_addr - = static_cast<recv_addr_t*>( - HASH_GET_FIRST( - recv_sys->addr_hash, h)); - recv_addr != 0; - recv_addr = static_cast<recv_addr_t*>( - HASH_GET_NEXT(addr_hash, recv_addr))) { - const ulint space = recv_addr->space; - - if (is_predefined_tablespace(space)) { - continue; - } - - recv_spaces_t::iterator i - = recv_spaces.find(space); - ut_ad(i != recv_spaces.end()); - - if (i->second.deleted) { - ut_ad(missing_spaces.find(space) - == missing_spaces.end()); - recv_addr->state = RECV_DISCARDED; - continue; - } - - space_set_t::iterator m = missing_spaces.find( - space); - - if (m != missing_spaces.end()) { - missing_spaces.erase(m); - err = recv_init_missing_space(err, i); - recv_addr->state = RECV_DISCARDED; - /* All further redo log for this - tablespace should be removed. */ - i->second.deleted = true; - } - } - } - - if (err != DB_SUCCESS) { - return(err); - } - } - - for (space_set_t::const_iterator m = missing_spaces.begin(); - m != missing_spaces.end(); m++) { - recv_spaces_t::iterator i = recv_spaces.find(*m); - ut_ad(i != recv_spaces.end()); - - ib::info() << "Tablespace " << i->first - << " was not found at '" << i->second.name - << "', but there were no modifications either."; + return recv_validate_tablespace(rescan, missing_tablespace); } - if (srv_operation == SRV_OPERATION_NORMAL) { - buf_dblwr_process(); - } - - if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { - /* Spawn the background thread to flush dirty pages - from the buffer pools. */ - recv_writer_thread_active = true; - os_thread_create(recv_writer_thread, 0, 0); - } - - return(DB_SUCCESS); + return DB_SUCCESS; } /** Start recovering from a redo log checkpoint. @@ -3268,13 +3293,57 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) log_sys->lsn = recv_sys->recovered_lsn; if (recv_needed_recovery) { - err = recv_init_crash_recovery_spaces(); + bool missing_tablespace = false; + + err = recv_init_crash_recovery_spaces( + rescan, missing_tablespace); if (err != DB_SUCCESS) { log_mutex_exit(); return(err); } + /* If there is any missing tablespace and rescan is needed + then there is a possiblity that hash table will not contain + all space ids redo logs. Rescan the remaining unstored + redo logs for the validation of missing tablespace. */ + while (missing_tablespace) { + DBUG_PRINT("ib_log", ("Rescan of redo log to validate " + "the missing tablespace. Scan " + "from last stored LSN " LSN_PF, + recv_sys->last_stored_lsn)); + + lsn_t recent_stored_lsn = recv_sys->last_stored_lsn; + rescan = recv_group_scan_log_recs( + group, checkpoint_lsn, + &recent_stored_lsn, false); + + ut_ad(!recv_sys->found_corrupt_fs); + + missing_tablespace = false; + + err = recv_sys->found_corrupt_log + ? DB_ERROR + : recv_validate_tablespace( + rescan, missing_tablespace); + + if (err != DB_SUCCESS) { + log_mutex_exit(); + return err; + } + } + + if (srv_operation == SRV_OPERATION_NORMAL) { + buf_dblwr_process(); + } + + ut_ad(srv_force_recovery <= SRV_FORCE_NO_UNDO_LOG_SCAN); + + /* Spawn the background thread to flush dirty pages + from the buffer pools. */ + recv_writer_thread_active = true; + os_thread_create(recv_writer_thread, 0, 0); + if (rescan) { contiguous_lsn = checkpoint_lsn; diff --git a/storage/innobase/mem/mem0mem.cc b/storage/innobase/mem/mem0mem.cc index b4a4e8eec4a..f101d624e88 100644 --- a/storage/innobase/mem/mem0mem.cc +++ b/storage/innobase/mem/mem0mem.cc @@ -323,6 +323,11 @@ mem_heap_create_block_func( heap->total_size += len; } + /* Poison all available memory. Individual chunks will be unpoisoned on + every mem_heap_alloc() call. */ + compile_time_assert(MEM_BLOCK_HEADER_SIZE >= sizeof *block); + UNIV_MEM_FREE(block + 1, len - sizeof *block); + ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len); return(block); diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 0f82dea9c99..69469f787dc 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -701,28 +701,50 @@ static bool os_aio_validate(); +/** Handle errors for file operations. +@param[in] name name of a file or NULL +@param[in] operation operation +@param[in] should_abort whether to abort on an unknown error +@param[in] on_error_silent whether to suppress reports of non-fatal errors +@return true if we should retry the operation */ +static MY_ATTRIBUTE((warn_unused_result)) +bool +os_file_handle_error_cond_exit( + const char* name, + const char* operation, + bool should_abort, + bool on_error_silent); + /** Does error handling when a file operation fails. -@param[in] name File name or NULL -@param[in] operation Name of operation e.g., "read", "write" +@param[in] name name of a file or NULL +@param[in] operation operation name that failed @return true if we should retry the operation */ static bool os_file_handle_error( const char* name, - const char* operation); + const char* operation) +{ + /* Exit in case of unknown error */ + return(os_file_handle_error_cond_exit(name, operation, true, false)); +} -/** -Does error handling when a file operation fails. -@param[in] name File name or NULL -@param[in] operation Name of operation e.g., "read", "write" -@param[in] silent if true then don't print any message to the log. +/** Does error handling when a file operation fails. +@param[in] name name of a file or NULL +@param[in] operation operation name that failed +@param[in] on_error_silent if true then don't print any message to the log. @return true if we should retry the operation */ static bool os_file_handle_error_no_exit( const char* name, const char* operation, - bool silent); + bool on_error_silent) +{ + /* Don't exit in case of unknown error */ + return(os_file_handle_error_cond_exit( + name, operation, false, on_error_silent)); +} /** Does simulated AIO. This function should be called by an i/o-handler thread. @@ -2253,7 +2275,7 @@ AIO::is_linux_native_aio_supported() strcpy(name + dirnamelen, "ib_logfile0"); - fd = open(name, O_RDONLY); + fd = open(name, O_RDONLY | O_CLOEXEC); if (fd == -1) { @@ -5025,52 +5047,31 @@ os_file_read_page( ut_ad(type.validate()); ut_ad(n > 0); - for (;;) { - ssize_t n_bytes; - - n_bytes = os_file_pread(type, file, buf, n, offset, &err); - - if (o != NULL) { - *o = n_bytes; - } - - if (err != DB_SUCCESS && !exit_on_err) { - - return(err); - - } else if ((ulint) n_bytes == n) { - return(DB_SUCCESS); - } - - ib::error() << "Tried to read " << n - << " bytes at offset " << offset - << ", but was only able to read " << n_bytes; - - if (exit_on_err) { + ssize_t n_bytes = os_file_pread(type, file, buf, n, offset, &err); - if (!os_file_handle_error(NULL, "read")) { - /* Hard error */ - break; - } + if (o) { + *o = n_bytes; + } - } else if (!os_file_handle_error_no_exit(NULL, "read", false)) { + if (ulint(n_bytes) == n || (err != DB_SUCCESS && !exit_on_err)) { + return err; + } - /* Hard error */ - break; - } + ib::error() << "Tried to read " << n << " bytes at offset " + << offset << ", but was only able to read " << n_bytes; - if (n_bytes > 0 && (ulint) n_bytes < n) { - n -= (ulint) n_bytes; - offset += (ulint) n_bytes; - buf = reinterpret_cast<uchar*>(buf) + (ulint) n_bytes; - } + if (!os_file_handle_error_cond_exit( + NULL, "read", exit_on_err, false)) { + ib::fatal() + << "Cannot read from file. OS error number " + << errno << "."; } - ib::fatal() - << "Cannot read from file. OS error number " - << errno << "."; + if (err == DB_SUCCESS) { + err = DB_IO_ERROR; + } - return(err); + return err; } /** Retrieves the last error number if an error occurs in a file io function. @@ -5176,37 +5177,6 @@ os_file_handle_error_cond_exit( return(false); } -/** Does error handling when a file operation fails. -@param[in] name name of a file or NULL -@param[in] operation operation name that failed -@return true if we should retry the operation */ -static -bool -os_file_handle_error( - const char* name, - const char* operation) -{ - /* Exit in case of unknown error */ - return(os_file_handle_error_cond_exit(name, operation, true, false)); -} - -/** Does error handling when a file operation fails. -@param[in] name name of a file or NULL -@param[in] operation operation name that failed -@param[in] on_error_silent if true then don't print any message to the log. -@return true if we should retry the operation */ -static -bool -os_file_handle_error_no_exit( - const char* name, - const char* operation, - bool on_error_silent) -{ - /* Don't exit in case of unknown error */ - return(os_file_handle_error_cond_exit( - name, operation, false, on_error_silent)); -} - #ifndef _WIN32 /** Tries to disable OS caching on an opened file descriptor. @param[in] fd file descriptor to alter diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index db85b09631e..559b7d06145 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -35,6 +35,7 @@ Created 2/2/1994 Heikki Tuuri #include "lock0lock.h" #include "fut0lst.h" #include "btr0sea.h" +#include "trx0sys.h" /* THE INDEX PAGE ============== diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 4ef37b81c29..5a1643c5a1d 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -45,6 +45,7 @@ const byte field_ref_zero[FIELD_REF_SIZE] = { #include "btr0cur.h" #include "page0types.h" #include "log0recv.h" +#include "row0row.h" #include "row0trunc.h" #include "zlib.h" #include "buf0buf.h" diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 6caffb8f0ab..acaffa6c2ae 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -36,6 +36,7 @@ Created 2012-02-08 by Sunny Bains. #include "row0mysql.h" #include "srv0start.h" #include "row0quiesce.h" +#include "fil0pagecompress.h" #include "trx0undo.h" #include "ut0new.h" @@ -45,12 +46,10 @@ Created 2012-02-08 by Sunny Bains. #include <my_aes.h> #endif -/** The size of the buffer to use for IO. Note: os_file_read() doesn't expect -reads to fail. If you set the buffer size to be greater than a multiple of the -file size then it will assert. TODO: Fix this limitation of the IO functions. -@param n page size of the tablespace. -@retval number of pages */ -#define IO_BUFFER_SIZE(m, n) ((m) / (n)) +/** The size of the buffer to use for IO. +@param n physical page size +@return number of pages */ +#define IO_BUFFER_SIZE(n) ((1024 * 1024) / n) /** For gathering stats on records during phase I */ struct row_stats_t { @@ -346,12 +345,14 @@ private: /** Functor that is called for each physical page that is read from the tablespace file. */ -class AbstractCallback : public PageCallback { +class AbstractCallback +{ public: /** Constructor @param trx covering transaction */ AbstractCallback(trx_t* trx) : + m_page_size(0, 0, false), m_trx(trx), m_space(ULINT_UNDEFINED), m_xdes(), @@ -384,31 +385,50 @@ public: return(m_space_flags); } -protected: - /** Get the data page depending on the table type, compressed or not. - @param block block read from disk - @retval the buffer frame */ - buf_frame_t* get_frame(buf_block_t* block) const UNIV_NOTHROW + /** + Set the name of the physical file and the file handle that is used + to open it for the file that is being iterated over. + @param filename the physical name of the tablespace file + @param file OS file handle */ + void set_file(const char* filename, pfs_os_file_t file) UNIV_NOTHROW { - if (is_compressed_table()) { - return(block->page.zip.data); - } - - return(buf_block_get_frame(block)); + m_file = file; + m_filepath = filename; } - /** Check for session interrupt. If required we could - even flush to disk here every N pages. - @retval DB_SUCCESS or error code */ - dberr_t periodic_check() UNIV_NOTHROW - { - if (trx_is_interrupted(m_trx)) { - return(DB_INTERRUPTED); - } + const page_size_t& get_page_size() const { return m_page_size; } - return(DB_SUCCESS); + const char* filename() const { return m_filepath; } + + /** + Called for every page in the tablespace. If the page was not + updated then its state must be set to BUF_PAGE_NOT_USED. For + compressed tables the page descriptor memory will be at offset: + block->frame + UNIV_PAGE_SIZE; + @param offset - physical offset within the file + @param block - block read from file, note it is not from the buffer pool + @retval DB_SUCCESS or error code. */ + virtual dberr_t operator()( + os_offset_t offset, + buf_block_t* block) UNIV_NOTHROW = 0; + + /** + @return the space id of the tablespace */ + virtual ulint get_space_id() const UNIV_NOTHROW = 0; + + bool is_interrupted() const { return trx_is_interrupted(m_trx); } + + /** + Get the data page depending on the table type, compressed or not. + @param block - block read from disk + @retval the buffer frame */ + static byte* get_frame(const buf_block_t* block) + { + return block->page.zip.data + ? block->page.zip.data : block->frame; } +protected: /** Get the physical offset of the extent descriptor within the page. @param page_no page number of the extent descriptor @param page contents of the page containing the extent descriptor. @@ -488,6 +508,15 @@ protected: } protected: + /** The tablespace page size. */ + page_size_t m_page_size; + + /** File handle to the tablespace */ + pfs_os_file_t m_file; + + /** Physical file path. */ + const char* m_filepath; + /** Covering transaction. */ trx_t* m_trx; @@ -564,9 +593,7 @@ AbstractCallback::init( m_free_limit = mach_read_from_4(page + FSP_FREE_LIMIT); m_space = mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID); - dberr_t err = set_current_xdes(0, page); - - return(err); + return set_current_xdes(0, page); } /** @@ -637,11 +664,7 @@ FetchIndexRootPages::operator() ( os_offset_t offset, buf_block_t* block) UNIV_NOTHROW { - dberr_t err; - - if ((err = periodic_check()) != DB_SUCCESS) { - return(err); - } + if (is_interrupted()) return DB_INTERRUPTED; const page_t* page = get_frame(block); @@ -654,9 +677,9 @@ FetchIndexRootPages::operator() ( << ", file offset: " << (offset / m_page_size.physical()); - err = DB_CORRUPTION; + return DB_CORRUPTION; } else if (page_type == FIL_PAGE_TYPE_XDES) { - err = set_current_xdes(block->page.id.page_no(), page); + return set_current_xdes(block->page.id.page_no(), page); } else if (fil_page_index_page_check(page) && !is_free(block->page.id.page_no()) && page_is_root(page)) { @@ -680,7 +703,7 @@ FetchIndexRootPages::operator() ( } } - return(err); + return DB_SUCCESS; } /** @@ -808,14 +831,6 @@ public: os_offset_t offset, buf_block_t* block) UNIV_NOTHROW; private: - - /** Status returned by PageConverter::validate() */ - enum import_page_status_t { - IMPORT_PAGE_STATUS_OK, /*!< Page is OK */ - IMPORT_PAGE_STATUS_ALL_ZERO, /*!< Page is all zeros */ - IMPORT_PAGE_STATUS_CORRUPTED /*!< Page is corrupted */ - }; - /** Update the page, set the space id, max trx id and index id. @param block block read from file @param page_type type of the page @@ -824,17 +839,6 @@ private: buf_block_t* block, ulint& page_type) UNIV_NOTHROW; -#ifdef UNIV_DEBUG - /** - @return true error condition is enabled. */ - bool trigger_corruption() UNIV_NOTHROW - { - return(false); - } - #else -#define trigger_corruption() (false) -#endif /* UNIV_DEBUG */ - /** Update the space, index id, trx id. @param block block to convert @return DB_SUCCESS or error code */ @@ -846,14 +850,6 @@ private: @retval DB_SUCCESS or error code */ dberr_t update_records(buf_block_t* block) UNIV_NOTHROW; - /** Validate the page, check for corruption. - @param offset physical offset within file. - @param page page read from file. - @return 0 on success, 1 if all zero, 2 if corrupted */ - import_page_status_t validate( - os_offset_t offset, - buf_block_t* page) UNIV_NOTHROW; - /** Validate the space flags and update tablespace header page. @param block block read from file, not from the buffer pool. @retval DB_SUCCESS or error code */ @@ -1537,6 +1533,7 @@ IndexPurge::purge() UNIV_NOTHROW /** Constructor @param cfg config of table being imported. @param trx transaction covering the import */ +inline PageConverter::PageConverter( row_import* cfg, trx_t* trx) @@ -1560,6 +1557,7 @@ PageConverter::PageConverter( @param offsets column offsets for the record @param i column ordinal value @return DB_SUCCESS or error code */ +inline dberr_t PageConverter::adjust_cluster_index_blob_column( rec_t* rec, @@ -1588,13 +1586,11 @@ PageConverter::adjust_cluster_index_blob_column( field += BTR_EXTERN_SPACE_ID - BTR_EXTERN_FIELD_REF_SIZE + len; - if (is_compressed_table()) { - mach_write_to_4(field, get_space_id()); + mach_write_to_4(field, get_space_id()); + if (m_page_zip_ptr) { page_zip_write_blob_ptr( m_page_zip_ptr, rec, m_cluster_index, offsets, i, 0); - } else { - mlog_write_ulint(field, get_space_id(), MLOG_4BYTES, 0); } return(DB_SUCCESS); @@ -1605,6 +1601,7 @@ stored columns. @param rec record to update @param offsets column offsets for the record @return DB_SUCCESS or error code */ +inline dberr_t PageConverter::adjust_cluster_index_blob_columns( rec_t* rec, @@ -1637,6 +1634,7 @@ BLOB reference, write the new space id. @param rec record to update @param offsets column offsets for the record @return DB_SUCCESS or error code */ +inline dberr_t PageConverter::adjust_cluster_index_blob_ref( rec_t* rec, @@ -1659,6 +1657,7 @@ PageConverter::adjust_cluster_index_blob_ref( re-organising the B+tree. @param offsets current row offsets. @return true if purge succeeded */ +inline bool PageConverter::purge(const ulint* offsets) UNIV_NOTHROW { @@ -1681,6 +1680,7 @@ PageConverter::purge(const ulint* offsets) UNIV_NOTHROW @param rec record to update @param offsets column offsets for the record @return DB_SUCCESS or error code. */ +inline dberr_t PageConverter::adjust_cluster_record( const dict_index_t* index, @@ -1717,6 +1717,7 @@ PageConverter::adjust_cluster_record( rows that can't be purged optimistically. @param block block to update @retval DB_SUCCESS or error code */ +inline dberr_t PageConverter::update_records( buf_block_t* block) UNIV_NOTHROW @@ -1780,6 +1781,7 @@ PageConverter::update_records( /** Update the space, index id, trx id. @return DB_SUCCESS or error code */ +inline dberr_t PageConverter::update_index_page( buf_block_t* block) UNIV_NOTHROW @@ -1867,6 +1869,7 @@ PageConverter::update_index_page( /** Validate the space flags and update tablespace header page. @param block block read from file, not from the buffer pool. @retval DB_SUCCESS or error code */ +inline dberr_t PageConverter::update_header( buf_block_t* block) UNIV_NOTHROW @@ -1903,6 +1906,7 @@ PageConverter::update_header( /** Update the page, set the space id, max trx id and index id. @param block block read from file @retval DB_SUCCESS or error code */ +inline dberr_t PageConverter::update_page( buf_block_t* block, @@ -1910,6 +1914,14 @@ PageConverter::update_page( { dberr_t err = DB_SUCCESS; + ut_ad(!block->page.zip.data == !is_compressed_table()); + + if (block->page.zip.data) { + m_page_zip_ptr = &block->page.zip; + } else { + ut_ad(!m_page_zip_ptr); + } + switch (page_type = fil_page_get_type(get_frame(block))) { case FIL_PAGE_TYPE_FSP_HDR: ut_a(block->page.id.page_no() == 0); @@ -1966,117 +1978,41 @@ PageConverter::update_page( return(DB_CORRUPTION); } -/** Validate the page -@param offset physical offset within file. -@param page page read from file. -@return status */ -PageConverter::import_page_status_t -PageConverter::validate( - os_offset_t offset, - buf_block_t* block) UNIV_NOTHROW -{ - buf_frame_t* page = get_frame(block); - - /* Check that the page number corresponds to the offset in - the file. Flag as corrupt if it doesn't. Disable the check - for LSN in buf_page_is_corrupted() */ - - if (buf_page_is_corrupted( - false, page, get_page_size(), NULL) - || (page_get_page_no(page) != offset / m_page_size.physical() - && page_get_page_no(page) != 0)) { - - return(IMPORT_PAGE_STATUS_CORRUPTED); - - } else if (offset > 0 && page_get_page_no(page) == 0) { - - /* The page is all zero: do nothing. We already checked - for all NULs in buf_page_is_corrupted() */ - return(IMPORT_PAGE_STATUS_ALL_ZERO); - } - - return(IMPORT_PAGE_STATUS_OK); -} - /** Called for every page in the tablespace. If the page was not updated then its state must be set to BUF_PAGE_NOT_USED. -@param offset physical offset within the file @param block block read from file, note it is not from the buffer pool @retval DB_SUCCESS or error code. */ dberr_t -PageConverter::operator() ( - os_offset_t offset, - buf_block_t* block) UNIV_NOTHROW +PageConverter::operator() (os_offset_t, buf_block_t* block) UNIV_NOTHROW { + /* If we already had an old page with matching number + in the buffer pool, evict it now, because + we no longer evict the pages on DISCARD TABLESPACE. */ + buf_page_get_gen(block->page.id, get_page_size(), + RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL, + __FILE__, __LINE__, NULL, NULL); + ulint page_type; - dberr_t err = DB_SUCCESS; - if ((err = periodic_check()) != DB_SUCCESS) { - return(err); - } + dberr_t err = update_page(block, page_type); + if (err != DB_SUCCESS) return err; - if (is_compressed_table()) { - m_page_zip_ptr = &block->page.zip; + if (!block->page.zip.data) { + buf_flush_init_for_writing( + NULL, block->frame, NULL, m_current_lsn); + } else if (fil_page_type_is_index(page_type)) { + buf_flush_init_for_writing( + NULL, block->page.zip.data, &block->page.zip, + m_current_lsn); } else { - ut_ad(m_page_zip_ptr == 0); + /* Calculate and update the checksum of non-index + pages for ROW_FORMAT=COMPRESSED tables. */ + buf_flush_update_zip_checksum( + block->page.zip.data, get_page_size().physical(), + m_current_lsn); } - switch (validate(offset, block)) { - case IMPORT_PAGE_STATUS_OK: - - /* We have to decompress the compressed pages before - we can work on them */ - - if ((err = update_page(block, page_type)) != DB_SUCCESS) { - break; - } - - /* Note: For compressed pages this function will write to the - zip descriptor and for uncompressed pages it will write to - page (ie. the block->frame). Therefore the caller should write - out the descriptor contents and not block->frame for compressed - pages. */ - - if (!is_compressed_table() - || fil_page_type_is_index(page_type)) { - - buf_flush_init_for_writing( - !is_compressed_table() ? block : NULL, - !is_compressed_table() - ? block->frame : block->page.zip.data, - !is_compressed_table() ? 0 : m_page_zip_ptr, - m_current_lsn); - } else { - /* Calculate and update the checksum of non-btree - pages for compressed tables explicitly here. */ - - buf_flush_update_zip_checksum( - get_frame(block), get_page_size().physical(), - m_current_lsn); - } - - break; - - case IMPORT_PAGE_STATUS_ALL_ZERO: - /* The page is all zero: leave it as is. */ - break; - - case IMPORT_PAGE_STATUS_CORRUPTED: - - ib::warn() << "Page " << (offset / m_page_size.physical()) - << " at offset " << offset - << " looks corrupted in file " << m_filepath; - - err = DB_CORRUPTION; - } - - /* If we already had and old page with matching number - in the buffer pool, evict it now, because - we no longer evict the pages on DISCARD TABLESPACE. */ - buf_page_get_gen(block->page.id, get_page_size(), - RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL, - __FILE__, __LINE__, NULL, NULL); - return(err); + return DB_SUCCESS; } /*****************************************************************//** @@ -3358,6 +3294,441 @@ row_import_update_discarded_flag( return(err); } +struct fil_iterator_t { + pfs_os_file_t file; /*!< File handle */ + const char* filepath; /*!< File path name */ + os_offset_t start; /*!< From where to start */ + os_offset_t end; /*!< Where to stop */ + os_offset_t file_size; /*!< File size in bytes */ + ulint n_io_buffers; /*!< Number of pages to use + for IO */ + byte* io_buffer; /*!< Buffer to use for IO */ + fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */ + byte* crypt_io_buffer; /*!< IO buffer when encrypted */ +}; + +/********************************************************************//** +TODO: This can be made parallel trivially by chunking up the file and creating +a callback per thread. . Main benefit will be to use multiple CPUs for +checksums and compressed tables. We have to do compressed tables block by +block right now. Secondly we need to decompress/compress and copy too much +of data. These are CPU intensive. + +Iterate over all the pages in the tablespace. +@param iter - Tablespace iterator +@param block - block to use for IO +@param callback - Callback to inspect and update page contents +@retval DB_SUCCESS or error code */ +static +dberr_t +fil_iterate( +/*========*/ + const fil_iterator_t& iter, + buf_block_t* block, + AbstractCallback& callback) +{ + os_offset_t offset; + const ulint size = callback.get_page_size().physical(); + ulint n_bytes = iter.n_io_buffers * size; + + ut_ad(!srv_read_only_mode); + + /* TODO: For ROW_FORMAT=COMPRESSED tables we do a lot of useless + copying for non-index pages. Unfortunately, it is + required by buf_zip_decompress() */ + + for (offset = iter.start; offset < iter.end; offset += n_bytes) { + if (callback.is_interrupted()) { + return DB_INTERRUPTED; + } + + byte* io_buffer = iter.io_buffer; + block->frame = io_buffer; + + if (block->page.zip.data) { + /* Zip IO is done in the compressed page buffer. */ + io_buffer = block->page.zip.data; + } + + /* We have to read the exact number of bytes. Otherwise the + InnoDB IO functions croak on failed reads. */ + + n_bytes = ulint(ut_min(os_offset_t(n_bytes), + iter.end - offset)); + + ut_ad(n_bytes > 0); + ut_ad(!(n_bytes % size)); + + const bool encrypted = iter.crypt_data != NULL + && iter.crypt_data->should_encrypt(); + /* Use additional crypt io buffer if tablespace is encrypted */ + byte* const readptr = encrypted + ? iter.crypt_io_buffer : io_buffer; + byte* const writeptr = readptr; + + IORequest read_request(IORequest::READ); + read_request.disable_partial_io_warnings(); + + dberr_t err = os_file_read_no_error_handling( + read_request, iter.file, readptr, offset, n_bytes, 0); + if (err != DB_SUCCESS) { + ib::error() << iter.filepath + << ": os_file_read() failed"; + } + + bool updated = false; + os_offset_t page_off = offset; + ulint n_pages_read = n_bytes / size; + bool decrypted = false; + block->page.id.set_page_no(ulint(page_off / size)); + + for (ulint i = 0; i < n_pages_read; + block->page.id.set_page_no(block->page.id.page_no() + 1), + ++i, page_off += size, block->frame += size) { + err = DB_SUCCESS; + byte* src = readptr + i * size; + byte* dst = io_buffer + i * size; + bool frame_changed = false; + ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE); + const bool page_compressed + = page_type + == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED + || page_type == FIL_PAGE_PAGE_COMPRESSED; + const ulint page_no = page_get_page_no(src); + if (!page_no && page_off) { + const ulint* b = reinterpret_cast<const ulint*> + (src); + const ulint* const e = b + size / sizeof *b; + do { + if (*b++) { + goto page_corrupted; + } + } while (b != e); + + /* Proceed to the next page, + because this one is all zero. */ + continue; + } + + if (page_no != page_off / size) { + goto page_corrupted; + } + + if (encrypted) { + decrypted = fil_space_decrypt( + iter.crypt_data, dst, + callback.get_page_size(), src, &err); + + if (err != DB_SUCCESS) { + return err; + } + + if (decrypted) { + updated = true; + } else { + if (!page_compressed + && !block->page.zip.data) { + block->frame = src; + frame_changed = true; + } else { + memcpy(dst, src, size); + } + } + } + + /* If the original page is page_compressed, we need + to decompress it before adjusting further. */ + if (page_compressed) { + fil_decompress_page(NULL, dst, ulong(size), + NULL); + updated = true; + } else if (buf_page_is_corrupted( + false, + encrypted && !frame_changed + ? dst : src, + callback.get_page_size(), NULL)) { +page_corrupted: + ib::warn() << callback.filename() + << ": Page " << (offset / size) + << " at offset " << offset + << " looks corrupted."; + return DB_CORRUPTION; + } + + if ((err = callback(page_off, block)) != DB_SUCCESS) { + return err; + } else if (!updated) { + updated = buf_block_get_state(block) + == BUF_BLOCK_FILE_PAGE; + } + + /* If tablespace is encrypted we use additional + temporary scratch area where pages are read + for decrypting readptr == crypt_io_buffer != io_buffer. + + Destination for decryption is a buffer pool block + block->frame == dst == io_buffer that is updated. + Pages that did not require decryption even when + tablespace is marked as encrypted are not copied + instead block->frame is set to src == readptr. + + For encryption we again use temporary scratch area + writeptr != io_buffer == dst + that is then written to the tablespace + + (1) For normal tables io_buffer == dst == writeptr + (2) For only page compressed tables + io_buffer == dst == writeptr + (3) For encrypted (and page compressed) + readptr != io_buffer == dst != writeptr + */ + + ut_ad(!encrypted && !page_compressed ? + src == dst && dst == writeptr + (i * size):1); + ut_ad(page_compressed && !encrypted ? + src == dst && dst == writeptr + (i * size):1); + ut_ad(encrypted ? + src != dst && dst != writeptr + (i * size):1); + + if (encrypted) { + memcpy(writeptr + (i * size), + callback.get_frame(block), size); + } + + if (frame_changed) { + block->frame = dst; + } + + src = io_buffer + (i * size); + + if (page_compressed) { + ulint len = 0; + + fil_compress_page( + NULL, + src, + NULL, + size, + 0,/* FIXME: compression level */ + 512,/* FIXME: use proper block size */ + encrypted, + &len); + ut_ad(len <= size); + memset(src + len, 0, size - len); + updated = true; + } + + /* Encrypt the page if encryption was used. */ + if (encrypted && decrypted) { + byte *dest = writeptr + i * size; + byte* tmp = fil_encrypt_buf( + iter.crypt_data, + block->page.id.space(), + block->page.id.page_no(), + mach_read_from_8(src + FIL_PAGE_LSN), + src, callback.get_page_size(), dest); + + if (tmp == src) { + /* TODO: remove unnecessary memcpy's */ + memcpy(dest, src, size); + } + + updated = true; + } + } + + /* A page was updated in the set, write back to disk. */ + if (updated) { + IORequest write_request(IORequest::WRITE); + + err = os_file_write(write_request, + iter.filepath, iter.file, + writeptr, offset, n_bytes); + + if (err != DB_SUCCESS) { + return err; + } + } + } + + return DB_SUCCESS; +} + +/********************************************************************//** +Iterate over all the pages in the tablespace. +@param table - the table definiton in the server +@param n_io_buffers - number of blocks to read and write together +@param callback - functor that will do the page updates +@return DB_SUCCESS or error code */ +static +dberr_t +fil_tablespace_iterate( +/*===================*/ + dict_table_t* table, + ulint n_io_buffers, + AbstractCallback& callback) +{ + dberr_t err; + pfs_os_file_t file; + char* filepath; + + ut_a(n_io_buffers > 0); + ut_ad(!srv_read_only_mode); + + DBUG_EXECUTE_IF("ib_import_trigger_corruption_1", + return(DB_CORRUPTION);); + + /* Make sure the data_dir_path is set. */ + dict_get_and_save_data_dir_path(table, false); + + if (DICT_TF_HAS_DATA_DIR(table->flags)) { + ut_a(table->data_dir_path); + + filepath = fil_make_filepath( + table->data_dir_path, table->name.m_name, IBD, true); + } else { + filepath = fil_make_filepath( + NULL, table->name.m_name, IBD, false); + } + + if (!filepath) { + return(DB_OUT_OF_MEMORY); + } else { + bool success; + + file = os_file_create_simple_no_error_handling( + innodb_data_file_key, filepath, + OS_FILE_OPEN, OS_FILE_READ_WRITE, false, &success); + + if (!success) { + /* The following call prints an error message */ + os_file_get_last_error(true); + ib::error() << "Trying to import a tablespace," + " but could not open the tablespace file " + << filepath; + ut_free(filepath); + return DB_TABLESPACE_NOT_FOUND; + } else { + err = DB_SUCCESS; + } + } + + callback.set_file(filepath, file); + + os_offset_t file_size = os_file_get_size(file); + ut_a(file_size != (os_offset_t) -1); + + /* Allocate a page to read in the tablespace header, so that we + can determine the page size and zip_size (if it is compressed). + We allocate an extra page in case it is a compressed table. One + page is to ensure alignement. */ + + void* page_ptr = ut_malloc_nokey(3 * UNIV_PAGE_SIZE); + byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE)); + + buf_block_t* block = reinterpret_cast<buf_block_t*> + (ut_zalloc_nokey(sizeof *block)); + block->frame = page; + block->page.id.copy_from(page_id_t(0, 0)); + block->page.io_fix = BUF_IO_NONE; + block->page.buf_fix_count = 1; + block->page.state = BUF_BLOCK_FILE_PAGE; + + /* Read the first page and determine the page and zip size. */ + + IORequest request(IORequest::READ); + request.disable_partial_io_warnings(); + + err = os_file_read_no_error_handling(request, file, page, 0, + UNIV_PAGE_SIZE, 0); + + if (err == DB_SUCCESS) { + err = callback.init(file_size, block); + } + + if (err == DB_SUCCESS) { + block->page.id.copy_from( + page_id_t(callback.get_space_id(), 0)); + block->page.size.copy_from(callback.get_page_size()); + if (block->page.size.is_compressed()) { + page_zip_set_size(&block->page.zip, + callback.get_page_size().physical()); + /* ROW_FORMAT=COMPRESSED is not optimised for block IO + for now. We do the IMPORT page by page. */ + n_io_buffers = 1; + } + + fil_iterator_t iter; + + /* read (optional) crypt data */ + iter.crypt_data = fil_space_read_crypt_data( + callback.get_page_size(), page); + + /* If tablespace is encrypted, it needs extra buffers */ + if (iter.crypt_data && n_io_buffers > 1) { + /* decrease io buffers so that memory + consumption will not double */ + n_io_buffers /= 2; + } + + iter.file = file; + iter.start = 0; + iter.end = file_size; + iter.filepath = filepath; + iter.file_size = file_size; + iter.n_io_buffers = n_io_buffers; + + /* Add an extra page for compressed page scratch area. */ + void* io_buffer = ut_malloc_nokey( + (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE); + + iter.io_buffer = static_cast<byte*>( + ut_align(io_buffer, UNIV_PAGE_SIZE)); + + void* crypt_io_buffer = NULL; + if (iter.crypt_data) { + crypt_io_buffer = ut_malloc_nokey( + (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE); + iter.crypt_io_buffer = static_cast<byte*>( + ut_align(crypt_io_buffer, UNIV_PAGE_SIZE)); + } + + if (block->page.zip.ssize) { + ut_ad(iter.n_io_buffers == 1); + block->frame = iter.io_buffer; + block->page.zip.data = block->frame + UNIV_PAGE_SIZE; + } + + err = fil_iterate(iter, block, callback); + + if (iter.crypt_data) { + fil_space_destroy_crypt_data(&iter.crypt_data); + } + + ut_free(crypt_io_buffer); + ut_free(io_buffer); + } + + if (err == DB_SUCCESS) { + ib::info() << "Sync to disk"; + + if (!os_file_flush(file)) { + ib::info() << "os_file_flush() failed!"; + err = DB_IO_ERROR; + } else { + ib::info() << "Sync to disk - done!"; + } + } + + os_file_close(file); + + ut_free(page_ptr); + ut_free(filepath); + ut_free(block); + + return(err); +} + /*****************************************************************//** Imports a tablespace. The space id in the .ibd file must match the space id of the table in the data dictionary. @@ -3481,9 +3852,7 @@ row_import_for_mysql( FetchIndexRootPages fetchIndexRootPages(table, trx); err = fil_tablespace_iterate( - table, IO_BUFFER_SIZE( - cfg.m_page_size.physical(), - cfg.m_page_size.physical()), + table, IO_BUFFER_SIZE(cfg.m_page_size.physical()), fetchIndexRootPages); if (err == DB_SUCCESS) { @@ -3521,9 +3890,7 @@ row_import_for_mysql( /* Set the IO buffer size in pages. */ err = fil_tablespace_iterate( - table, IO_BUFFER_SIZE( - cfg.m_page_size.physical(), - cfg.m_page_size.physical()), converter); + table, IO_BUFFER_SIZE(cfg.m_page_size.physical()), converter); DBUG_EXECUTE_IF("ib_import_reset_space_and_lsn_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index e87e857c812..0eda95c6e58 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1875,8 +1875,6 @@ do_possible_lock_wait: check_table->inc_fk_checks(); - trx_kill_blocking(trx); - lock_wait_suspend_thread(thr); thr->lock_state = QUE_THR_LOCK_NOLOCK; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 2928ca51ddb..a791de052e8 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -36,6 +36,7 @@ Completed by Sunny Bains and Marko Makela #include "row0ext.h" #include "row0log.h" #include "row0ins.h" +#include "row0row.h" #include "row0sel.h" #include "log0crypt.h" #include "dict0crea.h" @@ -45,6 +46,7 @@ Completed by Sunny Bains and Marko Makela #include "ut0sort.h" #include "row0ftsort.h" #include "row0import.h" +#include "row0vers.h" #include "handler0alter.h" #include "btr0bulk.h" #include "fsp0sysspace.h" @@ -3721,8 +3723,6 @@ row_merge_lock_table( trx->op_info = "setting table lock for creating or dropping index"; trx->ddl = true; - /* Trx for DDL should not be forced to rollback for now */ - trx->in_innodb |= TRX_FORCE_ROLLBACK_DISABLE; return(lock_table_for_trx(table, trx, mode)); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 835ca2ec2d1..4f1be7433a7 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -730,9 +730,6 @@ handle_new_error: /* MySQL will roll back the latest SQL statement */ break; case DB_LOCK_WAIT: - - trx_kill_blocking(trx); - lock_wait_suspend_thread(thr); if (trx->error_state != DB_SUCCESS) { @@ -3347,30 +3344,7 @@ run_again: } else { que_thr_stop_for_mysql(thr); - if (err != DB_QUE_THR_SUSPENDED) { - ibool was_lock_wait; - - was_lock_wait = row_mysql_handle_errors( - &err, trx, thr, NULL); - - if (was_lock_wait) { - goto run_again; - } - } else { - que_thr_t* run_thr; - que_node_t* parent; - - parent = que_node_get_parent(thr); - - run_thr = que_fork_start_command( - static_cast<que_fork_t*>(parent)); - - ut_a(run_thr == thr); - - /* There was a lock wait but the thread was not - in a ready to run or running state. */ - trx->error_state = DB_LOCK_WAIT; - + if (row_mysql_handle_errors(&err, trx, thr, NULL)) { goto run_again; } } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 7b802b01793..503f4537b8d 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -2856,7 +2856,9 @@ row_sel_field_store_in_mysql_format_func( || !(templ->mysql_col_len % templ->mbmaxlen)); ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len || (field_no == templ->icp_rec_field_no - && field->prefix_len > 0)); + && field->prefix_len > 0) + || templ->rec_field_is_prefix); + ut_ad(templ->is_virtual || !(field->prefix_len % templ->mbmaxlen)); @@ -4025,6 +4027,118 @@ row_sel_fill_vrow( } } +/** Return the record field length in characters. +@param[in] col table column of the field +@param[in] field_no field number +@param[in] rec physical record +@param[in] offsets field offsets in the physical record +@return field length in characters. */ +static +size_t +rec_field_len_in_chars( + const dict_col_t* col, + const ulint field_no, + const rec_t* rec, + const ulint* offsets) +{ + const ulint cset = dtype_get_charset_coll(col->prtype); + const CHARSET_INFO* cs = all_charsets[cset]; + ulint rec_field_len; + const char* rec_field = reinterpret_cast<const char *>( + rec_get_nth_field( + rec, offsets, field_no, &rec_field_len)); + + if (UNIV_UNLIKELY(!cs)) { + ib::warn() << "Missing collation " << cset; + return SIZE_T_MAX; + } + + return(cs->cset->numchars(cs, rec_field, rec_field + rec_field_len)); +} + +/** Avoid the clustered index lookup if all the following conditions +are true: +1) all columns are in secondary index +2) all values for columns that are prefix-only indexes are shorter +than the prefix size. This optimization can avoid many IOs for certain schemas. +@return true, to avoid clustered index lookup. */ +static +bool row_search_with_covering_prefix( + row_prebuilt_t* prebuilt, + const rec_t* rec, + const ulint* offsets) +{ + const dict_index_t* index = prebuilt->index; + ut_ad(!dict_index_is_clust(index)); + + if (!srv_prefix_index_cluster_optimization) { + return false; + } + + /** Optimization only applicable if there the number of secondary index + fields are greater than or equal to number of clustered index fields. */ + if (prebuilt->n_template > index->n_fields) { + return false; + } + + for (ulint i = 0; i < prebuilt->n_template; i++) { + mysql_row_templ_t* templ = prebuilt->mysql_template + i; + ulint j = templ->rec_prefix_field_no; + + /** Condition (1) : is the field in the index. */ + if (j == ULINT_UNDEFINED) { + return false; + } + + /** Condition (2): If this is a prefix index then + row's value size shorter than prefix length. */ + + if (!templ->rec_field_is_prefix) { + continue; + } + + ulint rec_size = rec_offs_nth_size(offsets, j); + const dict_field_t* field = dict_index_get_nth_field(index, j); + ulint max_chars = field->prefix_len / templ->mbmaxlen; + + ut_a(field->prefix_len > 0); + + if (rec_size < max_chars) { + /* Record in bytes shorter than the index + prefix length in char. */ + continue; + } + + if (rec_size * templ->mbminlen >= field->prefix_len) { + /* Shortest representation string by the + byte length of the record is longer than the + maximum possible index prefix. */ + return false; + } + + size_t num_chars = rec_field_len_in_chars( + field->col, j, rec, offsets); + + if (num_chars >= max_chars) { + /* No of chars to store the record exceeds + the index prefix character length. */ + return false; + } + } + + /* If prefix index optimization condition satisfied then + for all columns above, use rec_prefix_field_no instead of + rec_field_no, and skip the clustered lookup below. */ + for (ulint i = 0; i < prebuilt->n_template; i++) { + mysql_row_templ_t* templ = prebuilt->mysql_template + i; + templ->rec_field_no = templ->rec_prefix_field_no; + ut_a(templ->rec_field_no != ULINT_UNDEFINED); + } + + srv_stats.n_sec_rec_cluster_reads_avoided.inc(); + return true; +} + /** Searches for rows in the database using cursor. Function is mainly used for tables that are shared across connections and so it employs technique that can help re-construct the rows that @@ -4085,7 +4199,6 @@ row_search_mvcc( ulint* offsets = offsets_; ibool table_lock_waited = FALSE; byte* next_buf = 0; - ibool use_clustered_index = FALSE; bool spatial_search = false; rec_offs_init(offsets_); @@ -4383,17 +4496,12 @@ row_search_mvcc( naturally moves upward (in fetch next) in alphabetical order, otherwise downward */ - if (direction == 0) { - - if (mode == PAGE_CUR_GE - || mode == PAGE_CUR_G + if (UNIV_UNLIKELY(direction == 0)) { + if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G || mode >= PAGE_CUR_CONTAIN) { - moves_up = TRUE; } - } else if (direction == ROW_SEL_NEXT) { - moves_up = TRUE; } @@ -4970,8 +5078,7 @@ no_gap_lock: a deadlock and the transaction had to wait then release the lock it is waiting on. */ - trx->abort_type = TRX_SERVER_ABORT; - err = lock_trx_handle_wait(trx, false, false); + err = lock_trx_handle_wait(trx); switch (err) { case DB_SUCCESS: @@ -5147,69 +5254,10 @@ locks_ok_del_marked: break; } - /* Get the clustered index record if needed, if we did not do the - search using the clustered index... */ - - use_clustered_index = - (index != clust_index && prebuilt->need_to_access_clustered); - - if (use_clustered_index && srv_prefix_index_cluster_optimization - && prebuilt->n_template <= index->n_fields) { - /* ...but, perhaps avoid the clustered index lookup if - all of the following are true: - 1) all columns are in the secondary index - 2) all values for columns that are prefix-only - indexes are shorter than the prefix size - This optimization can avoid many IOs for certain schemas. - */ - ibool row_contains_all_values = TRUE; - uint i; - for (i = 0; i < prebuilt->n_template; i++) { - /* Condition (1) from above: is the field in the - index (prefix or not)? */ - mysql_row_templ_t* templ = - prebuilt->mysql_template + i; - ulint secondary_index_field_no = - templ->rec_prefix_field_no; - if (secondary_index_field_no == ULINT_UNDEFINED) { - row_contains_all_values = FALSE; - break; - } - /* Condition (2) from above: if this is a - prefix, is this row's value size shorter - than the prefix? */ - if (templ->rec_field_is_prefix) { - ulint record_size = rec_offs_nth_size( - offsets, - secondary_index_field_no); - const dict_field_t *field = - dict_index_get_nth_field( - index, - secondary_index_field_no); - ut_a(field->prefix_len > 0); - if (record_size >= field->prefix_len) { - row_contains_all_values = FALSE; - break; - } - } - } - /* If (1) and (2) were true for all columns above, use - rec_prefix_field_no instead of rec_field_no, and skip - the clustered lookup below. */ - if (row_contains_all_values) { - for (i = 0; i < prebuilt->n_template; i++) { - mysql_row_templ_t* templ = - prebuilt->mysql_template + i; - templ->rec_field_no = - templ->rec_prefix_field_no; - ut_a(templ->rec_field_no != ULINT_UNDEFINED); - } - use_clustered_index = FALSE; - srv_stats.n_sec_rec_cluster_reads_avoided.inc(); + if (index != clust_index && prebuilt->need_to_access_clustered) { + if (row_search_with_covering_prefix(prebuilt, rec, offsets)) { + goto use_covering_index; } - } - - if (use_clustered_index) { requires_clust_rec: ut_ad(index != clust_index); /* We use a 'goto' to the preceding label if a consistent @@ -5307,6 +5355,7 @@ requires_clust_rec: } } } else { +use_covering_index: result_rec = rec; } @@ -5652,15 +5701,6 @@ normal_return: mtr.commit(); - /* Rollback blocking transactions from hit list for high priority - transaction, if any. We should not be holding latches here as - we are going to rollback the blocking transactions. */ - if (!trx->hit_list.empty()) { - - ut_ad(trx_is_high_priority(trx)); - trx_kill_blocking(trx); - } - DEBUG_SYNC_C("row_search_for_mysql_before_return"); if (prebuilt->idx_cond != 0) { diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index d395dcc7e05..192f4c17b8d 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -36,7 +36,8 @@ Created 2013-04-12 Sunny Bains #include "srv0start.h" #include "row0trunc.h" #include "os0file.h" -#include <vector> +#include "que0que.h" +#include "trx0undo.h" /* FIXME: For temporary tables, use a simple approach of btr_free() and btr_create() of each index tree. */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index c94ff932651..fef5ed3e37b 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -404,16 +404,6 @@ ulint srv_truncated_status_writes; /** Number of initialized rollback segments for persistent undo log */ ulong srv_available_undo_logs; -UNIV_INTERN ib_uint64_t srv_page_compression_saved; -UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect512; -UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect4096; -UNIV_INTERN ib_uint64_t srv_index_pages_written; -UNIV_INTERN ib_uint64_t srv_non_index_pages_written; -UNIV_INTERN ib_uint64_t srv_pages_page_compressed; -UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op; -UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op_saved; -UNIV_INTERN ib_uint64_t srv_index_page_decompressed; - /* Defragmentation */ UNIV_INTERN my_bool srv_defragment; /** innodb_defragment_n_pages */ @@ -1162,7 +1152,16 @@ srv_refresh_innodb_monitor_stats(void) { mutex_enter(&srv_innodb_monitor_mutex); - srv_last_monitor_time = time(NULL); + time_t current_time = time(NULL); + + if (difftime(current_time, srv_last_monitor_time) <= 60) { + /* We referesh InnoDB Monitor values so that averages are + printed from at most 60 last seconds */ + mutex_exit(&srv_innodb_monitor_mutex); + return; + } + + srv_last_monitor_time = current_time; os_aio_refresh_stats(); @@ -1757,6 +1756,8 @@ loop: } } + srv_refresh_innodb_monitor_stats(); + if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { goto exit_func; } @@ -1828,13 +1829,6 @@ loop: old_lsn = new_lsn; } - if (difftime(time(NULL), srv_last_monitor_time) > 60) { - /* We referesh InnoDB Monitor values so that averages are - printed from at most 60 last seconds */ - - srv_refresh_innodb_monitor_stats(); - } - /* Update the statistics collected for deciding LRU eviction policy. */ buf_LRU_stat_update(); @@ -2903,7 +2897,9 @@ srv_purge_wakeup() srv_release_threads(SRV_WORKER, n_workers); } - } while (!srv_running + } while (!my_atomic_loadptr_explicit(reinterpret_cast<void**> + (&srv_running), + MY_MEMORY_ORDER_RELAXED) && (srv_sys.n_threads_active[SRV_WORKER] || srv_sys.n_threads_active[SRV_PURGE])); } diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 8b17fdaad96..94b5f491c89 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -895,12 +895,11 @@ srv_undo_tablespaces_init(bool create_new_db) switch (srv_operation) { case SRV_OPERATION_RESTORE_DELTA: case SRV_OPERATION_BACKUP: - /* MDEV-13561 FIXME: Determine srv_undo_space_id_start - from the undo001 file. */ - srv_undo_space_id_start = 1; for (i = 0; i < n_undo_tablespaces; i++) { undo_tablespace_ids[i] = i + srv_undo_space_id_start; } + + prev_space_id = srv_undo_space_id_start - 1; break; case SRV_OPERATION_NORMAL: if (create_new_db) { @@ -961,7 +960,7 @@ srv_undo_tablespaces_init(bool create_new_db) undo_tablespace_ids[i]); /* Should be no gaps in undo tablespace ids. */ - ut_a(prev_space_id + 1 == undo_tablespace_ids[i]); + ut_a(!i || prev_space_id + 1 == undo_tablespace_ids[i]); /* The system space id should not be in this array. */ ut_a(undo_tablespace_ids[i] != 0); @@ -989,14 +988,14 @@ srv_undo_tablespaces_init(bool create_new_db) not in use and therefore not required by recovery. We only check that there are no gaps. */ - for (i = prev_space_id + 1; i < TRX_SYS_N_RSEGS; ++i) { + for (i = prev_space_id + 1; + i < srv_undo_space_id_start + TRX_SYS_N_RSEGS; ++i) { char name[OS_FILE_MAX_PATH]; snprintf( name, sizeof(name), "%s%cundo%03zu", srv_undo_dir, OS_PATH_SEPARATOR, i); - /* Undo space ids start from 1. */ err = srv_undo_tablespace_open(name, i); if (err != DB_SUCCESS) { @@ -2793,7 +2792,9 @@ srv_shutdown_bg_undo_sources() void innodb_shutdown() { - ut_ad(!srv_running); + ut_ad(!my_atomic_loadptr_explicit(reinterpret_cast<void**> + (&srv_running), + MY_MEMORY_ORDER_RELAXED)); ut_ad(!srv_undo_sources); switch (srv_operation) { diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index bf73759a499..c729407ee6e 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -191,10 +191,7 @@ trx_rollback_for_mysql_low( /** Rollback a transaction used in MySQL @param[in, out] trx transaction @return error code or DB_SUCCESS */ -static -dberr_t -trx_rollback_low( - trx_t* trx) +dberr_t trx_rollback_for_mysql(trx_t* trx) { /* We are reading trx->state without holding trx_sys.mutex here, because the rollback should be invoked for a running @@ -202,7 +199,6 @@ trx_rollback_low( that is associated with the current thread. */ switch (trx->state) { - case TRX_STATE_FORCED_ROLLBACK: case TRX_STATE_NOT_STARTED: trx->will_lock = 0; ut_ad(trx->in_mysql_trx_list); @@ -273,28 +269,6 @@ trx_rollback_low( } /*******************************************************************//** -Rollback a transaction used in MySQL. -@return error code or DB_SUCCESS */ -dberr_t -trx_rollback_for_mysql( -/*===================*/ - trx_t* trx) /*!< in/out: transaction */ -{ - /* Avoid the tracking of async rollback killer - thread to enter into InnoDB. */ - if (TrxInInnoDB::is_async_rollback(trx)) { - - return(trx_rollback_low(trx)); - - } else { - - TrxInInnoDB trx_in_innodb(trx, true); - - return(trx_rollback_low(trx)); - } -} - -/*******************************************************************//** Rollback the latest SQL statement for MySQL. @return error code or DB_SUCCESS */ dberr_t @@ -311,7 +285,6 @@ trx_rollback_last_sql_stat_for_mysql( ut_ad(trx->in_mysql_trx_list); switch (trx->state) { - case TRX_STATE_FORCED_ROLLBACK: case TRX_STATE_NOT_STARTED: return(DB_SUCCESS); @@ -498,12 +471,9 @@ trx_rollback_to_savepoint_for_mysql( switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - ib::error() << "Transaction has a savepoint " << savep->name << " though it is not started"; - return(DB_ERROR); case TRX_STATE_ACTIVE: diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index c76fa683d62..943364c0aee 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -42,7 +42,6 @@ Created 3/26/1996 Heikki Tuuri #include "srv0mon.h" #include "srv0srv.h" #include "fsp0sysspace.h" -#include "row0mysql.h" #include "srv0start.h" #include "trx0purge.h" #include "trx0rec.h" @@ -79,15 +78,6 @@ typedef std::set< std::less<table_id_t>, ut_allocator<table_id_t> > table_id_set; -/** Constructor */ -TrxVersion::TrxVersion(trx_t* trx) - : - m_trx(trx), - m_version(trx->version) -{ - /* No op */ -} - /** Set flush observer for the transaction @param[in/out] trx transaction struct @param[in] observer flush observer */ @@ -131,14 +121,12 @@ trx_init( /*=====*/ trx_t* trx) { - /* This is called at the end of commit, do not reset the - trx_t::state here to NOT_STARTED. The FORCED_ROLLBACK - status is required for asynchronous handling. */ - trx->id = 0; trx->no = TRX_ID_MAX; + trx->state = TRX_STATE_NOT_STARTED; + trx->is_recovered = false; trx->op_info = ""; @@ -193,29 +181,7 @@ trx_init( trx->lock.table_cached = 0; - /* During asynchronous rollback, we should reset forced rollback flag - only after rollback is complete to avoid race with the thread owning - the transaction. */ - - if (!TrxInInnoDB::is_async_rollback(trx)) { - - my_atomic_storelong(&trx->killed_by, 0); - - /* Note: Do not set to 0, the ref count is decremented inside - the TrxInInnoDB() destructor. We only need to clear the flags. */ - - trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK; - } - - /* Note: It's possible that this list is not empty if a transaction - was interrupted after it collected the victim transactions and before - it got a chance to roll them back asynchronously. */ - - trx->hit_list.clear(); - trx->flush_observer = NULL; - - ++trx->version; } /** For managing the life-cycle of the trx_t instance that we get @@ -230,7 +196,7 @@ struct TrxFactory { { /* Explicitly call the constructor of the already allocated object. trx_t objects are allocated by - ut_zalloc() in Pool::Pool() which would not call + ut_zalloc_nokey() in Pool::Pool() which would not call the constructors of the trx_t members. */ new(&trx->mod_tables) trx_mod_tables_t(); @@ -240,15 +206,11 @@ struct TrxFactory { new(&trx->lock.table_locks) lock_pool_t(); - new(&trx->hit_list) hit_list_t(); new(&trx->read_view) ReadView(); trx->rw_trx_hash_pins = 0; trx_init(trx); - DBUG_LOG("trx", "Init: " << trx); - trx->state = TRX_STATE_NOT_STARTED; - trx->dict_operation_lock_mode = 0; trx->xid = UT_NEW_NOKEY(xid_t()); @@ -321,7 +283,6 @@ struct TrxFactory { trx->lock.table_locks.~lock_pool_t(); - trx->hit_list.~hit_list_t(); trx->read_view.~ReadView(); } @@ -336,8 +297,7 @@ struct TrxFactory { ut_ad(!trx->read_only); - ut_ad(trx->state == TRX_STATE_NOT_STARTED - || trx->state == TRX_STATE_FORCED_ROLLBACK); + ut_ad(trx->state == TRX_STATE_NOT_STARTED); ut_ad(trx->dict_operation == TRX_DICT_OP_NONE); @@ -355,12 +315,6 @@ struct TrxFactory { ut_ad(trx->lock.table_locks.empty()); - ut_ad(!trx->abort); - - ut_ad(trx->hit_list.empty()); - - ut_ad(trx->killed_by == 0); - return(true); } }; @@ -453,16 +407,10 @@ trx_create_low() /* We just got trx from pool, it should be non locking */ ut_ad(trx->will_lock == 0); + ut_ad(trx->state == TRX_STATE_NOT_STARTED); ut_ad(!trx->rw_trx_hash_pins); - /* Background trx should not be forced to rollback, - we will unset the flag for user trx. */ - trx->in_innodb |= TRX_FORCE_ROLLBACK_DISABLE; - - /* Trx state can be TRX_STATE_FORCED_ROLLBACK if - the trx was forced to rollback before it's reused.*/ DBUG_LOG("trx", "Create: " << trx); - trx->state = TRX_STATE_NOT_STARTED; heap = mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 8); @@ -1104,7 +1052,6 @@ trx_start_low( { ut_ad(!trx->in_rollback); ut_ad(!trx->is_recovered); - ut_ad(trx->hit_list.empty()); ut_ad(trx->start_line != 0); ut_ad(trx->start_file != 0); ut_ad(trx->roll_limit == 0); @@ -1113,10 +1060,6 @@ trx_start_low( ut_ad(trx->rsegs.m_noredo.rseg == NULL); ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK)); - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC)); - - ++trx->version; /* Check whether it is an AUTOCOMMIT SELECT */ trx->auto_commit = thd_trx_is_auto_commit(trx->mysql_thd); @@ -1501,14 +1444,8 @@ trx_commit_in_memory( MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT); - /* AC-NL-RO transactions can't be rolled back asynchronously. */ - ut_ad(!trx->abort); - ut_ad(!(trx->in_innodb - & (TRX_FORCE_ROLLBACK | TRX_FORCE_ROLLBACK_ASYNC))); - DBUG_LOG("trx", "Autocommit in memory: " << trx); trx->state = TRX_STATE_NOT_STARTED; - } else { if (trx->id > 0) { /* For consistent snapshot, we need to remove current @@ -1627,20 +1564,8 @@ trx_commit_in_memory( } #endif - /* Because we can rollback transactions asynchronously, we change - the state at the last step. trx_t::abort cannot change once commit - or rollback has started because we will have released the locks by - the time we get here. */ - - if (trx->abort) { - - trx->abort = false; - DBUG_LOG("trx", "Abort: " << trx); - trx->state = TRX_STATE_FORCED_ROLLBACK; - } else { - DBUG_LOG("trx", "Commit in memory: " << trx); - trx->state = TRX_STATE_NOT_STARTED; - } + DBUG_LOG("trx", "Commit in memory: " << trx); + trx->state = TRX_STATE_NOT_STARTED; /* trx->in_mysql_trx_list would hold between trx_allocate_for_mysql() and trx_free_for_mysql(). It does not @@ -1779,8 +1704,6 @@ trx_commit_or_rollback_prepare( switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - trx_start_low(trx, true); /* fall through */ @@ -1884,22 +1807,12 @@ trx_commit_for_mysql( /*=================*/ trx_t* trx) /*!< in/out: transaction */ { - TrxInInnoDB trx_in_innodb(trx, true); - - if (trx_in_innodb.is_aborted() - && trx->killed_by != os_thread_get_curr_id()) { - - return(DB_FORCED_ABORT); - } - /* Because we do not do the commit by sending an Innobase sig to the transaction, we must here make sure that trx has been started. */ switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - ut_d(trx->start_file = __FILE__); ut_d(trx->start_line = __LINE__); @@ -1956,7 +1869,6 @@ trx_mark_sql_stat_end( case TRX_STATE_COMMITTED_IN_MEMORY: break; case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: trx->undo_no = 0; trx->undo_rseg_space = 0; /* fall through */ @@ -2004,9 +1916,6 @@ trx_print_low( case TRX_STATE_NOT_STARTED: fputs(", not started", f); goto state_ok; - case TRX_STATE_FORCED_ROLLBACK: - fputs(", forced rollback", f); - goto state_ok; case TRX_STATE_ACTIVE: fprintf(f, ", ACTIVE %lu sec", (ulong) difftime(time(NULL), trx->start_time)); @@ -2167,7 +2076,6 @@ trx_assert_started( return(TRUE); case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: break; } @@ -2275,10 +2183,6 @@ trx_prepare( /*========*/ trx_t* trx) /*!< in/out: transaction */ { - /* This transaction has crossed the point of no return and cannot - be rolled back asynchronously now. It must commit or rollback - synhronously. */ - /* Only fresh user transactions can be prepared. Recovered transactions cannot. */ ut_a(!trx->is_recovered); @@ -2313,29 +2217,17 @@ trx_prepare( } } -/** -Does the transaction prepare for MySQL. -@param[in, out] trx Transaction instance to prepare */ -dberr_t -trx_prepare_for_mysql(trx_t* trx) +/** XA PREPARE a transaction. +@param[in,out] trx transaction to prepare */ +void trx_prepare_for_mysql(trx_t* trx) { trx_start_if_not_started_xa(trx, false); - TrxInInnoDB trx_in_innodb(trx, true); - - if (trx_in_innodb.is_aborted() - && trx->killed_by != os_thread_get_curr_id()) { - - return(DB_FORCED_ABORT); - } - trx->op_info = "preparing"; trx_prepare(trx); trx->op_info = ""; - - return(DB_SUCCESS); } @@ -2460,7 +2352,6 @@ trx_start_if_not_started_xa_low( { switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: trx_start_low(trx, read_write); return; @@ -2493,13 +2384,10 @@ trx_start_if_not_started_low( { switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - trx_start_low(trx, read_write); return; case TRX_STATE_ACTIVE: - if (read_write && trx->id == 0 && !trx->read_only) { trx_set_rw_mode(trx); } @@ -2556,8 +2444,6 @@ trx_start_for_ddl_low( { switch (trx->state) { case TRX_STATE_NOT_STARTED: - case TRX_STATE_FORCED_ROLLBACK: - /* Flag this transaction as a dictionary operation, so that the data dictionary will be locked in crash recovery. */ @@ -2619,146 +2505,3 @@ trx_set_rw_mode( trx->read_view.set_creator_trx_id(trx->id); } } - -/** -Kill all transactions that are blocking this transaction from acquiring locks. -@param[in,out] trx High priority transaction */ - -void -trx_kill_blocking(trx_t* trx) -{ - if (trx->hit_list.empty()) { - return; - } - - DEBUG_SYNC_C("trx_kill_blocking_enter"); - - ulint had_dict_lock = trx->dict_operation_lock_mode; - - switch (had_dict_lock) { - case 0: - break; - - case RW_S_LATCH: - /* Release foreign key check latch */ - row_mysql_unfreeze_data_dictionary(trx); - break; - - default: - /* There should never be a lock wait when the - dictionary latch is reserved in X mode. Dictionary - transactions should only acquire locks on dictionary - tables, not other tables. All access to dictionary - tables should be covered by dictionary - transactions. */ - ut_error; - } - - ut_a(trx->dict_operation_lock_mode == 0); - - /** Kill the transactions in the lock acquisition order old -> new. */ - hit_list_t::reverse_iterator end = trx->hit_list.rend(); - - for (hit_list_t::reverse_iterator it = trx->hit_list.rbegin(); - it != end; - ++it) { - - trx_t* victim_trx = it->m_trx; - ulint version = it->m_version; - - /* Shouldn't commit suicide. */ - ut_ad(victim_trx != trx); - ut_ad(victim_trx->mysql_thd != trx->mysql_thd); - - /* Check that the transaction isn't active inside - InnoDB code. We have to wait while it is executing - in the InnoDB context. This can potentially take a - long time */ - - trx_mutex_enter(victim_trx); - ut_ad(version <= victim_trx->version); - - ulint loop_count = 0; - /* start with optimistic sleep time of 20 micro seconds. */ - ulint sleep_time = 20; - - while ((victim_trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0 - && victim_trx->version == version) { - - trx_mutex_exit(victim_trx); - - loop_count++; - /* If the wait is long, don't hog the cpu. */ - if (loop_count < 100) { - /* 20 microseconds */ - sleep_time = 20; - } else if (loop_count < 1000) { - /* 1 millisecond */ - sleep_time = 1000; - } else { - /* 100 milliseconds */ - sleep_time = 100000; - } - - os_thread_sleep(sleep_time); - - trx_mutex_enter(victim_trx); - } - - /* Compare the version to check if the transaction has - already finished */ - if (victim_trx->version != version) { - trx_mutex_exit(victim_trx); - continue; - } - - /* We should never kill background transactions. */ - ut_ad(victim_trx->mysql_thd != NULL); - - ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE)); - ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK); - ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC); - ut_ad(victim_trx->killed_by == os_thread_get_curr_id()); - ut_ad(victim_trx->version == it->m_version); - - /* We don't kill Read Only, Background or high priority - transactions. */ - ut_a(!victim_trx->read_only); - ut_a(victim_trx->mysql_thd != NULL); - - trx_mutex_exit(victim_trx); - -#ifndef DBUG_OFF - char buffer[1024]; -#endif /* !DBUG_OFF */ - - DBUG_LOG("trx", - "High Priority Transaction " - << trx->id << " killed transaction " - << victim_trx->id << " in hit list" - << " - " - << thd_get_error_context_description( - victim_trx->mysql_thd, - buffer, sizeof(buffer), 512)); - - trx_rollback_for_mysql(victim_trx); - trx_mutex_enter(victim_trx); - - version++; - ut_ad(victim_trx->version == version); - - my_atomic_storelong(&victim_trx->killed_by, 0); - - victim_trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK; - - trx_mutex_exit(victim_trx); - } - - trx->hit_list.clear(); - - if (had_dict_lock) { - - row_mysql_freeze_data_dictionary(trx); - } - -} diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc index a8ff700847a..7bc51b801c5 100644 --- a/storage/innobase/ut/ut0ut.cc +++ b/storage/innobase/ut/ut0ut.cc @@ -583,8 +583,6 @@ ut_strerr( return("Rollback"); case DB_DUPLICATE_KEY: return("Duplicate key"); - case DB_QUE_THR_SUSPENDED: - return("The queue thread has been suspended"); case DB_MISSING_HISTORY: return("Required history data has been deleted"); case DB_CLUSTER_NOT_FOUND: diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c index 01af4c0381f..86a27a13136 100644 --- a/storage/maria/maria_chk.c +++ b/storage/maria/maria_chk.c @@ -895,7 +895,7 @@ static void get_options(register int *argc,register char ***argv) { int ho_error; - load_defaults("my", load_default_groups, argc, argv); + load_defaults_or_exit("my", load_default_groups, argc, argv); default_argv= *argv; check_param.testflag= T_UPDATE_STATE; if (isatty(fileno(stdout))) diff --git a/storage/maria/maria_dump_log.c b/storage/maria/maria_dump_log.c index 42c694bf1bf..3570dede80e 100644 --- a/storage/maria/maria_dump_log.c +++ b/storage/maria/maria_dump_log.c @@ -133,7 +133,7 @@ int main(int argc, char **argv) uchar buffer[TRANSLOG_PAGE_SIZE]; MY_INIT(argv[0]); - load_defaults("my", load_default_groups, &argc, &argv); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; get_options(&argc, &argv); diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c index c087697bf0b..c36543eb231 100644 --- a/storage/maria/maria_pack.c +++ b/storage/maria/maria_pack.c @@ -208,7 +208,7 @@ int main(int argc, char **argv) char **default_argv; MY_INIT(argv[0]); - load_defaults("my",load_default_groups,&argc,&argv); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; get_options(&argc,&argv); maria_init(); diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 2c24c125f36..551732d8ba3 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -47,7 +47,7 @@ int main(int argc, char **argv) maria_data_root= (char *)"."; sf_leaking_memory=1; /* don't report memory leaks on early exits */ - load_defaults("my", load_default_groups, &argc, &argv); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; get_options(&argc, &argv); diff --git a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c index cffe188e855..cbf914f5d45 100644 --- a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c +++ b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c @@ -256,7 +256,7 @@ int main(int argc __attribute__((unused)), char *argv[]) #endif long_buffer= malloc(LONG_BUFFER_SIZE + LSN_STORE_SIZE * 2 + 2); - load_defaults("my", load_default_groups, &argc, &argv); + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; get_options(&argc, &argv); diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index e2f99177894..ad8de98280c 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -752,9 +752,7 @@ static void get_options(register int *argc,register char ***argv) { int ho_error; - if (load_defaults("my", load_default_groups, argc, argv)) - exit(1); - + load_defaults_or_exit("my", load_default_groups, argc, argv); default_argv= *argv; if (isatty(fileno(stdout))) check_param.testflag|=T_WRITE_LOOP; diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c index 6fb2a5a69d5..4ea1602bec3 100644 --- a/storage/myisam/myisampack.c +++ b/storage/myisam/myisampack.c @@ -209,9 +209,7 @@ int main(int argc, char **argv) char **default_argv; MY_INIT(argv[0]); - if (load_defaults("my",load_default_groups,&argc,&argv)) - exit(1); - + load_defaults_or_exit("my", load_default_groups, &argc, &argv); default_argv= argv; get_options(&argc,&argv); diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index 44cec1c2550..5fe4c792d13 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -4417,6 +4417,49 @@ static int rocksdb_done_func(void *const p) { } /* + MariaDB: When the plugin is unloaded with UNINSTALL SONAME command, some + connections may still have Rdb_transaction objects. + + These objects are not genuine transactions (as SQL layer makes sure that + a plugin that is being unloaded has no open tables), they are empty + Rdb_transaction objects that were left there to save on object + creation/deletion. + + Go through the list and delete them. + */ + { + class Rdb_trx_deleter: public Rdb_tx_list_walker { + public: + std::set<Rdb_transaction*> rdb_trxs; + + void process_tran(const Rdb_transaction *const tx) override { + /* + Check if the transaction is really empty. We only check + non-WriteBatch-based transactions, because there is no easy way to + check WriteBatch-based transactions. + */ + if (!tx->is_writebatch_trx()) { + const auto tx_impl = static_cast<const Rdb_transaction_impl *>(tx); + DBUG_ASSERT(tx_impl); + if (tx_impl->get_rdb_trx()) + DBUG_ASSERT(0); + } + rdb_trxs.insert((Rdb_transaction*)tx); + }; + } deleter; + + Rdb_transaction::walk_tx_list(&deleter); + + for (std::set<Rdb_transaction*>::iterator it= deleter.rdb_trxs.begin(); + it != deleter.rdb_trxs.end(); + ++it) + { + // When a transaction is deleted, it removes itself from s_tx_list. + delete *it; + } + } + + /* destructors for static objects can be called at _exit(), but we want to free the memory at dlclose() */ diff --git a/storage/rocksdb/mysql-test/rocksdb/r/mariadb_plugin.result b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_plugin.result new file mode 100644 index 00000000000..bb06c4be2e5 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/r/mariadb_plugin.result @@ -0,0 +1,12 @@ +# +# MDEV-14843: Assertion `s_tx_list.size() == 0' failed in myrocks::Rdb_transaction::term_mutex +# +INSTALL SONAME 'ha_rocksdb'; +CREATE TABLE t1 (i INT) ENGINE=RocksDB; +insert into t1 values (1); +connect con1,localhost,root,,; +connection con1; +insert into test.t1 values (1); +connection default; +DROP TABLE t1; +UNINSTALL SONAME 'ha_rocksdb'; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin-master.opt b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin-master.opt new file mode 100644 index 00000000000..0f0a3ef33e5 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin-master.opt @@ -0,0 +1 @@ +--default-storage-engine=myisam --plugin-load='' --ignore-db-dirs=#rocksdb diff --git a/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin.test b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin.test new file mode 100644 index 00000000000..303c4a5e0f9 --- /dev/null +++ b/storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin.test @@ -0,0 +1,21 @@ +--source include/have_log_bin.inc +--source include/have_binlog_format_row.inc + +--echo # +--echo # MDEV-14843: Assertion `s_tx_list.size() == 0' failed in myrocks::Rdb_transaction::term_mutex +--echo # + +INSTALL SONAME 'ha_rocksdb'; + +CREATE TABLE t1 (i INT) ENGINE=RocksDB; +insert into t1 values (1); + +connect (con1,localhost,root,,); +connection con1; +insert into test.t1 values (1); + +connection default; + +# Cleanup +DROP TABLE t1; +UNINSTALL SONAME 'ha_rocksdb'; diff --git a/storage/spider/spd_db_oracle.cc b/storage/spider/spd_db_oracle.cc index f9eb305d258..b852a43282c 100644 --- a/storage/spider/spd_db_oracle.cc +++ b/storage/spider/spd_db_oracle.cc @@ -31,6 +31,10 @@ #endif #ifdef HAVE_ORACLE_OCI +#if (defined(WIN32) || defined(_WIN32) || defined(WINDOWS) || defined(_WINDOWS)) +#include <Shlwapi.h> +#define strcasestr StrStr +#endif #include <oci.h> #include "spd_err.h" #include "spd_param.h" diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc index 4d69d9af615..d0c72674de2 100644 --- a/storage/spider/spd_direct_sql.cc +++ b/storage/spider/spd_direct_sql.cc @@ -399,6 +399,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn( if (direct_sql->access_mode == 0) { #endif + if (direct_sql->dbton_id == SPIDER_DBTON_SIZE) + { + /* Invalid target wrapper */ + *error_num = ER_SPIDER_INVALID_CONNECT_INFO_NUM; + my_printf_error(*error_num, ER_SPIDER_INVALID_CONNECT_INFO_STR, + MYF(0), direct_sql->tgt_wrapper); + goto error_alloc_conn; + } if (!(conn = (SPIDER_CONN *) spider_bulk_malloc(spider_current_trx, 32, MYF(MY_WME | MY_ZEROFILL), &conn, sizeof(*conn), @@ -426,6 +434,14 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn( conn->default_database.init_calc_mem(138); #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) } else { + if (direct_sql->dbton_id == SPIDER_DBTON_SIZE) + { + /* Invalid target wrapper */ + *error_num = ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_NUM; + my_printf_error(*error_num, ER_SPIDER_NOSQL_WRAPPER_IS_INVALID_STR, + MYF(0), direct_sql->tgt_wrapper); + goto error_alloc_conn; + } if (!(conn = (SPIDER_CONN *) spider_bulk_malloc(spider_current_trx, 33, MYF(MY_WME | MY_ZEROFILL), &conn, sizeof(*conn), diff --git a/storage/spider/spd_sys_table.cc b/storage/spider/spd_sys_table.cc index ae64da1c29f..9f1a9850083 100644 --- a/storage/spider/spd_sys_table.cc +++ b/storage/spider/spd_sys_table.cc @@ -40,6 +40,86 @@ extern handlerton *spider_hton_ptr; extern Time_zone *spd_tz_system; static const LEX_CSTRING empty_clex_string= {"", 0}; +/** + Insert a Spider system table row. + + @param table The spider system table. + @param do_handle_error TRUE if an error message should be printed + before returning. + + @return Error code returned by the write. +*/ + +inline int spider_write_sys_table_row(TABLE *table, bool do_handle_error = TRUE) +{ + int error_num; + THD *thd = table->in_use; + + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error_num = table->file->ha_write_row(table->record[0]); + reenable_binlog(thd); + + if (error_num && do_handle_error) + table->file->print_error(error_num, MYF(0)); + + return error_num; +} + +/** + Update a Spider system table row. + + @param table The spider system table. + + @return Error code returned by the update. +*/ + +inline int spider_update_sys_table_row(TABLE *table) +{ + int error_num; + THD *thd = table->in_use; + + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error_num = table->file->ha_update_row(table->record[1], table->record[0]); + reenable_binlog(thd); + + if (error_num) + { + if (error_num == HA_ERR_RECORD_IS_THE_SAME) + error_num = 0; + else + table->file->print_error(error_num, MYF(0)); + } + + return error_num; +} + +/** + Delete a Spider system table row. + + @param table The spider system table. + @param record_number Location of the record: 0 or 1. + @param do_handle_error TRUE if an error message should be printed + before returning. + + @return Error code returned by the update. +*/ + +inline int spider_delete_sys_table_row(TABLE *table, int record_number = 0, + bool do_handle_error = TRUE) +{ + int error_num; + THD *thd = table->in_use; + + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error_num = table->file->ha_delete_row(table->record[record_number]); + reenable_binlog(thd); + + if (error_num && do_handle_error) + table->file->print_error(error_num, MYF(0)); + + return error_num; +} + #if MYSQL_VERSION_ID < 50500 TABLE *spider_open_sys_table( THD *thd, @@ -1179,11 +1259,8 @@ int spider_insert_xa( table->use_all_columns(); spider_store_xa_bqual_length(table, xid); spider_store_xa_status(table, status); - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } } else { my_message(ER_SPIDER_XA_EXISTS_NUM, ER_SPIDER_XA_EXISTS_STR, MYF(0)); DBUG_RETURN(ER_SPIDER_XA_EXISTS_NUM); @@ -1213,11 +1290,8 @@ int spider_insert_xa_member( } table->use_all_columns(); spider_store_xa_member_info(table, xid, conn); - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } } else { my_message(ER_SPIDER_XA_MEMBER_EXISTS_NUM, ER_SPIDER_XA_MEMBER_EXISTS_STR, MYF(0)); @@ -1247,11 +1321,8 @@ int spider_insert_tables( SPIDER_LINK_STATUS_NO_CHANGE ? share->alter_table.tmp_link_statuses[roop_count] : SPIDER_LINK_STATUS_OK); - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } } DBUG_RETURN(0); @@ -1381,11 +1452,8 @@ int spider_log_tables_link_failed( if (table->field[3] == table->timestamp_field) table->timestamp_field->set_time(); #endif - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } DBUG_RETURN(0); } @@ -1419,11 +1487,8 @@ int spider_log_xa_failed( if (table->field[20] == table->timestamp_field) table->timestamp_field->set_time(); #endif - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } DBUG_RETURN(0); } @@ -1452,14 +1517,8 @@ int spider_update_xa( store_record(table, record[1]); table->use_all_columns(); spider_store_xa_status(table, status); - if ( - (error_num = table->file->ha_update_row( - table->record[1], table->record[0])) && - error_num != HA_ERR_RECORD_IS_THE_SAME - ) { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_update_sys_table_row(table))) DBUG_RETURN(error_num); - } } DBUG_RETURN(0); @@ -1492,14 +1551,8 @@ int spider_update_tables_name( store_record(table, record[1]); table->use_all_columns(); spider_store_tables_name(table, to, strlen(to)); - if ( - (error_num = table->file->ha_update_row( - table->record[1], table->record[0])) && - error_num != HA_ERR_RECORD_IS_THE_SAME - ) { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_update_sys_table_row(table))) DBUG_RETURN(error_num); - } } roop_count++; } @@ -1543,11 +1596,8 @@ int spider_update_tables_priority( SPIDER_LINK_STATUS_NO_CHANGE ? alter_table->tmp_link_statuses[roop_count] : SPIDER_LINK_STATUS_OK); - if ((error_num = table->file->ha_write_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_write_sys_table_row(table))) DBUG_RETURN(error_num); - } roop_count++; } while (roop_count < (int) alter_table->all_link_count); DBUG_RETURN(0); @@ -1563,14 +1613,8 @@ int spider_update_tables_priority( spider_store_tables_connect_info(table, alter_table, roop_count); spider_store_tables_link_status(table, alter_table->tmp_link_statuses[roop_count]); - if ( - (error_num = table->file->ha_update_row( - table->record[1], table->record[0])) && - error_num != HA_ERR_RECORD_IS_THE_SAME - ) { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_update_sys_table_row(table))) DBUG_RETURN(error_num); - } } } while (TRUE) @@ -1588,11 +1632,8 @@ int spider_update_tables_priority( table->file->print_error(error_num, MYF(0)); DBUG_RETURN(error_num); } - if ((error_num = table->file->ha_delete_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_delete_sys_table_row(table))) DBUG_RETURN(error_num); - } } roop_count++; } @@ -1628,14 +1669,8 @@ int spider_update_tables_link_status( store_record(table, record[1]); table->use_all_columns(); spider_store_tables_link_status(table, link_status); - if ( - (error_num = table->file->ha_update_row( - table->record[1], table->record[0])) && - error_num != HA_ERR_RECORD_IS_THE_SAME - ) { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_update_sys_table_row(table))) DBUG_RETURN(error_num); - } } DBUG_RETURN(0); @@ -1662,11 +1697,8 @@ int spider_delete_xa( MYF(0)); DBUG_RETURN(ER_SPIDER_XA_NOT_EXISTS_NUM); } else { - if ((error_num = table->file->ha_delete_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_delete_sys_table_row(table))) DBUG_RETURN(error_num); - } } DBUG_RETURN(0); @@ -1693,7 +1725,7 @@ int spider_delete_xa_member( DBUG_RETURN(0); } else { do { - if ((error_num = table->file->ha_delete_row(table->record[0]))) + if ((error_num = spider_delete_sys_table_row(table, 0, FALSE))) { spider_sys_index_end(table); table->file->print_error(error_num, MYF(0)); @@ -1728,11 +1760,8 @@ int spider_delete_tables( if ((error_num = spider_check_sys_table(table, table_key))) break; else { - if ((error_num = table->file->ha_delete_row(table->record[0]))) - { - table->file->print_error(error_num, MYF(0)); + if ((error_num = spider_delete_sys_table_row(table))) DBUG_RETURN(error_num); - } } roop_count++; } @@ -3123,7 +3152,7 @@ int spider_sys_replace( char table_key[MAX_KEY_LENGTH]; DBUG_ENTER("spider_sys_replace"); - while ((error_num = table->file->ha_write_row(table->record[0]))) + while ((error_num = spider_write_sys_table_row(table, FALSE))) { if ( table->file->is_fatal_error(error_num, HA_CHECK_DUP) || @@ -3175,13 +3204,11 @@ int spider_sys_replace( last_uniq_key && !table->file->referenced_by_foreign_key() ) { - error_num = table->file->ha_update_row(table->record[1], - table->record[0]); - if (error_num && error_num != HA_ERR_RECORD_IS_THE_SAME) + if ((error_num = spider_update_sys_table_row(table))) goto error; DBUG_RETURN(0); } else { - if ((error_num = table->file->ha_delete_row(table->record[1]))) + if ((error_num = spider_delete_sys_table_row(table, 1, FALSE))) goto error; *modified_non_trans_table = TRUE; } diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result index 2e9faddbaff..3804a583dc3 100644 --- a/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result +++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/mdev6657.result @@ -10,7 +10,7 @@ col3 smallint(5) NOT NULL DEFAULT '1', filler varchar(255) DEFAULT NULL, KEY pk_ersatz(col1,col2,col3), KEY key1 (col1,col2) USING BTREE -) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA; +) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1; insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2; insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2; insert into t3 select 1410799999+a, 12345, 7890, 'data' from t2; @@ -34,7 +34,7 @@ from t3 where col1 <= 1410799999 order by col1 desc,col2 desc,col3 desc limit 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 2001 Using where; Using index +1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index # The same query but the constant is bigger. # The query should use range(PRIMARY), not full index scan: explain @@ -43,5 +43,5 @@ from t3 where col1 <= 1412199999 order by col1 desc, col2 desc, col3 desc limit 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL 15001 Using where; Using index +1 SIMPLE t3 range pk_ersatz,key1 pk_ersatz 4 NULL # Using where; Using index drop table t1,t2,t3; diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test index a809c3faf06..b723a5d72e8 100644 --- a/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test +++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/mdev6657.test @@ -15,7 +15,7 @@ CREATE TABLE t3 ( filler varchar(255) DEFAULT NULL, KEY pk_ersatz(col1,col2,col3), KEY key1 (col1,col2) USING BTREE -) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1 COMPRESSION=TOKUDB_LZMA; +) ENGINE=TokuDB DEFAULT CHARSET=latin1 PACK_KEYS=1; insert into t3 select 1300000000+a, 12345, 7890, 'data' from t2; insert into t3 select 1400000000+a, 12345, 7890, 'data' from t2; @@ -35,6 +35,7 @@ insert into t3 select 1412099999+a, 12345, 7890, 'data' from t2; insert into t3 select 1412199999+a, 12345, 7890, 'data' from t2; --echo # The following must use range(PRIMARY): +--replace_column 9 # explain select col1,col2,col3 from t3 @@ -43,6 +44,7 @@ order by col1 desc,col2 desc,col3 desc limit 1; --echo # The same query but the constant is bigger. --echo # The query should use range(PRIMARY), not full index scan: +--replace_column 9 # explain select col1,col2,col3 from t3 diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c index 622183d527a..73dc443f782 100644 --- a/tests/mysql_client_fw.c +++ b/tests/mysql_client_fw.c @@ -1419,8 +1419,7 @@ int main(int argc, char **argv) for (i= 0; i < argc; i++) original_argv[i]= strdup(argv[i]); - if (load_defaults("my", client_test_load_default_groups, &argc, &argv)) - exit(1); + load_defaults_or_exit("my", client_test_load_default_groups, &argc, &argv); get_options(&argc, &argv); /* Set main opt_count. */ diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 0289e26ad05..e90453411cb 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7115,11 +7115,7 @@ static void test_embedded_start_stop() MY_INIT(argv[0]); /* Load the client defaults from the .cnf file[s]. */ - if (load_defaults("my", client_test_load_default_groups, &argc, &argv)) - { - myerror("load_defaults failed"); - exit(1); - } + load_defaults_or_exit("my", client_test_load_default_groups, &argc, &argv); /* Parse the options (including the ones given from defaults files). */ get_options(&argc, &argv); @@ -7167,12 +7163,7 @@ static void test_embedded_start_stop() MY_INIT(argv[0]); - if (load_defaults("my", client_test_load_default_groups, &argc, &argv)) - { - myerror("load_defaults failed \n "); - exit(1); - } - + load_defaults_or_exit("my", client_test_load_default_groups, &argc, &argv); get_options(&argc, &argv); /* Must start the main embedded server again after the test. */ @@ -20205,6 +20196,7 @@ static void test_proxy_header_localhost() /* Proxy header ignoring */ static void test_proxy_header_ignore() { + int rc; MYSQL *m = mysql_client_init(NULL); v2_proxy_header v2_header; DIE_UNLESS(m != NULL); @@ -20222,7 +20214,7 @@ static void test_proxy_header_ignore() mysql_close(m); /* test for connection denied with empty proxy_protocol_networks */ - int rc = mysql_query(mysql, "select @@proxy_protocol_networks into @sv_proxy_protocol_networks"); + rc = mysql_query(mysql, "select @@proxy_protocol_networks into @sv_proxy_protocol_networks"); myquery(rc); mysql_query(mysql, "set global proxy_protocol_networks=default"); myquery(rc); diff --git a/tests/thread_test.c b/tests/thread_test.c index bf0fb8ea2c0..38e453e9cb8 100644 --- a/tests/thread_test.c +++ b/tests/thread_test.c @@ -168,8 +168,8 @@ static void get_options(int argc, char **argv) { int ho_error; - if ((ho_error= load_defaults("my",load_default_groups,&argc,&argv)) || - (ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) + load_defaults_or_exit("my", load_default_groups, &argc, &argv); + if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); free_defaults(argv); |