1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-02 14:22:51 +03:00

Merge 10.11 into 11.0

This commit is contained in:
Marko Mäkelä
2024-03-28 10:51:36 +02:00
490 changed files with 14843 additions and 4704 deletions

View File

@ -510,9 +510,9 @@ mini-benchmark:
- | - |
mariadb --skip-column-names -e "SELECT @@version, @@version_comment" | tee /tmp/version mariadb --skip-column-names -e "SELECT @@version, @@version_comment" | tee /tmp/version
grep $MARIADB_MAJOR_VERSION /tmp/version || echo "MariaDB didn't install properly" grep $MARIADB_MAJOR_VERSION /tmp/version || echo "MariaDB didn't install properly"
- yum install -y sysbench procps-ng perf util-linux || yum install -y https://kojipkgs.fedoraproject.org//packages/luajit/2.0.4/3.el7/x86_64/luajit-2.0.4-3.el7.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/sysbench/1.0.17/2.el7/x86_64/sysbench-1.0.17-2.el7.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/ck/0.5.2/2.el7/x86_64/ck-0.5.2-2.el7.x86_64.rpm - yum install -y sysbench procps-ng perf flamegraph flamegraph-stackcollapse-perf util-linux dnf-utils
- /usr/share/mysql/mini-benchmark - /usr/share/mysql/mini-benchmark
- cp -av */sysbench-run-*.log */metrics.txt .. # Move files one level down so they can be saved as artifacts - cp -av */sysbench-run-*.log */metrics.txt . # Move files one level down so they can be saved as artifacts
artifacts: artifacts:
when: always when: always
paths: paths:

View File

@ -615,7 +615,7 @@ void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds,
const char *from); const char *from);
ATTRIBUTE_NORETURN ATTRIBUTE_NORETURN
static void cleanup_and_exit(int exit_code); static void cleanup_and_exit(int exit_code, bool called_from_die);
ATTRIBUTE_NORETURN ATTRIBUTE_NORETURN
static void really_die(const char *msg); static void really_die(const char *msg);
@ -932,6 +932,7 @@ pthread_attr_t cn_thd_attrib;
pthread_handler_t connection_thread(void *arg) pthread_handler_t connection_thread(void *arg)
{ {
struct st_connection *cn= (struct st_connection*)arg; struct st_connection *cn= (struct st_connection*)arg;
DBUG_ENTER("connection_thread");
mysql_thread_init(); mysql_thread_init();
while (cn->command != EMB_END_CONNECTION) while (cn->command != EMB_END_CONNECTION)
@ -943,6 +944,7 @@ pthread_handler_t connection_thread(void *arg)
pthread_cond_wait(&cn->query_cond, &cn->query_mutex); pthread_cond_wait(&cn->query_cond, &cn->query_mutex);
pthread_mutex_unlock(&cn->query_mutex); pthread_mutex_unlock(&cn->query_mutex);
} }
DBUG_PRINT("info", ("executing command: %d", cn->command));
switch (cn->command) switch (cn->command)
{ {
case EMB_END_CONNECTION: case EMB_END_CONNECTION:
@ -963,24 +965,26 @@ pthread_handler_t connection_thread(void *arg)
break; break;
case EMB_CLOSE_STMT: case EMB_CLOSE_STMT:
cn->result= mysql_stmt_close(cn->stmt); cn->result= mysql_stmt_close(cn->stmt);
cn->stmt= 0;
break; break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
cn->command= 0;
pthread_mutex_lock(&cn->result_mutex); pthread_mutex_lock(&cn->result_mutex);
cn->query_done= 1; cn->query_done= 1;
cn->command= 0;
pthread_cond_signal(&cn->result_cond); pthread_cond_signal(&cn->result_cond);
pthread_mutex_unlock(&cn->result_mutex); pthread_mutex_unlock(&cn->result_mutex);
} }
end_thread: end_thread:
cn->query_done= 1; DBUG_ASSERT(cn->stmt == 0);
mysql_close(cn->mysql); mysql_close(cn->mysql);
cn->mysql= 0; cn->mysql= 0;
cn->query_done= 1;
mysql_thread_end(); mysql_thread_end();
pthread_exit(0); pthread_exit(0);
return 0; DBUG_RETURN(0);
} }
static void wait_query_thread_done(struct st_connection *con) static void wait_query_thread_done(struct st_connection *con)
@ -998,12 +1002,16 @@ static void wait_query_thread_done(struct st_connection *con)
static void signal_connection_thd(struct st_connection *cn, int command) static void signal_connection_thd(struct st_connection *cn, int command)
{ {
DBUG_ENTER("signal_connection_thd");
DBUG_PRINT("enter", ("command: %d", command));
DBUG_ASSERT(cn->has_thread); DBUG_ASSERT(cn->has_thread);
cn->query_done= 0; cn->query_done= 0;
cn->command= command;
pthread_mutex_lock(&cn->query_mutex); pthread_mutex_lock(&cn->query_mutex);
cn->command= command;
pthread_cond_signal(&cn->query_cond); pthread_cond_signal(&cn->query_cond);
pthread_mutex_unlock(&cn->query_mutex); pthread_mutex_unlock(&cn->query_mutex);
DBUG_VOID_RETURN;
} }
@ -1068,27 +1076,37 @@ static int do_stmt_execute(struct st_connection *cn)
static int do_stmt_close(struct st_connection *cn) static int do_stmt_close(struct st_connection *cn)
{ {
DBUG_ENTER("do_stmt_close"); DBUG_ENTER("do_stmt_close");
/* The cn->stmt is already set. */
if (!cn->has_thread) if (!cn->has_thread)
DBUG_RETURN(mysql_stmt_close(cn->stmt)); {
/* The cn->stmt is already set. */
int res= mysql_stmt_close(cn->stmt);
cn->stmt= 0;
DBUG_RETURN(res);
}
wait_query_thread_done(cn);
signal_connection_thd(cn, EMB_CLOSE_STMT); signal_connection_thd(cn, EMB_CLOSE_STMT);
wait_query_thread_done(cn); wait_query_thread_done(cn);
DBUG_ASSERT(cn->stmt == 0);
DBUG_RETURN(cn->result); DBUG_RETURN(cn->result);
} }
static void emb_close_connection(struct st_connection *cn) static void emb_close_connection(struct st_connection *cn)
{ {
DBUG_ENTER("emb_close_connection");
if (!cn->has_thread) if (!cn->has_thread)
return; DBUG_VOID_RETURN;
wait_query_thread_done(cn); wait_query_thread_done(cn);
signal_connection_thd(cn, EMB_END_CONNECTION); signal_connection_thd(cn, EMB_END_CONNECTION);
pthread_join(cn->tid, NULL); pthread_join(cn->tid, NULL);
cn->has_thread= FALSE; cn->has_thread= FALSE;
DBUG_ASSERT(cn->mysql == 0);
DBUG_ASSERT(cn->stmt == 0);
pthread_mutex_destroy(&cn->query_mutex); pthread_mutex_destroy(&cn->query_mutex);
pthread_cond_destroy(&cn->query_cond); pthread_cond_destroy(&cn->query_cond);
pthread_mutex_destroy(&cn->result_mutex); pthread_mutex_destroy(&cn->result_mutex);
pthread_cond_destroy(&cn->result_cond); pthread_cond_destroy(&cn->result_cond);
DBUG_VOID_RETURN;
} }
@ -1112,7 +1130,13 @@ static void init_connection_thd(struct st_connection *cn)
#define do_read_query_result(cn) mysql_read_query_result(cn->mysql) #define do_read_query_result(cn) mysql_read_query_result(cn->mysql)
#define do_stmt_prepare(cn, q, q_len) mysql_stmt_prepare(cn->stmt, q, (ulong)q_len) #define do_stmt_prepare(cn, q, q_len) mysql_stmt_prepare(cn->stmt, q, (ulong)q_len)
#define do_stmt_execute(cn) mysql_stmt_execute(cn->stmt) #define do_stmt_execute(cn) mysql_stmt_execute(cn->stmt)
#define do_stmt_close(cn) mysql_stmt_close(cn->stmt)
static int do_stmt_close(struct st_connection *cn)
{
int res= mysql_stmt_close(cn->stmt);
cn->stmt= 0;
return res;
}
#endif /*EMBEDDED_LIBRARY*/ #endif /*EMBEDDED_LIBRARY*/
@ -1440,7 +1464,6 @@ void close_statements()
{ {
if (con->stmt) if (con->stmt)
do_stmt_close(con); do_stmt_close(con);
con->stmt= 0;
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -1512,7 +1535,8 @@ void ha_pre_shutdown();
#endif #endif
ATTRIBUTE_NORETURN static void cleanup_and_exit(int exit_code) ATTRIBUTE_NORETURN static void cleanup_and_exit(int exit_code,
bool called_from_die)
{ {
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
if (server_initialized) if (server_initialized)
@ -1525,16 +1549,6 @@ ATTRIBUTE_NORETURN static void cleanup_and_exit(int exit_code)
if (server_initialized) if (server_initialized)
mysql_server_end(); mysql_server_end();
/*
mysqltest is fundamentally written in a way that makes impossible
to free all memory before exit (consider memory allocated
for frame local DYNAMIC_STRING's and die() invoked down the stack.
We close stderr here to stop unavoidable safemalloc reports
from polluting the output.
*/
fclose(stderr);
my_end(my_end_arg); my_end(my_end_arg);
if (!silent) { if (!silent) {
@ -1554,6 +1568,11 @@ ATTRIBUTE_NORETURN static void cleanup_and_exit(int exit_code)
} }
} }
/*
Report memory leaks, if not called from 'die()', as die() will not release
all memory.
*/
sf_leaking_memory= called_from_die;
exit(exit_code); exit(exit_code);
} }
@ -1620,7 +1639,7 @@ static void really_die(const char *msg)
second time, just exit second time, just exit
*/ */
if (dying) if (dying)
cleanup_and_exit(1); cleanup_and_exit(1, 1);
dying= 1; dying= 1;
log_file.show_tail(opt_tail_lines); log_file.show_tail(opt_tail_lines);
@ -1632,7 +1651,7 @@ static void really_die(const char *msg)
if (cur_con && !cur_con->pending) if (cur_con && !cur_con->pending)
show_warnings_before_error(cur_con->mysql); show_warnings_before_error(cur_con->mysql);
cleanup_and_exit(1); cleanup_and_exit(1, 1);
} }
void report_or_die(const char *fmt, ...) void report_or_die(const char *fmt, ...)
@ -1686,7 +1705,7 @@ void abort_not_supported_test(const char *fmt, ...)
} }
va_end(args); va_end(args);
cleanup_and_exit(62); cleanup_and_exit(62, 0);
} }
@ -2233,14 +2252,14 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
check_result check_result
RETURN VALUES RETURN VALUES
error - the function will not return 0 ok
1 error
*/ */
void check_result() int check_result()
{ {
const char *mess= 0; const char *mess= 0;
int error= 1;
DBUG_ENTER("check_result"); DBUG_ENTER("check_result");
DBUG_ASSERT(result_file_name); DBUG_ASSERT(result_file_name);
DBUG_PRINT("enter", ("result_file_name: %s", result_file_name)); DBUG_PRINT("enter", ("result_file_name: %s", result_file_name));
@ -2248,7 +2267,10 @@ void check_result()
switch (compare_files(log_file.file_name(), result_file_name)) { switch (compare_files(log_file.file_name(), result_file_name)) {
case RESULT_OK: case RESULT_OK:
if (!error_count) if (!error_count)
{
error= 0;
break; /* ok */ break; /* ok */
}
mess= "Got errors while running test"; mess= "Got errors while running test";
/* Fallthrough */ /* Fallthrough */
case RESULT_LENGTH_MISMATCH: case RESULT_LENGTH_MISMATCH:
@ -2287,14 +2309,13 @@ void check_result()
log_file.file_name(), reject_file, errno); log_file.file_name(), reject_file, errno);
show_diff(NULL, result_file_name, reject_file); show_diff(NULL, result_file_name, reject_file);
die("%s", mess); fprintf(stderr, "%s", mess);
break; break;
} }
default: /* impossible */ default: /* impossible */
die("Unknown error code from dyn_string_cmp()"); die("Unknown error code from dyn_string_cmp()");
} }
DBUG_RETURN(error);
DBUG_VOID_RETURN;
} }
@ -5693,7 +5714,6 @@ void do_close_connection(struct st_command *command)
#endif /*!EMBEDDED_LIBRARY*/ #endif /*!EMBEDDED_LIBRARY*/
if (con->stmt) if (con->stmt)
do_stmt_close(con); do_stmt_close(con);
con->stmt= 0;
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
/* /*
As query could be still executed in a separate thread As query could be still executed in a separate thread
@ -7375,17 +7395,17 @@ get_one_option(const struct my_option *opt, const char *argument, const char *)
break; break;
case 'V': case 'V':
print_version(); print_version();
exit(0); cleanup_and_exit(0,0);
case OPT_MYSQL_PROTOCOL: case OPT_MYSQL_PROTOCOL:
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib, if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
opt->name)) <= 0) opt->name)) <= 0)
exit(1); cleanup_and_exit(1,0);
#endif #endif
break; break;
case '?': case '?':
usage(); usage();
exit(0); cleanup_and_exit(0,0);
} }
return 0; return 0;
} }
@ -7397,12 +7417,12 @@ int parse_args(int argc, char **argv)
default_argv= argv; default_argv= argv;
if ((handle_options(&argc, &argv, my_long_options, get_one_option))) if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(1); cleanup_and_exit(1, 0);
if (argc > 1) if (argc > 1)
{ {
usage(); usage();
exit(1); cleanup_and_exit(1, 0);
} }
if (argc == 1) if (argc == 1)
opt_db= *argv; opt_db= *argv;
@ -8523,7 +8543,7 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
my_bool ds_res_1st_execution_init = FALSE; my_bool ds_res_1st_execution_init = FALSE;
my_bool compare_2nd_execution = TRUE; my_bool compare_2nd_execution = TRUE;
int query_match_ps2_re; int query_match_ps2_re;
MYSQL_RES *res;
DBUG_ENTER("run_query_stmt"); DBUG_ENTER("run_query_stmt");
DBUG_PRINT("query", ("'%-.60s'", query)); DBUG_PRINT("query", ("'%-.60s'", query));
DBUG_PRINT("info", DBUG_PRINT("info",
@ -8729,10 +8749,13 @@ void run_query_stmt(struct st_connection *cn, struct st_command *command,
The --enable_prepare_warnings command can be used to change this so The --enable_prepare_warnings command can be used to change this so
that warnings from both the prepare and execute phase are shown. that warnings from both the prepare and execute phase are shown.
*/ */
if ((mysql_stmt_result_metadata(stmt) != NULL) && if ((res= mysql_stmt_result_metadata(stmt)))
!disable_warnings && {
if (!disable_warnings &&
!prepare_warnings_enabled) !prepare_warnings_enabled)
dynstr_set(&ds_prepare_warnings, NULL); dynstr_set(&ds_prepare_warnings, NULL);
mysql_free_result(res);
}
/* /*
Fetch info before fetching warnings, since it will be reset Fetch info before fetching warnings, since it will be reset
@ -9860,6 +9883,7 @@ static sig_handler signal_handler(int sig)
fflush(stderr); fflush(stderr);
my_write_core(sig); my_write_core(sig);
#ifndef _WIN32 #ifndef _WIN32
sf_leaking_memory= 1;
exit(1); // Shouldn't get here but just in case exit(1); // Shouldn't get here but just in case
#endif #endif
} }
@ -9933,12 +9957,10 @@ int main(int argc, char **argv)
uint command_executed= 0, last_command_executed= 0; uint command_executed= 0, last_command_executed= 0;
char save_file[FN_REFLEN]; char save_file[FN_REFLEN];
bool empty_result= FALSE; bool empty_result= FALSE;
int error= 0;
MY_INIT(argv[0]); MY_INIT(argv[0]);
DBUG_ENTER("main"); DBUG_ENTER("main");
/* mysqltest has no way to free all its memory correctly */
sf_leaking_memory= 1;
save_file[0]= 0; save_file[0]= 0;
TMPDIR[0]= 0; TMPDIR[0]= 0;
@ -10631,7 +10653,7 @@ int main(int argc, char **argv)
die("Test ended with parsing disabled"); die("Test ended with parsing disabled");
/* /*
The whole test has been executed _successfully_. The whole test has been executed successfully.
Time to compare result or save it to record file. Time to compare result or save it to record file.
The entire output from test is in the log file The entire output from test is in the log file
*/ */
@ -10654,7 +10676,7 @@ int main(int argc, char **argv)
else else
{ {
/* Check that the output from test is equal to result file */ /* Check that the output from test is equal to result file */
check_result(); error= check_result();
} }
} }
} }
@ -10664,7 +10686,8 @@ int main(int argc, char **argv)
if (! result_file_name || record || if (! result_file_name || record ||
compare_files (log_file.file_name(), result_file_name)) compare_files (log_file.file_name(), result_file_name))
{ {
die("The test didn't produce any output"); fprintf(stderr, "mysqltest: The test didn't produce any output\n");
error= 1;
} }
else else
{ {
@ -10673,12 +10696,15 @@ int main(int argc, char **argv)
} }
if (!command_executed && result_file_name && !empty_result) if (!command_executed && result_file_name && !empty_result)
die("No queries executed but non-empty result file found!"); {
fprintf(stderr, "mysqltest: No queries executed but non-empty result file found!\n");
error= 1;
}
if (!error)
verbose_msg("Test has succeeded!"); verbose_msg("Test has succeeded!");
timer_output(); timer_output();
/* Yes, if we got this far the test has succeeded! Sakila smiles */ cleanup_and_exit(error, 0);
cleanup_and_exit(0);
return 0; /* Keep compiler happy too */ return 0; /* Keep compiler happy too */
} }

View File

@ -53,7 +53,7 @@ MACRO (MYSQL_USE_BUNDLED_SSL)
${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl ${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl
${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl/wolfssl ${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl/wolfssl
) )
SET(SSL_LIBRARIES wolfssl wolfcrypt) SET(SSL_LIBRARIES wolfssl)
SET(SSL_INCLUDE_DIRS ${INC_DIRS}) SET(SSL_INCLUDE_DIRS ${INC_DIRS})
SET(SSL_DEFINES "-DHAVE_OPENSSL -DHAVE_WOLFSSL -DWOLFSSL_USER_SETTINGS") SET(SSL_DEFINES "-DHAVE_OPENSSL -DHAVE_WOLFSSL -DWOLFSSL_USER_SETTINGS")
SET(HAVE_ERR_remove_thread_state ON CACHE INTERNAL "wolfssl doesn't have ERR_remove_thread_state") SET(HAVE_ERR_remove_thread_state ON CACHE INTERNAL "wolfssl doesn't have ERR_remove_thread_state")

View File

@ -31,6 +31,7 @@ ENDIF()
INCLUDE_DIRECTORIES( INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/storage/maria
${CMAKE_CURRENT_SOURCE_DIR}/quicklz ${CMAKE_CURRENT_SOURCE_DIR}/quicklz
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
) )
@ -71,8 +72,12 @@ MYSQL_ADD_EXECUTABLE(mariadb-backup
xbstream_write.cc xbstream_write.cc
backup_mysql.cc backup_mysql.cc
backup_copy.cc backup_copy.cc
xb_plugin.cc encryption_plugin.cc
${PROJECT_BINARY_DIR}/sql/sql_builtin.cc ${PROJECT_BINARY_DIR}/sql/sql_builtin.cc
aria_backup_client.cc
thread_pool.cc
ddl_log.cc
common_engine.cc
${PROJECT_SOURCE_DIR}/sql/net_serv.cc ${PROJECT_SOURCE_DIR}/sql/net_serv.cc
${PROJECT_SOURCE_DIR}/libmysqld/libmysql.c ${PROJECT_SOURCE_DIR}/libmysqld/libmysql.c
COMPONENT Backup COMPONENT Backup
@ -81,7 +86,8 @@ MYSQL_ADD_EXECUTABLE(mariadb-backup
# Export all symbols on Unix, for better crash callstacks # Export all symbols on Unix, for better crash callstacks
SET_TARGET_PROPERTIES(mariadb-backup PROPERTIES ENABLE_EXPORTS TRUE) SET_TARGET_PROPERTIES(mariadb-backup PROPERTIES ENABLE_EXPORTS TRUE)
TARGET_LINK_LIBRARIES(mariadb-backup sql sql_builtins) TARGET_LINK_LIBRARIES(mariadb-backup sql sql_builtins aria)
IF(NOT HAVE_SYSTEM_REGEX) IF(NOT HAVE_SYSTEM_REGEX)
TARGET_LINK_LIBRARIES(mariadb-backup pcre2-posix) TARGET_LINK_LIBRARIES(mariadb-backup pcre2-posix)
ENDIF() ENDIF()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
#pragma once
#include "my_global.h"
#include "datasink.h"
#include "backup_mysql.h"
#include "thread_pool.h"
#include "xtrabackup.h"
namespace aria {
bool prepare(const char *target_dir);
class BackupImpl;
class Backup {
public:
Backup(const char *datadir_path,
const char *aria_log_path,
ds_ctxt_t *datasink,
std::vector<MYSQL *> &con_pool, ThreadPool &thread_pool);
~Backup();
Backup (Backup &&other) = delete;
Backup & operator= (Backup &&other) = delete;
Backup(const Backup &) = delete;
Backup & operator= (const Backup &) = delete;
bool init();
bool start(bool no_lock);
bool wait_for_finish();
bool copy_offline_tables(
const std::unordered_set<table_key_t> *exclude_tables, bool no_lock,
bool copy_stats);
bool finalize();
bool copy_log_tail();
void set_post_copy_table_hook(const post_copy_table_hook_t &hook);
private:
BackupImpl *m_backup_impl;
};
} // namespace aria

View File

@ -41,6 +41,9 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
*******************************************************/ *******************************************************/
#include <my_global.h> #include <my_global.h>
#include <my_config.h>
#include <unireg.h>
#include <datadict.h>
#include <os0file.h> #include <os0file.h>
#include <my_dir.h> #include <my_dir.h>
#include <ut0mem.h> #include <ut0mem.h>
@ -66,19 +69,26 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
#include <aclapi.h> #include <aclapi.h>
#endif #endif
#ifdef MYSQL_CLIENT
#define WAS_MYSQL_CLIENT 1
#undef MYSQL_CLIENT
#endif
#include "table.h"
#ifdef WAS_MYSQL_CLIENT
#define MYSQL_CLIENT 1
#undef WAS_MYSQL_CLIENT
#endif
#define ROCKSDB_BACKUP_DIR "#rocksdb" #define ROCKSDB_BACKUP_DIR "#rocksdb"
/* list of files to sync for --rsync mode */
static std::set<std::string> rsync_list;
/* locations of tablespaces read from .isl files */ /* locations of tablespaces read from .isl files */
static std::map<std::string, std::string> tablespace_locations; static std::map<std::string, std::string> tablespace_locations;
/* Whether LOCK BINLOG FOR BACKUP has been issued during backup */ /* Whether LOCK BINLOG FOR BACKUP has been issued during backup */
bool binlog_locked; bool binlog_locked;
static void rocksdb_create_checkpoint();
static bool has_rocksdb_plugin();
static void rocksdb_backup_checkpoint(ds_ctxt *ds_data); static void rocksdb_backup_checkpoint(ds_ctxt *ds_data);
static void rocksdb_copy_back(ds_ctxt *ds_data); static void rocksdb_copy_back(ds_ctxt *ds_data);
@ -135,10 +145,6 @@ struct datadir_thread_ctxt_t {
bool ret; bool ret;
}; };
static bool backup_files_from_datadir(ds_ctxt_t *ds_data,
const char *dir_path,
const char *prefix);
/************************************************************************ /************************************************************************
Retirn true if character if file separator */ Retirn true if character if file separator */
bool bool
@ -585,7 +591,6 @@ datafile_read(datafile_cur_t *cursor)
Check to see if a file exists. Check to see if a file exists.
Takes name of the file to check. Takes name of the file to check.
@return true if file exists. */ @return true if file exists. */
static
bool bool
file_exists(const char *filename) file_exists(const char *filename)
{ {
@ -601,7 +606,6 @@ file_exists(const char *filename)
/************************************************************************ /************************************************************************
Trim leading slashes from absolute path so it becomes relative */ Trim leading slashes from absolute path so it becomes relative */
static
const char * const char *
trim_dotslash(const char *path) trim_dotslash(const char *path)
{ {
@ -634,7 +638,7 @@ ends_with(const char *str, const char *suffix)
&& strcmp(str + str_len - suffix_len, suffix) == 0); && strcmp(str + str_len - suffix_len, suffix) == 0);
} }
static bool starts_with(const char *str, const char *prefix) bool starts_with(const char *str, const char *prefix)
{ {
return strncmp(str, prefix, strlen(prefix)) == 0; return strncmp(str, prefix, strlen(prefix)) == 0;
} }
@ -785,7 +789,6 @@ directory_exists_and_empty(const char *dir, const char *comment)
/************************************************************************ /************************************************************************
Check if file name ends with given set of suffixes. Check if file name ends with given set of suffixes.
@return true if it does. */ @return true if it does. */
static
bool bool
filename_matches(const char *filename, const char **ext_list) filename_matches(const char *filename, const char **ext_list)
{ {
@ -800,6 +803,115 @@ filename_matches(const char *filename, const char **ext_list)
return(false); return(false);
} }
// TODO: the code can be used to find storage engine of partitions
/*
static
bool is_aria_frm_or_par(const char *path) {
if (!ends_with(path, ".frm") && !ends_with(path, ".par"))
return false;
const char *frm_path = path;
if (ends_with(path, ".par")) {
size_t frm_path_len = strlen(path);
DBUG_ASSERT(frm_path_len > strlen("frm"));
frm_path = strdup(path);
strcpy(const_cast<char *>(frm_path) + frm_path_len - strlen("frm"), "frm");
}
bool result = false;
File file;
uchar header[40];
legacy_db_type dbt;
if ((file= mysql_file_open(key_file_frm, frm_path, O_RDONLY | O_SHARE, MYF(0)))
< 0)
goto err;
if (mysql_file_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP)))
goto err;
if (!strncmp((char*) header, "TYPE=VIEW\n", 10))
goto err;
if (!is_binary_frm_header(header))
goto err;
dbt = (legacy_db_type)header[3];
if (dbt == DB_TYPE_ARIA) {
result = true;
}
else if (dbt == DB_TYPE_PARTITION_DB) {
MY_STAT state;
uchar *frm_image= 0;
// uint n_length;
if (mysql_file_fstat(file, &state, MYF(MY_WME)))
goto err;
if (mysql_file_seek(file, 0, SEEK_SET, MYF(MY_WME)))
goto err;
if (read_string(file, &frm_image, (size_t)state.st_size))
goto err;
dbt = (legacy_db_type)frm_image[61];
if (dbt == DB_TYPE_ARIA) {
result = true;
}
my_free(frm_image);
}
err:
if (file >= 0)
mysql_file_close(file, MYF(MY_WME));
if (frm_path != path)
free(const_cast<char *>(frm_path));
return result;
}
*/
void parse_db_table_from_file_path(
const char *filepath, char *dbname, char *tablename) {
dbname[0] = '\0';
tablename[0] = '\0';
const char *dbname_start = nullptr;
const char *tablename_start = filepath;
const char *const_ptr;
while ((const_ptr = strchr(tablename_start, FN_LIBCHAR)) != NULL) {
dbname_start = tablename_start;
tablename_start = const_ptr + 1;
}
if (!dbname_start)
return;
size_t dbname_len = tablename_start - dbname_start - 1;
if (dbname_len >= FN_REFLEN)
dbname_len = FN_REFLEN-1;
strmake(dbname, dbname_start, dbname_len);
strmake(tablename, tablename_start, FN_REFLEN-1);
char *ptr;
if ((ptr = strchr(tablename, '.')))
*ptr = '\0';
if ((ptr = strstr(tablename, "#P#")))
*ptr = '\0';
}
bool is_system_table(const char *dbname, const char *tablename)
{
DBUG_ASSERT(dbname);
DBUG_ASSERT(tablename);
LEX_CSTRING lex_dbname;
LEX_CSTRING lex_tablename;
lex_dbname.str = dbname;
lex_dbname.length = strlen(dbname);
lex_tablename.str = tablename;
lex_tablename.length = strlen(tablename);
TABLE_CATEGORY tg = get_table_category(&lex_dbname, &lex_tablename);
return (tg == TABLE_CATEGORY_LOG) || (tg == TABLE_CATEGORY_SYSTEM);
}
/************************************************************************ /************************************************************************
Copy data file for backup. Also check if it is allowed to copy by Copy data file for backup. Also check if it is allowed to copy by
@ -810,8 +922,7 @@ static
bool bool
datafile_copy_backup(ds_ctxt *ds_data, const char *filepath, uint thread_n) datafile_copy_backup(ds_ctxt *ds_data, const char *filepath, uint thread_n)
{ {
const char *ext_list[] = {"frm", "isl", "MYD", "MYI", "MAD", "MAI", const char *ext_list[] = {".frm", ".isl", ".TRG", ".TRN", ".opt", ".par",
"MRG", "TRG", "TRN", "ARM", "ARZ", "CSM", "CSV", "opt", "par",
NULL}; NULL};
/* Get the name and the path for the tablespace. node->name always /* Get the name and the path for the tablespace. node->name always
@ -835,41 +946,6 @@ datafile_copy_backup(ds_ctxt *ds_data, const char *filepath, uint thread_n)
return(true); return(true);
} }
/************************************************************************
Same as datafile_copy_backup, but put file name into the list for
rsync command. */
static
bool
datafile_rsync_backup(const char *filepath, bool save_to_list, FILE *f)
{
const char *ext_list[] = {"frm", "isl", "MYD", "MYI", "MAD", "MAI",
"MRG", "TRG", "TRN", "ARM", "ARZ", "CSM", "CSV", "opt", "par",
NULL};
/* Get the name and the path for the tablespace. node->name always
contains the path (which may be absolute for remote tablespaces in
5.6+). space->name contains the tablespace name in the form
"./database/table.ibd" (in 5.5-) or "database/table" (in 5.6+). For a
multi-node shared tablespace, space->name contains the name of the first
node, but that's irrelevant, since we only need node_name to match them
against filters, and the shared tablespace is always copied regardless
of the filters value. */
if (check_if_skip_table(filepath)) {
return(true);
}
if (filename_matches(filepath, ext_list)) {
fprintf(f, "%s\n", filepath);
if (save_to_list) {
rsync_list.insert(filepath);
}
}
return(true);
}
bool ds_ctxt_t::backup_file_print_buf(const char *filename, bool ds_ctxt_t::backup_file_print_buf(const char *filename,
const char *buf, int buf_len) const char *buf, int buf_len)
{ {
@ -1004,16 +1080,15 @@ Copy file for backup/restore.
bool bool
ds_ctxt_t::copy_file(const char *src_file_path, ds_ctxt_t::copy_file(const char *src_file_path,
const char *dst_file_path, const char *dst_file_path,
uint thread_n) uint thread_n,
bool rewrite)
{ {
char dst_name[FN_REFLEN]; char dst_name[FN_REFLEN];
ds_file_t *dstfile = NULL; ds_file_t *dstfile = NULL;
datafile_cur_t cursor; datafile_cur_t cursor;
xb_fil_cur_result_t res; xb_fil_cur_result_t res;
DBUG_ASSERT(datasink->remove); DBUG_ASSERT(datasink->remove);
const char *dst_path = const char *dst_path = convert_dst(dst_file_path);
(xtrabackup_copy_back || xtrabackup_move_back)?
dst_file_path : trim_dotslash(dst_file_path);
if (!datafile_open(src_file_path, &cursor, thread_n)) { if (!datafile_open(src_file_path, &cursor, thread_n)) {
goto error_close; goto error_close;
@ -1021,7 +1096,7 @@ ds_ctxt_t::copy_file(const char *src_file_path,
strncpy(dst_name, cursor.rel_path, sizeof(dst_name)); strncpy(dst_name, cursor.rel_path, sizeof(dst_name));
dstfile = ds_open(this, dst_path, &cursor.statinfo); dstfile = ds_open(this, dst_path, &cursor.statinfo, rewrite);
if (dstfile == NULL) { if (dstfile == NULL) {
msg(thread_n,"error: " msg(thread_n,"error: "
"cannot open the destination stream for %s", dst_name); "cannot open the destination stream for %s", dst_name);
@ -1245,278 +1320,45 @@ cleanup:
} }
static
bool bool
backup_files(ds_ctxt *ds_data, const char *from, bool prep_mode) backup_files(ds_ctxt *ds_data, const char *from)
{ {
char rsync_tmpfile_name[FN_REFLEN];
FILE *rsync_tmpfile = NULL;
datadir_iter_t *it; datadir_iter_t *it;
datadir_node_t node; datadir_node_t node;
bool ret = true; bool ret = true;
msg("Starting to backup non-InnoDB tables and files");
if (prep_mode && !opt_rsync) {
return(true);
}
if (opt_rsync) {
snprintf(rsync_tmpfile_name, sizeof(rsync_tmpfile_name),
"%s/%s%d", opt_mysql_tmpdir,
"xtrabackup_rsyncfiles_pass",
prep_mode ? 1 : 2);
rsync_tmpfile = fopen(rsync_tmpfile_name, "w");
if (rsync_tmpfile == NULL) {
msg("Error: can't create file %s",
rsync_tmpfile_name);
return(false);
}
}
msg("Starting %s non-InnoDB tables and files",
prep_mode ? "prep copy of" : "to backup");
datadir_node_init(&node); datadir_node_init(&node);
it = datadir_iter_new(from); it = datadir_iter_new(from);
while (datadir_iter_next(it, &node)) { while (datadir_iter_next(it, &node)) {
if (!node.is_empty_dir) { if (!node.is_empty_dir) {
if (opt_rsync) {
ret = datafile_rsync_backup(node.filepath,
!prep_mode, rsync_tmpfile);
} else {
ret = datafile_copy_backup(ds_data, node.filepath, 1); ret = datafile_copy_backup(ds_data, node.filepath, 1);
}
if (!ret) { if (!ret) {
msg("Failed to copy file %s", node.filepath); msg("Failed to copy file %s", node.filepath);
goto out; goto out;
} }
} else if (!prep_mode) { } else {
/* backup fake file into empty directory */ /* backup fake file into empty directory */
char path[FN_REFLEN]; char path[FN_REFLEN];
snprintf(path, sizeof(path), snprintf(path, sizeof(path), "%s/db.opt", node.filepath);
"%s/db.opt", node.filepath); if (!(ret = ds_data->backup_file_printf(trim_dotslash(path), "%s", ""))) {
if (!(ret = ds_data->backup_file_printf(
trim_dotslash(path), "%s", ""))) {
msg("Failed to create file %s", path); msg("Failed to create file %s", path);
goto out; goto out;
} }
} }
} }
msg("Finished backing up non-InnoDB tables and files");
if (opt_rsync) {
std::stringstream cmd;
int err;
if (buffer_pool_filename && file_exists(buffer_pool_filename)) {
fprintf(rsync_tmpfile, "%s\n", buffer_pool_filename);
rsync_list.insert(buffer_pool_filename);
}
if (file_exists("ib_lru_dump")) {
fprintf(rsync_tmpfile, "%s\n", "ib_lru_dump");
rsync_list.insert("ib_lru_dump");
}
fclose(rsync_tmpfile);
rsync_tmpfile = NULL;
cmd << "rsync -t . --files-from=" << rsync_tmpfile_name
<< " " << xtrabackup_target_dir;
msg("Starting rsync as: %s", cmd.str().c_str());
if ((err = system(cmd.str().c_str()) && !prep_mode) != 0) {
msg("Error: rsync failed with error code %d", err);
ret = false;
goto out;
}
msg("rsync finished successfully.");
if (!prep_mode && !opt_no_lock) {
char path[FN_REFLEN];
char dst_path[FN_REFLEN];
char *newline;
/* Remove files that have been removed between first and
second passes. Cannot use "rsync --delete" because it
does not work with --files-from. */
snprintf(rsync_tmpfile_name, sizeof(rsync_tmpfile_name),
"%s/%s", opt_mysql_tmpdir,
"xtrabackup_rsyncfiles_pass1");
rsync_tmpfile = fopen(rsync_tmpfile_name, "r");
if (rsync_tmpfile == NULL) {
msg("Error: can't open file %s",
rsync_tmpfile_name);
ret = false;
goto out;
}
while (fgets(path, sizeof(path), rsync_tmpfile)) {
newline = strchr(path, '\n');
if (newline) {
*newline = 0;
}
if (rsync_list.count(path) < 1) {
snprintf(dst_path, sizeof(dst_path),
"%s/%s", xtrabackup_target_dir,
path);
msg("Removing %s", dst_path);
unlink(dst_path);
}
}
fclose(rsync_tmpfile);
rsync_tmpfile = NULL;
}
}
msg("Finished %s non-InnoDB tables and files",
prep_mode ? "a prep copy of" : "backing up");
out: out:
datadir_iter_free(it); datadir_iter_free(it);
datadir_node_free(&node); datadir_node_free(&node);
if (rsync_tmpfile != NULL) {
fclose(rsync_tmpfile);
}
return(ret); return(ret);
} }
lsn_t get_current_lsn(MYSQL *connection)
{
static const char lsn_prefix[] = "\nLog sequence number ";
lsn_t lsn = 0;
if (MYSQL_RES *res = xb_mysql_query(connection,
"SHOW ENGINE INNODB STATUS",
true, false)) {
if (MYSQL_ROW row = mysql_fetch_row(res)) {
const char *p= strstr(row[2], lsn_prefix);
DBUG_ASSERT(p);
if (p) {
p += sizeof lsn_prefix - 1;
lsn = lsn_t(strtoll(p, NULL, 10));
}
}
mysql_free_result(res);
}
return lsn;
}
lsn_t server_lsn_after_lock; lsn_t server_lsn_after_lock;
extern void backup_wait_for_lsn(lsn_t lsn); extern void backup_wait_for_lsn(lsn_t lsn);
/** Start --backup */
bool backup_start(ds_ctxt *ds_data, ds_ctxt *ds_meta,
CorruptedPages &corrupted_pages)
{
if (!opt_no_lock) {
if (opt_safe_slave_backup) {
if (!wait_for_safe_slave(mysql_connection)) {
return(false);
}
}
if (!backup_files(ds_data, fil_path_to_mysql_datadir, true)) {
return(false);
}
history_lock_time = time(NULL);
if (!lock_tables(mysql_connection)) {
return(false);
}
server_lsn_after_lock = get_current_lsn(mysql_connection);
}
if (!backup_files(ds_data, fil_path_to_mysql_datadir, false)) {
return(false);
}
if (!backup_files_from_datadir(ds_data, fil_path_to_mysql_datadir,
"aws-kms-key") ||
!backup_files_from_datadir(ds_data,
aria_log_dir_path,
"aria_log")) {
return false;
}
if (has_rocksdb_plugin()) {
rocksdb_create_checkpoint();
}
msg("Waiting for log copy thread to read lsn %llu", (ulonglong)server_lsn_after_lock);
backup_wait_for_lsn(server_lsn_after_lock);
DBUG_EXECUTE_FOR_KEY("sleep_after_waiting_for_lsn", {},
{
ulong milliseconds = strtoul(dbug_val, NULL, 10);
msg("sleep_after_waiting_for_lsn");
my_sleep(milliseconds*1000UL);
});
corrupted_pages.backup_fix_ddl(ds_data, ds_meta);
// There is no need to stop slave thread before coping non-Innodb data when
// --no-lock option is used because --no-lock option requires that no DDL or
// DML to non-transaction tables can occur.
if (opt_no_lock) {
if (opt_safe_slave_backup) {
if (!wait_for_safe_slave(mysql_connection)) {
return(false);
}
}
}
if (opt_slave_info) {
lock_binlog_maybe(mysql_connection);
if (!write_slave_info(ds_data, mysql_connection)) {
return(false);
}
}
/* The only reason why Galera/binlog info is written before
wait_for_ibbackup_log_copy_finish() is that after that call the xtrabackup
binary will start streamig a temporary copy of REDO log to stdout and
thus, any streaming from innobackupex would interfere. The only way to
avoid that is to have a single process, i.e. merge innobackupex and
xtrabackup. */
if (opt_galera_info) {
if (!write_galera_info(ds_data, mysql_connection)) {
return(false);
}
}
if (opt_binlog_info == BINLOG_INFO_ON) {
lock_binlog_maybe(mysql_connection);
write_binlog_info(ds_data, mysql_connection);
}
if (!opt_no_lock) {
msg("Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...");
xb_mysql_query(mysql_connection,
"FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS", false);
}
return(true);
}
/** Release resources after backup_start() */ /** Release resources after backup_start() */
void backup_release() void backup_release()
{ {
/* release all locks */
if (!opt_no_lock) {
unlock_all(mysql_connection);
history_lock_time = 0;
} else {
history_lock_time = time(NULL) - history_lock_time;
}
if (opt_lock_ddl_per_table) { if (opt_lock_ddl_per_table) {
mdl_unlock_all(); mdl_unlock_all();
} }
@ -1534,7 +1376,7 @@ static const char *default_buffer_pool_file = "ib_buffer_pool";
bool backup_finish(ds_ctxt *ds_data) bool backup_finish(ds_ctxt *ds_data)
{ {
/* Copy buffer pool dump or LRU dump */ /* Copy buffer pool dump or LRU dump */
if (!opt_rsync && opt_galera_info) { if (opt_galera_info) {
if (buffer_pool_filename && file_exists(buffer_pool_filename)) { if (buffer_pool_filename && file_exists(buffer_pool_filename)) {
ds_data->copy_file(buffer_pool_filename, default_buffer_pool_file, 0); ds_data->copy_file(buffer_pool_filename, default_buffer_pool_file, 0);
} }
@ -1893,8 +1735,6 @@ copy_back()
return(false); return(false);
} }
srv_max_n_threads = 1000;
/* copy undo tablespaces */ /* copy undo tablespaces */
Copy_back_dst_dir dst_dir_buf; Copy_back_dst_dir dst_dir_buf;
@ -1922,7 +1762,8 @@ copy_back()
dst_dir = dst_dir_buf.make(srv_log_group_home_dir); dst_dir = dst_dir_buf.make(srv_log_group_home_dir);
/* --backup generates a single ib_logfile0, which we must copy. */ /* --backup generates a single LOG_FILE_NAME, which we must copy
if it exists. */
ds_tmp = ds_create(dst_dir, DS_TYPE_LOCAL); ds_tmp = ds_create(dst_dir, DS_TYPE_LOCAL);
if (!(ret = copy_or_move_file(ds_tmp, LOG_FILE_NAME, LOG_FILE_NAME, if (!(ret = copy_or_move_file(ds_tmp, LOG_FILE_NAME, LOG_FILE_NAME,
@ -2155,8 +1996,6 @@ decrypt_decompress()
bool ret; bool ret;
datadir_iter_t *it = NULL; datadir_iter_t *it = NULL;
srv_max_n_threads = 1000;
/* cd to backup directory */ /* cd to backup directory */
if (my_setwd(xtrabackup_target_dir, MYF(MY_WME))) if (my_setwd(xtrabackup_target_dir, MYF(MY_WME)))
{ {
@ -2169,8 +2008,6 @@ decrypt_decompress()
it = datadir_iter_new(".", false); it = datadir_iter_new(".", false);
ut_a(xtrabackup_parallel >= 0);
ret = run_data_threads(it, decrypt_decompress_thread_func, ret = run_data_threads(it, decrypt_decompress_thread_func,
xtrabackup_parallel ? xtrabackup_parallel : 1); xtrabackup_parallel ? xtrabackup_parallel : 1);
@ -2192,7 +2029,7 @@ decrypt_decompress()
Do not copy the Innodb files (ibdata1, redo log files), Do not copy the Innodb files (ibdata1, redo log files),
as this is done in a separate step. as this is done in a separate step.
*/ */
static bool backup_files_from_datadir(ds_ctxt_t *ds_data, bool backup_files_from_datadir(ds_ctxt_t *ds_data,
const char *dir_path, const char *dir_path,
const char *prefix) const char *prefix)
{ {
@ -2218,10 +2055,6 @@ static bool backup_files_from_datadir(ds_ctxt_t *ds_data,
pname = info.name; pname = info.name;
if (!starts_with(pname, prefix)) if (!starts_with(pname, prefix))
/* For ES exchange the above line with the following code:
(!xtrabackup_prepare || !xtrabackup_incremental_dir ||
!starts_with(pname, "aria_log")))
*/
continue; continue;
if (xtrabackup_prepare && xtrabackup_incremental_dir && if (xtrabackup_prepare && xtrabackup_incremental_dir &&
@ -2244,7 +2077,7 @@ static int rocksdb_remove_checkpoint_directory()
return 0; return 0;
} }
static bool has_rocksdb_plugin() bool has_rocksdb_plugin()
{ {
static bool first_time = true; static bool first_time = true;
static bool has_plugin= false; static bool has_plugin= false;
@ -2390,7 +2223,7 @@ static void rocksdb_unlock_checkpoint()
#define MARIADB_CHECKPOINT_DIR "mariabackup-checkpoint" #define MARIADB_CHECKPOINT_DIR "mariabackup-checkpoint"
static char rocksdb_checkpoint_dir[FN_REFLEN]; static char rocksdb_checkpoint_dir[FN_REFLEN];
static void rocksdb_create_checkpoint() void rocksdb_create_checkpoint()
{ {
MYSQL_RES *result = xb_mysql_query(mysql_connection, "SELECT @@rocksdb_datadir,@@datadir", true, true); MYSQL_RES *result = xb_mysql_query(mysql_connection, "SELECT @@rocksdb_datadir,@@datadir", true, true);
MYSQL_ROW row = mysql_fetch_row(result); MYSQL_ROW row = mysql_fetch_row(result);
@ -2470,3 +2303,39 @@ static void rocksdb_copy_back(ds_ctxt *ds_data) {
mkdirp(rocksdb_home_dir, 0777, MYF(0)); mkdirp(rocksdb_home_dir, 0777, MYF(0));
ds_data->copy_or_move_dir(ROCKSDB_BACKUP_DIR, rocksdb_home_dir, xtrabackup_copy_back, xtrabackup_copy_back); ds_data->copy_or_move_dir(ROCKSDB_BACKUP_DIR, rocksdb_home_dir, xtrabackup_copy_back, xtrabackup_copy_back);
} }
void foreach_file_in_db_dirs(
const char *dir_path, std::function<bool(const char *)> func) {
DBUG_ASSERT(dir_path);
datadir_iter_t *it;
datadir_node_t node;
datadir_node_init(&node);
it = datadir_iter_new(dir_path);
while (datadir_iter_next(it, &node))
if (!node.is_empty_dir && !func(node.filepath))
break;
datadir_iter_free(it);
datadir_node_free(&node);
}
void foreach_file_in_datadir(
const char *dir_path, std::function<bool(const char *)> func)
{
DBUG_ASSERT(dir_path);
os_file_dir_t dir = os_file_opendir(dir_path);
os_file_stat_t info;
while (os_file_readdir_next_file(dir_path, dir, &info) == 0) {
if (info.type != OS_FILE_TYPE_FILE)
continue;
const char *pname = strrchr(info.name, IF_WIN('\\', '/'));
if (!pname)
pname = info.name;
if (!func(pname))
break;
}
os_file_closedir(dir);
}

View File

@ -2,6 +2,7 @@
#ifndef XTRABACKUP_BACKUP_COPY_H #ifndef XTRABACKUP_BACKUP_COPY_H
#define XTRABACKUP_BACKUP_COPY_H #define XTRABACKUP_BACKUP_COPY_H
#include <functional>
#include <my_global.h> #include <my_global.h>
#include <mysql.h> #include <mysql.h>
#include "datasink.h" #include "datasink.h"
@ -21,8 +22,7 @@ bool
equal_paths(const char *first, const char *second); equal_paths(const char *first, const char *second);
/** Start --backup */ /** Start --backup */
bool backup_start(ds_ctxt *ds_data, ds_ctxt *ds_meta, bool backup_files(ds_ctxt *ds_data, const char *from);
CorruptedPages &corrupted_pages);
/** Release resources after backup_start() */ /** Release resources after backup_start() */
void backup_release(); void backup_release();
/** Finish after backup_start() and backup_release() */ /** Finish after backup_start() and backup_release() */
@ -38,7 +38,25 @@ is_path_separator(char);
bool bool
directory_exists(const char *dir, bool create); directory_exists(const char *dir, bool create);
lsn_t bool has_rocksdb_plugin();
get_current_lsn(MYSQL *connection); void rocksdb_create_checkpoint();
void foreach_file_in_db_dirs(
const char *dir_path, std::function<bool(const char *)> func);
void foreach_file_in_datadir(
const char *dir_path, std::function<bool(const char *)> func);
bool ends_with(const char *str, const char *suffix);
bool starts_with(const char *str, const char *prefix);
void parse_db_table_from_file_path(
const char *filepath, char *dbname, char *tablename);
const char *trim_dotslash(const char *path);
bool backup_files_from_datadir(ds_ctxt_t *ds_data,
const char *dir_path,
const char *prefix);
bool is_system_table(const char *dbname, const char *tablename);
std::unique_ptr<std::vector<std::string>>
find_files(const char *dir_path, const char *prefix, const char *suffix);
bool file_exists(const char *filename);
bool
filename_matches(const char *filename, const char **ext_list);
#endif #endif

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "my_dbug.h" #include "my_dbug.h"
#ifndef DBUG_OFF #ifndef DBUG_OFF
char *dbug_mariabackup_get_val(const char *event, fil_space_t::name_type key); char *dbug_mariabackup_get_val(const char *event, fil_space_t::name_type key);
/* /*
@ -14,11 +15,21 @@ To use this facility, you need to
for the variable) for the variable)
3. start mariabackup with --dbug=+d,debug_mariabackup_events 3. start mariabackup with --dbug=+d,debug_mariabackup_events
*/ */
extern void dbug_mariabackup_event(
const char *event, const fil_space_t::name_type key, bool need_lock);
#define DBUG_MARIABACKUP_EVENT(A, B) \
DBUG_EXECUTE_IF("mariabackup_events", \
dbug_mariabackup_event(A,B,false););
#define DBUG_MARIABACKUP_EVENT_LOCK(A, B) \
DBUG_EXECUTE_IF("mariabackup_events", \
dbug_mariabackup_event(A,B, true););
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) \ #define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) \
DBUG_EXECUTE_IF("mariabackup_inject_code", \ DBUG_EXECUTE_IF("mariabackup_inject_code", {\
{ char *dbug_val= dbug_mariabackup_get_val(EVENT, KEY); \ char *dbug_val = dbug_mariabackup_get_val(EVENT, KEY); \
if (dbug_val) CODE }) if (dbug_val && *dbug_val) CODE \
})
#else #else
#define DBUG_MARIABACKUP_EVENT(A,B)
#define DBUG_MARIABACKUP_EVENT_LOCK(A,B)
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) #define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE)
#endif #endif

View File

@ -60,10 +60,11 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA
#include "backup_copy.h" #include "backup_copy.h"
#include "backup_mysql.h" #include "backup_mysql.h"
#include "mysqld.h" #include "mysqld.h"
#include "xb_plugin.h" #include "encryption_plugin.h"
#include <sstream> #include <sstream>
#include <sql_error.h> #include <sql_error.h>
#include "page0zip.h" #include "page0zip.h"
#include "backup_debug.h"
char *tool_name; char *tool_name;
char tool_args[2048]; char tool_args[2048];
@ -71,7 +72,7 @@ char tool_args[2048];
ulong mysql_server_version; ulong mysql_server_version;
/* server capabilities */ /* server capabilities */
bool have_backup_locks = false; bool have_changed_page_bitmaps = false;
bool have_lock_wait_timeout = false; bool have_lock_wait_timeout = false;
bool have_galera_enabled = false; bool have_galera_enabled = false;
bool have_multi_threaded_slave = false; bool have_multi_threaded_slave = false;
@ -251,13 +252,14 @@ struct mysql_variable {
static static
void uint
read_mysql_variables(MYSQL *connection, const char *query, mysql_variable *vars, read_mysql_variables(MYSQL *connection, const char *query, mysql_variable *vars,
bool vertical_result) bool vertical_result)
{ {
MYSQL_RES *mysql_result; MYSQL_RES *mysql_result;
MYSQL_ROW row; MYSQL_ROW row;
mysql_variable *var; mysql_variable *var;
uint n_values=0;
mysql_result = xb_mysql_query(connection, query, true); mysql_result = xb_mysql_query(connection, query, true);
@ -271,6 +273,7 @@ read_mysql_variables(MYSQL *connection, const char *query, mysql_variable *vars,
if (strcmp(var->name, name) == 0 if (strcmp(var->name, name) == 0
&& value != NULL) { && value != NULL) {
*(var->value) = strdup(value); *(var->value) = strdup(value);
n_values++;
} }
} }
} }
@ -287,6 +290,7 @@ read_mysql_variables(MYSQL *connection, const char *query, mysql_variable *vars,
if (strcmp(var->name, name) == 0 if (strcmp(var->name, name) == 0
&& value != NULL) { && value != NULL) {
*(var->value) = strdup(value); *(var->value) = strdup(value);
n_values++;
} }
} }
++i; ++i;
@ -295,6 +299,7 @@ read_mysql_variables(MYSQL *connection, const char *query, mysql_variable *vars,
} }
mysql_free_result(mysql_result); mysql_free_result(mysql_result);
return n_values;
} }
@ -359,7 +364,6 @@ bool get_mysql_vars(MYSQL *connection)
{ {
char *gtid_mode_var= NULL; char *gtid_mode_var= NULL;
char *version_var= NULL; char *version_var= NULL;
char *have_backup_locks_var= NULL;
char *log_bin_var= NULL; char *log_bin_var= NULL;
char *lock_wait_timeout_var= NULL; char *lock_wait_timeout_var= NULL;
char *wsrep_on_var= NULL; char *wsrep_on_var= NULL;
@ -384,7 +388,6 @@ bool get_mysql_vars(MYSQL *connection)
bool ret= true; bool ret= true;
mysql_variable mysql_vars[]= { mysql_variable mysql_vars[]= {
{"have_backup_locks", &have_backup_locks_var},
{"log_bin", &log_bin_var}, {"log_bin", &log_bin_var},
{"lock_wait_timeout", &lock_wait_timeout_var}, {"lock_wait_timeout", &lock_wait_timeout_var},
{"gtid_mode", &gtid_mode_var}, {"gtid_mode", &gtid_mode_var},
@ -409,11 +412,6 @@ bool get_mysql_vars(MYSQL *connection)
read_mysql_variables(connection, "SHOW VARIABLES", mysql_vars, true); read_mysql_variables(connection, "SHOW VARIABLES", mysql_vars, true);
if (have_backup_locks_var != NULL && !opt_no_backup_locks)
{
have_backup_locks= true;
}
if (opt_binlog_info == BINLOG_INFO_AUTO) if (opt_binlog_info == BINLOG_INFO_AUTO)
{ {
if (log_bin_var != NULL && !strcmp(log_bin_var, "ON")) if (log_bin_var != NULL && !strcmp(log_bin_var, "ON"))
@ -867,11 +865,11 @@ static void stop_query_killer()
/*********************************************************************//** /*********************************************************************//**
Function acquires either a backup tables lock, if supported Function acquires backup locks
by the server, or a global read lock (FLUSH TABLES WITH READ LOCK)
otherwise.
@returns true if lock acquired */ @returns true if lock acquired */
bool lock_tables(MYSQL *connection)
bool
lock_for_backup_stage_start(MYSQL *connection)
{ {
if (have_lock_wait_timeout || opt_lock_wait_timeout) if (have_lock_wait_timeout || opt_lock_wait_timeout)
{ {
@ -884,12 +882,6 @@ bool lock_tables(MYSQL *connection)
xb_mysql_query(connection, buf, false); xb_mysql_query(connection, buf, false);
} }
if (have_backup_locks)
{
msg("Executing LOCK TABLES FOR BACKUP...");
xb_mysql_query(connection, "LOCK TABLES FOR BACKUP", false);
return (true);
}
if (opt_lock_wait_timeout) if (opt_lock_wait_timeout)
{ {
@ -914,8 +906,6 @@ bool lock_tables(MYSQL *connection)
xb_mysql_query(connection, "BACKUP STAGE START", true); xb_mysql_query(connection, "BACKUP STAGE START", true);
DBUG_MARIABACKUP_EVENT("after_backup_stage_start", {}); DBUG_MARIABACKUP_EVENT("after_backup_stage_start", {});
xb_mysql_query(connection, "BACKUP STAGE BLOCK_COMMIT", true);
DBUG_MARIABACKUP_EVENT("after_backup_stage_block_commit", {});
/* Set the maximum supported session value for /* Set the maximum supported session value for
lock_wait_timeout to prevent unnecessary timeouts when the lock_wait_timeout to prevent unnecessary timeouts when the
global value is changed from the default */ global value is changed from the default */
@ -931,24 +921,68 @@ bool lock_tables(MYSQL *connection)
return (true); return (true);
} }
/*********************************************************************//**
If backup locks are used, execute LOCK BINLOG FOR BACKUP provided that we are
not in the --no-lock mode and the lock has not been acquired already.
@returns true if lock acquired */
bool bool
lock_binlog_maybe(MYSQL *connection) lock_for_backup_stage_flush(MYSQL *connection) {
{ if (opt_kill_long_queries_timeout) {
if (have_backup_locks && !opt_no_lock && !binlog_locked) { start_query_killer();
msg("Executing LOCK BINLOG FOR BACKUP..."); }
xb_mysql_query(connection, "LOCK BINLOG FOR BACKUP", false); xb_mysql_query(connection, "BACKUP STAGE FLUSH", true);
binlog_locked = true; if (opt_kill_long_queries_timeout) {
stop_query_killer();
return(true); }
return true;
} }
return(false); bool
lock_for_backup_stage_block_ddl(MYSQL *connection) {
if (opt_kill_long_queries_timeout) {
start_query_killer();
}
xb_mysql_query(connection, "BACKUP STAGE BLOCK_DDL", true);
DBUG_MARIABACKUP_EVENT("after_backup_stage_block_ddl", {});
if (opt_kill_long_queries_timeout) {
stop_query_killer();
}
return true;
} }
bool
lock_for_backup_stage_commit(MYSQL *connection) {
if (opt_kill_long_queries_timeout) {
start_query_killer();
}
xb_mysql_query(connection, "BACKUP STAGE BLOCK_COMMIT", true);
DBUG_MARIABACKUP_EVENT("after_backup_stage_block_commit", {});
if (opt_kill_long_queries_timeout) {
stop_query_killer();
}
return true;
}
bool backup_lock(MYSQL *con, const char *table_name) {
static const std::string backup_lock_prefix("BACKUP LOCK ");
std::string backup_lock_query = backup_lock_prefix + table_name;
xb_mysql_query(con, backup_lock_query.c_str(), true);
return true;
}
bool backup_unlock(MYSQL *con) {
xb_mysql_query(con, "BACKUP UNLOCK", true);
return true;
}
std::unordered_set<std::string>
get_tables_in_use(MYSQL *con) {
std::unordered_set<std::string> result;
MYSQL_RES *q_res =
xb_mysql_query(con, "SHOW OPEN TABLES WHERE In_use = 1", true);
while (MYSQL_ROW row = mysql_fetch_row(q_res)) {
auto tk = table_key(row[0], row[1]);
msg("Table %s is in use", tk.c_str());
result.insert(std::move(tk));
}
return result;
}
/*********************************************************************//** /*********************************************************************//**
Releases either global read lock acquired with FTWRL and the binlog Releases either global read lock acquired with FTWRL and the binlog
@ -1383,15 +1417,33 @@ write_slave_info(ds_ctxt *datasink, MYSQL *connection)
/*********************************************************************//** /*********************************************************************//**
Retrieves MySQL Galera and Retrieves MySQL Galera and saves it in a file. It also prints it to stdout.
saves it in a file. It also prints it to stdout. */
We should create xtrabackup_galelera_info file even when backup locks
are used because donor's wsrep_gtid_domain_id is needed later in joiner.
Note that at this stage wsrep_local_state_uuid and wsrep_last_committed
are inconsistent but they are not used in joiner. Joiner will rewrite this file
at mariabackup --prepare phase and thus there is extra file donor_galera_info.
Information is needed to maitain wsrep_gtid_domain_id and gtid_binlog_pos
same across the cluster. If joiner node have different wsrep_gtid_domain_id
we should still receive effective domain id from the donor node,
and use it.
*/
bool bool
write_galera_info(ds_ctxt *datasink, MYSQL *connection) write_galera_info(ds_ctxt *datasink, MYSQL *connection)
{ {
char *state_uuid = NULL, *state_uuid55 = NULL; char *state_uuid = NULL, *state_uuid55 = NULL;
char *last_committed = NULL, *last_committed55 = NULL; char *last_committed = NULL, *last_committed55 = NULL;
char *domain_id = NULL, *domain_id55 = NULL; char *domain_id = NULL, *domain_id55 = NULL;
bool result; bool result=true;
uint n_values=0;
char *wsrep_on = NULL, *wsrep_on55 = NULL;
mysql_variable vars[] = {
{"Wsrep_on", &wsrep_on},
{"wsrep_on", &wsrep_on55},
{NULL, NULL}
};
mysql_variable status[] = { mysql_variable status[] = {
{"Wsrep_local_state_uuid", &state_uuid}, {"Wsrep_local_state_uuid", &state_uuid},
@ -1407,27 +1459,30 @@ write_galera_info(ds_ctxt *datasink, MYSQL *connection)
{NULL, NULL} {NULL, NULL}
}; };
/* When backup locks are supported by the server, we should skip n_values= read_mysql_variables(connection, "SHOW VARIABLES", vars, true);
creating xtrabackup_galera_info file on the backup stage, because
wsrep_local_state_uuid and wsrep_last_committed will be inconsistent if (n_values == 0 || (wsrep_on == NULL && wsrep_on55 == NULL))
without blocking commits. The state file will be created on the prepare {
stage using the WSREP recovery procedure. */ msg("Server is not Galera node thus --galera-info does not "
if (have_backup_locks) { "have any effect.");
return(true); result = true;
goto cleanup;
} }
read_mysql_variables(connection, "SHOW STATUS", status, true); read_mysql_variables(connection, "SHOW STATUS", status, true);
if ((state_uuid == NULL && state_uuid55 == NULL) if ((state_uuid == NULL && state_uuid55 == NULL)
|| (last_committed == NULL && last_committed55 == NULL)) { || (last_committed == NULL && last_committed55 == NULL))
{
msg("Warning: failed to get master wsrep state from SHOW STATUS."); msg("Warning: failed to get master wsrep state from SHOW STATUS.");
result = true; result = true;
goto cleanup; goto cleanup;
} }
read_mysql_variables(connection, "SHOW VARIABLES LIKE 'wsrep%'", value, true); n_values= read_mysql_variables(connection, "SHOW VARIABLES LIKE 'wsrep%'", value, true);
if (domain_id == NULL && domain_id55 == NULL) { if (n_values == 0 || (domain_id == NULL && domain_id55 == NULL))
{
msg("Warning: failed to get master wsrep state from SHOW VARIABLES."); msg("Warning: failed to get master wsrep state from SHOW VARIABLES.");
result = true; result = true;
goto cleanup; goto cleanup;
@ -1445,10 +1500,15 @@ write_galera_info(ds_ctxt *datasink, MYSQL *connection)
last_committed ? last_committed : last_committed55, last_committed ? last_committed : last_committed55,
domain_id ? domain_id : domain_id55); domain_id ? domain_id : domain_id55);
} }
if (result) if (result)
{
write_current_binlog_file(datasink, connection); write_current_binlog_file(datasink, connection);
}
if (result)
msg("Writing Galera info succeeded with %s:%s %s",
state_uuid ? state_uuid : state_uuid55,
last_committed ? last_committed : last_committed55,
domain_id ? domain_id : domain_id55);
cleanup: cleanup:
free_mysql_variables(status); free_mysql_variables(status);
@ -1496,8 +1556,6 @@ write_current_binlog_file(ds_ctxt *datasink, MYSQL *connection)
if (gtid_exists) { if (gtid_exists) {
size_t log_bin_dir_length; size_t log_bin_dir_length;
lock_binlog_maybe(connection);
xb_mysql_query(connection, "FLUSH BINARY LOGS", false); xb_mysql_query(connection, "FLUSH BINARY LOGS", false);
read_mysql_variables(connection, "SHOW MASTER STATUS", read_mysql_variables(connection, "SHOW MASTER STATUS",
@ -1856,13 +1914,13 @@ bool write_backup_config_file(ds_ctxt *datasink)
srv_log_file_size, srv_log_file_size,
srv_page_size, srv_page_size,
srv_undo_dir, srv_undo_dir,
srv_undo_tablespaces, (uint) srv_undo_tablespaces,
page_zip_level, page_zip_level,
innobase_buffer_pool_filename ? innobase_buffer_pool_filename ?
"innodb_buffer_pool_filename=" : "", "innodb_buffer_pool_filename=" : "",
innobase_buffer_pool_filename ? innobase_buffer_pool_filename ?
innobase_buffer_pool_filename : "", innobase_buffer_pool_filename : "",
xb_plugin_get_config()); encryption_plugin_get_config());
return rc; return rc;
} }
@ -1987,3 +2045,23 @@ mdl_unlock_all()
mysql_close(mdl_con); mysql_close(mdl_con);
spaceid_to_tablename.clear(); spaceid_to_tablename.clear();
} }
ulonglong get_current_lsn(MYSQL *connection)
{
static const char lsn_prefix[] = "\nLog sequence number ";
ulonglong lsn = 0;
if (MYSQL_RES *res = xb_mysql_query(connection,
"SHOW ENGINE INNODB STATUS",
true, false)) {
if (MYSQL_ROW row = mysql_fetch_row(res)) {
const char *p= strstr(row[2], lsn_prefix);
DBUG_ASSERT(p);
if (p) {
p += sizeof lsn_prefix - 1;
lsn = lsn_t(strtoll(p, NULL, 10));
}
}
mysql_free_result(res);
}
return lsn;
}

View File

@ -2,12 +2,15 @@
#define XTRABACKUP_BACKUP_MYSQL_H #define XTRABACKUP_BACKUP_MYSQL_H
#include <mysql.h> #include <mysql.h>
#include <string>
#include <unordered_set>
#include "datasink.h"
/* MariaDB version */ /* MariaDB version */
extern ulong mysql_server_version; extern ulong mysql_server_version;
/* server capabilities */ /* server capabilities */
extern bool have_backup_locks; extern bool have_changed_page_bitmaps;
extern bool have_lock_wait_timeout; extern bool have_lock_wait_timeout;
extern bool have_galera_enabled; extern bool have_galera_enabled;
extern bool have_multi_threaded_slave; extern bool have_multi_threaded_slave;
@ -71,7 +74,21 @@ bool
lock_binlog_maybe(MYSQL *connection); lock_binlog_maybe(MYSQL *connection);
bool bool
lock_tables(MYSQL *connection); lock_for_backup_stage_start(MYSQL *connection);
bool
lock_for_backup_stage_flush(MYSQL *connection);
bool
lock_for_backup_stage_block_ddl(MYSQL *connection);
bool
lock_for_backup_stage_commit(MYSQL *connection);
bool backup_lock(MYSQL *con, const char *table_name);
bool backup_unlock(MYSQL *con);
std::unordered_set<std::string> get_tables_in_use(MYSQL *con);
bool bool
wait_for_safe_slave(MYSQL *connection); wait_for_safe_slave(MYSQL *connection);
@ -82,5 +99,6 @@ write_galera_info(ds_ctxt *datasink, MYSQL *connection);
bool bool
write_slave_info(ds_ctxt *datasink, MYSQL *connection); write_slave_info(ds_ctxt *datasink, MYSQL *connection);
ulonglong get_current_lsn(MYSQL *connection);
#endif #endif

View File

@ -0,0 +1,512 @@
#include "common_engine.h"
#include "backup_copy.h"
#include "xtrabackup.h"
#include "common.h"
#include "backup_debug.h"
#include <unordered_map>
#include <atomic>
#include <memory>
#include <chrono>
namespace common_engine {
class Table {
public:
Table(std::string &db, std::string &table, std::string &fs_name) :
m_db(std::move(db)), m_table(std::move(table)),
m_fs_name(std::move(fs_name)) {}
virtual ~Table() {}
void add_file_name(const char *file_name) { m_fnames.push_back(file_name); }
virtual bool copy(ds_ctxt_t *ds, MYSQL *con, bool no_lock,
bool finalize, unsigned thread_num);
std::string &get_db() { return m_db; }
std::string &get_table() { return m_table; }
std::string &get_version() { return m_version; }
protected:
std::string m_db;
std::string m_table;
std::string m_fs_name;
std::string m_version;
std::vector<std::string> m_fnames;
};
bool
Table::copy(ds_ctxt_t *ds, MYSQL *con, bool no_lock, bool, unsigned thread_num) {
static const size_t buf_size = 10 * 1024 * 1024;
std::unique_ptr<uchar[]> buf;
bool result = false;
File frm_file = -1;
std::vector<File> files;
bool locked = false;
std::string full_tname("`");
full_tname.append(m_db).append("`.`").append(m_table).append("`");
if (!no_lock && !backup_lock(con, full_tname.c_str())) {
msg(thread_num, "Error on executing BACKUP LOCK for table %s",
full_tname.c_str());
goto exit;
}
else
locked = !no_lock;
if ((frm_file = mysql_file_open(key_file_frm, (m_fs_name + ".frm").c_str(),
O_RDONLY | O_SHARE, MYF(0))) < 0 && !m_fnames.empty() &&
!ends_with(m_fnames[0].c_str(), ".ARZ") &&
!ends_with(m_fnames[0].c_str(), ".ARM")) {
// Don't treat it as error, as the table can be dropped after it
// was added to queue for copying
result = true;
goto exit;
}
for (const auto &fname : m_fnames) {
File file = mysql_file_open(0, fname.c_str(),O_RDONLY | O_SHARE, MYF(0));
if (file < 0) {
msg(thread_num, "Error on file %s open during %s table copy",
fname.c_str(), full_tname.c_str());
goto exit;
}
files.push_back(file);
}
if (locked && !backup_unlock(con)) {
msg(thread_num, "Error on BACKUP UNLOCK for table %s", full_tname.c_str());
locked = false;
goto exit;
}
locked = false;
buf.reset(new uchar[buf_size]);
for (size_t i = 0; i < m_fnames.size(); ++i) {
ds_file_t *dst_file = nullptr;
size_t bytes_read;
size_t copied_size = 0;
MY_STAT stat_info;
if (my_fstat(files[i], &stat_info, MYF(0))) {
msg(thread_num, "error: failed to get stat info for file %s of "
"table %s", m_fnames[i].c_str(), full_tname.c_str());
goto exit;
}
const char *dst_path =
(xtrabackup_copy_back || xtrabackup_move_back) ?
m_fnames[i].c_str() : trim_dotslash(m_fnames[i].c_str());
dst_file = ds_open(ds, dst_path, &stat_info, false);
if (!dst_file) {
msg(thread_num, "error: cannot open destination stream for %s, table %s",
dst_path, full_tname.c_str());
goto exit;
}
while ((bytes_read = my_read(files[i], buf.get(), buf_size, MY_WME))) {
if (bytes_read == size_t(-1)) {
msg(thread_num, "error: file %s read for table %s",
m_fnames[i].c_str(), full_tname.c_str());
ds_close(dst_file);
goto exit;
}
xtrabackup_io_throttling();
if (ds_write(dst_file, buf.get(), bytes_read)) {
msg(thread_num, "error: file %s write for table %s",
dst_path, full_tname.c_str());
ds_close(dst_file);
goto exit;
}
copied_size += bytes_read;
}
mysql_file_close(files[i], MYF(MY_WME));
files[i] = -1;
ds_close(dst_file);
msg(thread_num, "Copied file %s for table %s, %zu bytes",
m_fnames[i].c_str(), full_tname.c_str(), copied_size);
}
result = true;
#ifndef DBUG_OFF
{
std::string sql_name(m_db);
sql_name.append("/").append(m_table);
DBUG_MARIABACKUP_EVENT_LOCK("after_ce_table_copy", fil_space_t::name_type(sql_name.data(), sql_name.size()));
}
#endif // DBUG_OFF
exit:
if (frm_file >= 0) {
m_version = ::read_table_version_id(frm_file);
mysql_file_close(frm_file, MYF(MY_WME));
}
if (locked && !backup_unlock(con)) {
msg(thread_num, "Error on BACKUP UNLOCK for table %s", full_tname.c_str());
result = false;
}
for (auto file : files)
if (file >= 0)
mysql_file_close(file, MYF(MY_WME));
return result;
}
// Append-only tables
class LogTable : public Table {
public:
LogTable(std::string &db, std::string &table, std::string &fs_name) :
Table(db, table, fs_name) {}
virtual ~LogTable() { (void)close(); }
bool
copy(ds_ctxt_t *ds, MYSQL *con, bool no_lock, bool finalize,
unsigned thread_num) override;
bool close();
private:
bool open(ds_ctxt_t *ds, unsigned thread_num);
std::vector<File> m_src;
std::vector<ds_file_t *> m_dst;
};
bool
LogTable::open(ds_ctxt_t *ds, unsigned thread_num) {
DBUG_ASSERT(m_src.empty());
DBUG_ASSERT(m_dst.empty());
std::string full_tname("`");
full_tname.append(m_db).append("`.`").append(m_table).append("`");
for (const auto &fname : m_fnames) {
File file = mysql_file_open(0, fname.c_str(),O_RDONLY | O_SHARE, MYF(0));
if (file < 0) {
msg(thread_num, "Error on file %s open during %s log table copy",
fname.c_str(), full_tname.c_str());
return false;
}
m_src.push_back(file);
MY_STAT stat_info;
if (my_fstat(file, &stat_info, MYF(0))) {
msg(thread_num, "error: failed to get stat info for file %s of "
"log table %s", fname.c_str(), full_tname.c_str());
return false;
}
const char *dst_path =
(xtrabackup_copy_back || xtrabackup_move_back) ?
fname.c_str() : trim_dotslash(fname.c_str());
ds_file_t *dst_file = ds_open(ds, dst_path, &stat_info, false);
if (!dst_file) {
msg(thread_num, "error: cannot open destination stream for %s, "
"log table %s", dst_path, full_tname.c_str());
return false;
}
m_dst.push_back(dst_file);
}
File frm_file;
if ((frm_file = mysql_file_open(key_file_frm, (m_fs_name + ".frm").c_str(),
O_RDONLY | O_SHARE, MYF(0))) < 0 && !m_fnames.empty() &&
!ends_with(m_fnames[0].c_str(), ".ARZ") &&
!ends_with(m_fnames[0].c_str(), ".ARM")) {
msg(thread_num, "Error on .frm file open for log table %s",
full_tname.c_str());
return false;
}
m_version = ::read_table_version_id(frm_file);
mysql_file_close(frm_file, MYF(MY_WME));
return true;
}
bool LogTable::close() {
while (!m_src.empty()) {
auto f = m_src.back();
m_src.pop_back();
mysql_file_close(f, MYF(MY_WME));
}
while (!m_dst.empty()) {
auto f = m_dst.back();
m_dst.pop_back();
ds_close(f);
}
return true;
}
bool
LogTable::copy(ds_ctxt_t *ds, MYSQL *con, bool no_lock, bool finalize,
unsigned thread_num) {
static const size_t buf_size = 10 * 1024 * 1024;
DBUG_ASSERT(ds);
DBUG_ASSERT(con);
if (m_src.empty() && !open(ds, thread_num)) {
close();
return false;
}
DBUG_ASSERT(m_src.size() == m_dst.size());
std::unique_ptr<uchar[]> buf(new uchar[buf_size]);
for (size_t i = 0; i < m_src.size(); ++i) {
// .CSM can be rewritten (see write_meta_file() usage in ha_tina.cc)
if (!finalize && ends_with(m_fnames[i].c_str(), ".CSM"))
continue;
size_t bytes_read;
size_t copied_size = 0;
while ((bytes_read = my_read(m_src[i], buf.get(), buf_size, MY_WME))) {
if (bytes_read == size_t(-1)) {
msg(thread_num, "error: file %s read for log table %s",
m_fnames[i].c_str(),
std::string("`").append(m_db).append("`.`").
append(m_table).append("`").c_str());
close();
return false;
}
xtrabackup_io_throttling();
if (ds_write(m_dst[i], buf.get(), bytes_read)) {
msg(thread_num, "error: file %s write for log table %s",
m_fnames[i].c_str(), std::string("`").append(m_db).append("`.`").
append(m_table).append("`").c_str());
close();
return false;
}
copied_size += bytes_read;
}
msg(thread_num, "Copied file %s for log table %s, %zu bytes",
m_fnames[i].c_str(), std::string("`").append(m_db).append("`.`").
append(m_table).append("`").c_str(), copied_size);
}
return true;
}
class BackupImpl {
public:
BackupImpl(
const char *datadir_path, ds_ctxt_t *datasink,
std::vector<MYSQL *> &con_pool, ThreadPool &thread_pool) :
m_datadir_path(datadir_path), m_ds(datasink), m_con_pool(con_pool),
m_process_table_jobs(thread_pool) {}
~BackupImpl() { }
bool scan(
const std::unordered_set<std::string> &exclude_tables,
std::unordered_set<std::string> *out_processed_tables,
bool no_lock, bool collect_log_and_stats);
void set_post_copy_table_hook(const post_copy_table_hook_t &hook) {
m_table_post_copy_hook = hook;
}
bool copy_log_tables(bool finalize);
bool copy_stats_tables();
bool wait_for_finish();
bool close_log_tables();
private:
void process_table_job(Table *table, bool no_lock, bool delete_table,
bool finalize, unsigned thread_num);
const char *m_datadir_path;
ds_ctxt_t *m_ds;
std::vector<MYSQL *> &m_con_pool;
TasksGroup m_process_table_jobs;
post_copy_table_hook_t m_table_post_copy_hook;
std::unordered_map<table_key_t, std::unique_ptr<LogTable>> m_log_tables;
std::unordered_map<table_key_t, std::unique_ptr<Table>> m_stats_tables;
};
void BackupImpl::process_table_job(Table *table, bool no_lock,
bool delete_table, bool finalize, unsigned thread_num) {
int result = 0;
if (!m_process_table_jobs.get_result())
goto exit;
if (!table->copy(m_ds, m_con_pool[thread_num], no_lock, finalize, thread_num))
goto exit;
if (m_table_post_copy_hook)
m_table_post_copy_hook(table->get_db(), table->get_table(),
table->get_version());
result = 1;
exit:
if (delete_table)
delete table;
m_process_table_jobs.finish_task(result);
}
bool BackupImpl::scan(const std::unordered_set<table_key_t> &exclude_tables,
std::unordered_set<table_key_t> *out_processed_tables, bool no_lock,
bool collect_log_and_stats) {
msg("Start scanning common engine tables, need backup locks: %d, "
"collect log and stat tables: %d", no_lock, collect_log_and_stats);
std::unordered_map<table_key_t, std::unique_ptr<Table>> found_tables;
foreach_file_in_db_dirs(m_datadir_path,
[&](const char *file_path)->bool {
static const char *ext_list[] =
{".MYD", ".MYI", ".MRG", ".ARM", ".ARZ", ".CSM", ".CSV", NULL};
bool is_aria = ends_with(file_path, ".MAD") || ends_with(file_path, ".MAI");
if (!collect_log_and_stats && is_aria)
return true;
if (!is_aria && !filename_matches(file_path, ext_list))
return true;
if (check_if_skip_table(file_path)) {
msg("Skipping %s.", file_path);
return true;
}
auto db_table_fs = convert_filepath_to_tablename(file_path);
auto tk =
table_key(std::get<0>(db_table_fs), std::get<1>(db_table_fs));
// log and stats tables are only collected in this function,
// so there is no need to filter out them with exclude_tables.
if (collect_log_and_stats) {
if (is_log_table(std::get<0>(db_table_fs).c_str(),
std::get<1>(db_table_fs).c_str())) {
auto table_it = m_log_tables.find(tk);
if (table_it == m_log_tables.end()) {
msg("Log table found: %s", tk.c_str());
table_it = m_log_tables.emplace(tk,
std::unique_ptr<LogTable>(new LogTable(std::get<0>(db_table_fs),
std::get<1>(db_table_fs), std::get<2>(db_table_fs)))).first;
}
msg("Collect log table file: %s", file_path);
table_it->second->add_file_name(file_path);
return true;
}
// Aria can handle statistics tables
else if (is_stats_table(std::get<0>(db_table_fs).c_str(),
std::get<1>(db_table_fs).c_str()) && !is_aria) {
auto table_it = m_stats_tables.find(tk);
if (table_it == m_stats_tables.end()) {
msg("Stats table found: %s", tk.c_str());
table_it = m_stats_tables.emplace(tk,
std::unique_ptr<Table>(new Table(std::get<0>(db_table_fs),
std::get<1>(db_table_fs), std::get<2>(db_table_fs)))).first;
}
msg("Collect stats table file: %s", file_path);
table_it->second->add_file_name(file_path);
return true;
}
} else if (is_log_table(std::get<0>(db_table_fs).c_str(),
std::get<1>(db_table_fs).c_str()) ||
is_stats_table(std::get<0>(db_table_fs).c_str(),
std::get<1>(db_table_fs).c_str()))
return true;
if (is_aria)
return true;
if (exclude_tables.count(tk)) {
msg("Skip table %s at it is in exclude list", tk.c_str());
return true;
}
auto table_it = found_tables.find(tk);
if (table_it == found_tables.end()) {
table_it = found_tables.emplace(tk,
std::unique_ptr<Table>(new Table(std::get<0>(db_table_fs),
std::get<1>(db_table_fs), std::get<2>(db_table_fs)))).first;
}
table_it->second->add_file_name(file_path);
return true;
});
for (auto &table_it : found_tables) {
m_process_table_jobs.push_task(
std::bind(&BackupImpl::process_table_job, this, table_it.second.release(),
no_lock, true, false, std::placeholders::_1));
if (out_processed_tables)
out_processed_tables->insert(table_it.first);
}
msg("Stop scanning common engine tables");
return true;
}
bool BackupImpl::copy_log_tables(bool finalize) {
for (auto &table_it : m_log_tables) {
// Do not execute BACKUP LOCK for log tables as it's supposed
// that they must be copied on BLOCK_DDL and BLOCK_COMMIT locks.
m_process_table_jobs.push_task(
std::bind(&BackupImpl::process_table_job, this, table_it.second.get(),
true, false, finalize, std::placeholders::_1));
}
return true;
}
bool BackupImpl::copy_stats_tables() {
for (auto &table_it : m_stats_tables) {
// Do not execute BACKUP LOCK for stats tables as it's supposed
// that they must be copied on BLOCK_DDL and BLOCK_COMMIT locks.
// Delete stats table object after copy (see process_table_job())
m_process_table_jobs.push_task(
std::bind(&BackupImpl::process_table_job, this, table_it.second.release(),
true, true, false, std::placeholders::_1));
}
m_stats_tables.clear();
return true;
}
bool BackupImpl::wait_for_finish() {
/* Wait for threads to exit */
return m_process_table_jobs.wait_for_finish();
}
bool BackupImpl::close_log_tables() {
bool result = wait_for_finish();
for (auto &table_it : m_log_tables)
table_it.second->close();
return result;
}
Backup::Backup(const char *datadir_path, ds_ctxt_t *datasink,
std::vector<MYSQL *> &con_pool, ThreadPool &thread_pool) :
m_backup_impl(
new BackupImpl(datadir_path, datasink, con_pool,
thread_pool)) { }
Backup::~Backup() {
delete m_backup_impl;
}
bool Backup::scan(
const std::unordered_set<table_key_t> &exclude_tables,
std::unordered_set<table_key_t> *out_processed_tables,
bool no_lock, bool collect_log_and_stats) {
return m_backup_impl->scan(exclude_tables, out_processed_tables, no_lock,
collect_log_and_stats);
}
bool Backup::copy_log_tables(bool finalize) {
return m_backup_impl->copy_log_tables(finalize);
}
bool Backup::copy_stats_tables() {
return m_backup_impl->copy_stats_tables();
}
bool Backup::wait_for_finish() {
return m_backup_impl->wait_for_finish();
}
bool Backup::close_log_tables() {
return m_backup_impl->close_log_tables();
}
void Backup::set_post_copy_table_hook(const post_copy_table_hook_t &hook) {
m_backup_impl->set_post_copy_table_hook(hook);
}
} // namespace common_engine

View File

@ -0,0 +1,39 @@
#pragma once
#include "my_global.h"
#include "backup_mysql.h"
#include "datasink.h"
#include "thread_pool.h"
#include "xtrabackup.h"
#include <unordered_set>
#include <string>
#include <vector>
namespace common_engine {
class BackupImpl;
class Backup {
public:
Backup(const char *datadir_path, ds_ctxt_t *datasink,
std::vector<MYSQL *> &con_pool, ThreadPool &thread_pool);
~Backup();
Backup (Backup &&other) = delete;
Backup & operator= (Backup &&other) = delete;
Backup(const Backup &) = delete;
Backup & operator= (const Backup &) = delete;
bool scan(
const std::unordered_set<table_key_t> &exclude_tables,
std::unordered_set<table_key_t> *out_processed_tables,
bool no_lock, bool collect_log_and_stats);
bool copy_log_tables(bool finalize);
bool copy_stats_tables();
bool wait_for_finish();
bool close_log_tables();
void set_post_copy_table_hook(const post_copy_table_hook_t &hook);
private:
BackupImpl *m_backup_impl;
};
} // namespace common_engine

View File

@ -80,11 +80,11 @@ ds_create(const char *root, ds_type_t type)
/************************************************************************ /************************************************************************
Open a datasink file */ Open a datasink file */
ds_file_t * ds_file_t *
ds_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat) ds_open(ds_ctxt_t *ctxt, const char *path, const MY_STAT *stat, bool rewrite)
{ {
ds_file_t *file; ds_file_t *file;
file = ctxt->datasink->open(ctxt, path, stat); file = ctxt->datasink->open(ctxt, path, stat, rewrite);
if (file != NULL) { if (file != NULL) {
file->datasink = ctxt->datasink; file->datasink = ctxt->datasink;
} }
@ -104,6 +104,30 @@ ds_write(ds_file_t *file, const void *buf, size_t len)
return file->datasink->write(file, (const uchar *)buf, len); return file->datasink->write(file, (const uchar *)buf, len);
} }
int ds_seek_set(ds_file_t *file, my_off_t offset) {
DBUG_ASSERT(file);
DBUG_ASSERT(file->datasink);
if (file->datasink->seek_set)
return file->datasink->seek_set(file, offset);
return 0;
}
int ds_rename(ds_ctxt_t *ctxt, const char *old_path, const char *new_path) {
DBUG_ASSERT(ctxt);
DBUG_ASSERT(ctxt->datasink);
if (ctxt->datasink->rename)
return ctxt->datasink->rename(ctxt, old_path, new_path);
return 0;
}
int ds_remove(ds_ctxt_t *ctxt, const char *path) {
DBUG_ASSERT(ctxt);
DBUG_ASSERT(ctxt->datasink);
if (ctxt->datasink->remove)
return ctxt->datasink->mremove(ctxt, path);
return 0;
}
/************************************************************************ /************************************************************************
Close a datasink file. Close a datasink file.
@return 0 on success, 1, on error. */ @return 0 on success, 1, on error. */

View File

@ -43,7 +43,8 @@ typedef struct ds_ctxt {
*/ */
bool copy_file(const char *src_file_path, bool copy_file(const char *src_file_path,
const char *dst_file_path, const char *dst_file_path,
uint thread_n); uint thread_n,
bool rewrite = false);
bool move_file(const char *src_file_path, bool move_file(const char *src_file_path,
const char *dst_file_path, const char *dst_file_path,
@ -76,10 +77,15 @@ typedef struct {
struct datasink_struct { struct datasink_struct {
ds_ctxt_t *(*init)(const char *root); ds_ctxt_t *(*init)(const char *root);
ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path,
const MY_STAT *stat, bool rewrite);
int (*write)(ds_file_t *file, const unsigned char *buf, size_t len); int (*write)(ds_file_t *file, const unsigned char *buf, size_t len);
int (*seek_set)(ds_file_t *file, my_off_t offset);
int (*close)(ds_file_t *file); int (*close)(ds_file_t *file);
int (*remove)(const char *path); int (*remove)(const char *path);
// TODO: consider to return bool from "rename" and "remove"
int (*rename)(ds_ctxt_t *ctxt, const char *old_path, const char *new_path);
int (*mremove)(ds_ctxt_t *ctxt, const char *path);
void (*deinit)(ds_ctxt_t *ctxt); void (*deinit)(ds_ctxt_t *ctxt);
}; };
@ -106,12 +112,17 @@ ds_ctxt_t *ds_create(const char *root, ds_type_t type);
/************************************************************************ /************************************************************************
Open a datasink file */ Open a datasink file */
ds_file_t *ds_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); ds_file_t *ds_open(
ds_ctxt_t *ctxt, const char *path, const MY_STAT *stat, bool rewrite = false);
/************************************************************************ /************************************************************************
Write to a datasink file. Write to a datasink file.
@return 0 on success, 1 on error. */ @return 0 on success, 1 on error. */
int ds_write(ds_file_t *file, const void *buf, size_t len); int ds_write(ds_file_t *file, const void *buf, size_t len);
int ds_seek_set(ds_file_t *file, my_off_t offset);
int ds_rename(ds_ctxt_t *ctxt, const char *old_path, const char *new_path);
int ds_remove(ds_ctxt_t *ctxt, const char *path);
/************************************************************************ /************************************************************************
Close a datasink file. Close a datasink file.

View File

@ -0,0 +1,553 @@
#include "ddl_log.h"
#include "common.h"
#include "my_sys.h"
#include "sql_table.h"
#include "backup_copy.h"
#include "xtrabackup.h"
#include <unordered_set>
#include <functional>
#include <memory>
#include <cstddef>
namespace ddl_log {
struct Entry {
enum Type {
CREATE,
ALTER,
RENAME,
REPAIR,
OPTIMIZE,
DROP,
TRUNCATE,
CHANGE_INDEX,
BULK_INSERT
};
Type type;
std::string date;
std::string engine;
bool partitioned;
std::string db;
std::string table;
std::string id;
std::string new_engine;
bool new_partitioned;
std::string new_db;
std::string new_table;
std::string new_id;
};
typedef std::vector<std::unique_ptr<Entry>> entries_t;
typedef std::function<bool(std::unique_ptr<Entry>)> store_entry_func_t;
const char *aria_engine_name = "Aria";
static const char *frm_ext = ".frm";
static const char *database_keyword = "DATABASE";
const std::unordered_map<std::string, std::vector<const char *>> engine_exts =
{
{"Aria", {".MAD", ".MAI"}},
{"MyISAM", {".MYD", ".MYI"}},
{"MRG_MyISAM", {".MRG"}},
{"ARCHIVE", {".ARM", ".ARZ"}},
{"CSV", {".CSM", ".CSV"}}
};
static inline bool known_engine(const std::string &engine) {
return engine_exts.count(engine);
}
// TODO: add error messages
size_t parse(const uchar *buf, size_t buf_size, bool &error_flag,
store_entry_func_t &store_entry_func) {
DBUG_ASSERT(buf);
static constexpr char token_delimiter = '\t';
static constexpr char line_delimiter = '\n';
enum {
TOKEN_FIRST = 0,
TOKEN_DATE = TOKEN_FIRST,
TOKEN_TYPE,
TOKEN_ENGINE,
TOKEN_PARTITIONED,
TOKEN_DB,
TOKEN_TABLE,
TOKEN_ID,
TOKEN_MANDATORY = TOKEN_ID,
TOKEN_NEW_ENGINE,
TOKEN_NEW_PARTITIONED,
TOKEN_NEW_DB,
TOKEN_NEW_TABLE,
TOKEN_NEW_ID,
TOKEN_LAST = TOKEN_NEW_ID
};
const size_t string_offsets[TOKEN_LAST + 1] = {
offsetof(Entry, date),
offsetof(Entry, type), // not a string, be careful
offsetof(Entry, engine),
offsetof(Entry, partitioned), // not a string, be careful
offsetof(Entry, db),
offsetof(Entry, table),
offsetof(Entry, id),
offsetof(Entry, new_engine),
offsetof(Entry, new_partitioned), // not a string, be careful
offsetof(Entry, new_db),
offsetof(Entry, new_table),
offsetof(Entry, new_id)
};
const std::unordered_map<std::string, Entry::Type> str_to_type = {
{"CREATE", Entry::CREATE},
{"ALTER", Entry::ALTER},
{"RENAME", Entry::RENAME},
// TODO: fix to use uppercase-only
{"repair", Entry::REPAIR},
{"optimize", Entry::OPTIMIZE},
{"DROP", Entry::DROP},
{"TRUNCATE", Entry::TRUNCATE},
{"CHANGE_INDEX", Entry::CHANGE_INDEX},
{"BULK_INSERT", Entry::BULK_INSERT}
};
const uchar *new_line = buf;
const uchar *token_start = buf;
unsigned token_num = TOKEN_FIRST;
error_flag = false;
std::unique_ptr<Entry> entry(new Entry());
for (const uchar *ptr = buf; ptr < buf + buf_size; ++ptr) {
if (*ptr != token_delimiter && *ptr != line_delimiter)
continue;
if (token_start != ptr) {
std::string token(token_start, ptr);
if (token_num == TOKEN_TYPE) {
const auto type_it = str_to_type.find(token);
if (type_it == str_to_type.end()) {
error_flag = true;
goto exit;
}
entry->type = type_it->second;
}
else if (token_num == TOKEN_PARTITIONED) {
entry->partitioned = token[0] - '0';
}
else if (token_num == TOKEN_NEW_PARTITIONED) {
entry->new_partitioned = token[0] - '0';
}
else if (token_num <= TOKEN_LAST) {
DBUG_ASSERT(token_num != TOKEN_TYPE);
DBUG_ASSERT(token_num != TOKEN_PARTITIONED);
DBUG_ASSERT(token_num != TOKEN_NEW_PARTITIONED);
reinterpret_cast<std::string *>
(reinterpret_cast<uchar *>(entry.get()) + string_offsets[token_num])->
assign(std::move(token));
}
else {
error_flag = true;
goto exit;
}
}
token_start = ptr + 1;
if (*ptr == line_delimiter) {
if (token_num < TOKEN_MANDATORY) {
error_flag = true;
goto exit;
}
if (!store_entry_func(std::move(entry))) {
error_flag = true;
goto exit;
}
entry.reset(new Entry());
token_num = TOKEN_FIRST;
new_line = ptr + 1;
} else
++token_num;
}
exit:
return new_line - buf;
}
bool parse(const char *file_path, store_entry_func_t store_entry_func) {
DBUG_ASSERT(file_path);
DBUG_ASSERT(store_entry_func);
File file= -1;
bool result = true;
uchar buf[1024];
size_t bytes_read = 0;
size_t buf_read_offset = 0;
if ((file= my_open(file_path, O_RDONLY | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_WME))) < 0) {
msg("DDL log file %s open failed: %d", file_path, my_errno);
result = false;
goto exit;
}
while((bytes_read = my_read(
file, &buf[buf_read_offset], sizeof(buf) - buf_read_offset, MY_WME)) > 0) {
if (bytes_read == size_t(-1)) {
msg("DDL log file %s read error: %d", file_path, my_errno);
result = false;
break;
}
bytes_read += buf_read_offset;
bool parse_error_flag = false;
size_t bytes_parsed = parse(
buf, bytes_read, parse_error_flag, store_entry_func);
if (parse_error_flag) {
result = false;
break;
}
size_t rest_size = bytes_read - bytes_parsed;
if (rest_size)
memcpy(buf, buf + bytes_parsed, rest_size);
buf_read_offset = rest_size;
}
exit:
if (file >= 0)
my_close(file, MYF(MY_WME));
return result;
};
static
bool process_database(
const char *datadir_path,
ds_ctxt_t *ds,
const Entry &entry,
std::unordered_set<std::string> &dropped_databases) {
if (entry.type == Entry::Type::CREATE ||
entry.type == Entry::Type::ALTER) {
std::string opt_file(datadir_path);
opt_file.append("/").append(entry.db).append("/db.opt");
if (!ds->copy_file(opt_file.c_str(), opt_file.c_str(), 0, true)) {
msg("Failed to re-copy %s.", opt_file.c_str());
return false;
}
if (entry.type == Entry::Type::CREATE)
dropped_databases.erase(entry.db);
return true;
}
DBUG_ASSERT(entry.type == Entry::Type::DROP);
std::string db_path(datadir_path);
db_path.append("/").append(entry.db);
const char *dst_path = convert_dst(db_path.c_str());
if (!ds_remove(ds, dst_path)) {
dropped_databases.insert(entry.db);
return true;
}
return false;
}
static
std::unique_ptr<std::vector<std::string>>
find_table_files(
const char *dir_path,
const std::string &db,
const std::string &table) {
std::unique_ptr<std::vector<std::string>>
result(new std::vector<std::string>());
std::string prefix = convert_tablename_to_filepath(dir_path, db, table);
foreach_file_in_db_dirs(dir_path, [&](const char *file_name)->bool {
if (!strncmp(file_name, prefix.c_str(), prefix.size())) {
DBUG_ASSERT(strlen(file_name) >= prefix.size());
if (file_name[prefix.size()] == '.' ||
!strncmp(file_name + prefix.size(), "#P#", strlen("#P#")))
result->push_back(std::string(file_name));
}
return true;
});
return result;
}
static
bool process_remove(
const char *datadir_path,
ds_ctxt_t *ds,
const Entry &entry,
bool remove_frm) {
if (check_if_skip_table(
std::string(entry.db).append("/").append(entry.table).c_str()))
return true;
auto ext_it = engine_exts.find(entry.engine);
if (ext_it == engine_exts.end())
return true;
std::string file_preffix = convert_tablename_to_filepath(datadir_path,
entry.db, entry.table);
const char *dst_preffix = convert_dst(file_preffix.c_str());
for (const char *ext : ext_it->second) {
std::string old_name(dst_preffix);
if (!entry.partitioned)
old_name.append(ext);
else
old_name.append("#P#*");
if (ds_remove(ds, old_name.c_str())) {
msg("Failed to remove %s.", old_name.c_str());
return false;
}
}
if (remove_frm) {
std::string old_frm_name(dst_preffix);
old_frm_name.append(frm_ext);
if (ds_remove(ds, old_frm_name.c_str())) {
msg("Failed to remove %s.", old_frm_name.c_str());
return false;
}
}
return true;
}
static
bool process_recopy(
const char *datadir_path,
ds_ctxt_t *ds,
const Entry &entry,
const tables_t &tables) {
if (check_if_skip_table(
std::string(entry.db).append("/").append(entry.table).c_str()))
return true;
const std::string &new_table_id =
entry.new_id.empty() ? entry.id : entry.new_id;
DBUG_ASSERT(!new_table_id.empty());
const std::string &new_table =
entry.new_table.empty() ? entry.table : entry.new_table;
DBUG_ASSERT(!new_table.empty());
const std::string &new_db =
entry.new_db.empty() ? entry.db : entry.new_db;
DBUG_ASSERT(!new_db.empty());
const std::string &new_engine =
entry.new_engine.empty() ? entry.engine : entry.new_engine;
DBUG_ASSERT(!new_engine.empty());
if (entry.type != Entry::Type::BULK_INSERT) {
auto table_it = tables.find(table_key(new_db, new_table));
if (table_it != tables.end() &&
table_it->second == new_table_id)
return true;
}
if (!entry.new_engine.empty() &&
entry.engine != entry.new_engine &&
!known_engine(entry.new_engine)) {
return process_remove(datadir_path, ds, entry, false);
}
if ((entry.partitioned || entry.new_partitioned) &&
!process_remove(datadir_path, ds, entry, false))
return false;
if (entry.partitioned || entry.new_partitioned) {
auto files = find_table_files(datadir_path, new_db, new_table);
if (!files.get())
return true;
for (const auto &file : *files) {
const char *dst_path = convert_dst(file.c_str());
if (!ds->copy_file(file.c_str(), dst_path, 0, true)) {
msg("Failed to re-copy %s.", file.c_str());
return false;
}
}
return true;
}
auto ext_it = engine_exts.find(new_engine);
if (ext_it == engine_exts.end())
return false;
for (const char *ext : ext_it->second) {
std::string file_name =
convert_tablename_to_filepath(datadir_path, new_db, new_table).
append(ext);
const char *dst_path = convert_dst(file_name.c_str());
if (file_exists(file_name.c_str()) &&
!ds->copy_file(file_name.c_str(), dst_path, 0, true)) {
msg("Failed to re-copy %s.", file_name.c_str());
return false;
}
}
std::string frm_file =
convert_tablename_to_filepath(datadir_path, new_db, new_table).
append(frm_ext);
const char *frm_dst_path = convert_dst(frm_file.c_str());
if (file_exists(frm_file.c_str()) &&
!ds->copy_file(frm_file.c_str(), frm_dst_path, 0, true)) {
msg("Failed to re-copy %s.", frm_file.c_str());
return false;
}
return true;
}
static
bool process_rename(
const char *datadir_path,
ds_ctxt_t *ds,
const Entry &entry) {
if (check_if_skip_table(
std::string(entry.db).append("/").append(entry.table).c_str()))
return true;
DBUG_ASSERT(entry.db != "partition");
auto ext_it = engine_exts.find(entry.engine);
if (ext_it == engine_exts.end())
return false;
std::string new_preffix = convert_tablename_to_filepath(datadir_path,
entry.new_db, entry.new_table);
const char *dst_path = convert_dst(new_preffix.c_str());
std::string old_preffix = convert_tablename_to_filepath(datadir_path,
entry.db, entry.table);
const char *src_path = convert_dst(old_preffix.c_str());
for (const char *ext : ext_it->second) {
std::string old_name(src_path);
old_name.append(ext);
std::string new_name(dst_path);
new_name.append(ext);
if (ds_rename(ds, old_name.c_str(), new_name.c_str())) {
msg("Failed to rename %s to %s.",
old_name.c_str(), new_name.c_str());
return false;
}
}
std::string new_frm_file = new_preffix + frm_ext;
const char *new_frm_dst = convert_dst(new_frm_file.c_str());
if (file_exists(new_frm_file.c_str()) &&
!ds->copy_file(new_frm_file.c_str(), new_frm_dst, 0, true)) {
msg("Failed to re-copy %s.", new_frm_file.c_str());
return false;
}
// TODO: return this code if .frm is copied not under BLOCK_DDL
/*
std::string old_frm_name(src_path);
old_frm_name.append(frm_ext);
std::string new_frm_name(dst_path);
new_frm_name.append(frm_ext);
if (ds_rename(ds, old_frm_name.c_str(), new_frm_name.c_str())) {
msg("Failed to rename %s to %s.",
old_frm_name.c_str(), new_frm_name.c_str());
return false;
}
*/
return true;
}
bool backup(
const char *datadir_path,
ds_ctxt_t *ds,
const tables_t &tables) {
DBUG_ASSERT(datadir_path);
DBUG_ASSERT(ds);
char ddl_log_path[FN_REFLEN];
fn_format(ddl_log_path, "ddl", datadir_path, ".log", 0);
std::vector<std::unique_ptr<Entry>> entries;
std::unordered_set<std::string> processed_tables;
std::unordered_set<std::string> dropped_databases;
bool parsing_result =
parse(ddl_log_path, [&](std::unique_ptr<Entry> entry)->bool {
if (entry->engine == database_keyword)
return process_database(datadir_path, ds, *entry, dropped_databases);
if (!known_engine(entry->engine) && !known_engine(entry->new_engine))
return true;
if (entry->type == Entry::Type::CREATE ||
(entry->type == Entry::Type::ALTER &&
!entry->new_engine.empty() &&
entry->engine != entry->new_engine)) {
if (!process_recopy(datadir_path, ds, *entry, tables))
return false;
processed_tables.insert(table_key(entry->db, entry->table));
if (entry->type == Entry::Type::ALTER)
processed_tables.insert(table_key(entry->new_db, entry->new_table));
return true;
}
if (entry->type == Entry::Type::DROP) {
if (!process_remove(datadir_path, ds, *entry, true))
return false;
processed_tables.insert(table_key(entry->db, entry->table));
return true;
}
if (entry->type == Entry::Type::RENAME) {
if (entry->partitioned) {
if (!process_remove(datadir_path, ds, *entry, true))
return false;
Entry recopy_entry {
entry->type,
{},
entry->new_engine.empty() ? entry->engine : entry->new_engine,
true,
entry->new_db,
entry->new_table,
entry->new_id,
{}, true, {}, {}, {}
};
if (!process_recopy(datadir_path, ds, recopy_entry, tables))
return false;
}
else if (!process_rename(datadir_path, ds, *entry))
return false;
processed_tables.insert(table_key(entry->db, entry->table));
processed_tables.insert(table_key(entry->new_db, entry->new_table));
return true;
}
entries.push_back(std::move(entry));
return true;
});
if (!parsing_result)
return false;
while (!entries.empty()) {
auto entry = std::move(entries.back());
entries.pop_back();
auto tk = table_key(
entry->new_db.empty() ? entry->db : entry->new_db,
entry->new_table.empty() ? entry->table : entry->new_table);
if (dropped_databases.count(entry->db) ||
dropped_databases.count(entry->new_db))
continue;
if (processed_tables.count(tk))
continue;
processed_tables.insert(std::move(tk));
if (!process_recopy(datadir_path, ds, *entry, tables))
return false;
}
return true;
}
} // namespace ddl_log

View File

@ -0,0 +1,15 @@
#pragma once
#include "my_global.h"
#include "datasink.h"
#include "aria_backup_client.h"
#include <string>
#include <memory>
#include <vector>
#include <unordered_map>
namespace ddl_log {
typedef std::unordered_map<std::string, std::string> tables_t;
bool backup(const char *datadir_path, ds_ctxt_t *ds, const tables_t &tables);
} // namespace ddl_log

View File

@ -44,7 +44,7 @@ typedef struct {
static ds_ctxt_t *buffer_init(const char *root); static ds_ctxt_t *buffer_init(const char *root);
static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int buffer_write(ds_file_t *file, const uchar *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 int buffer_close(ds_file_t *file);
static void buffer_deinit(ds_ctxt_t *ctxt); static void buffer_deinit(ds_ctxt_t *ctxt);
@ -53,8 +53,11 @@ datasink_t datasink_buffer = {
&buffer_init, &buffer_init,
&buffer_open, &buffer_open,
&buffer_write, &buffer_write,
nullptr,
&buffer_close, &buffer_close,
&dummy_remove, &dummy_remove,
nullptr,
nullptr,
&buffer_deinit &buffer_deinit
}; };
@ -84,8 +87,10 @@ buffer_init(const char *root)
} }
static ds_file_t * static ds_file_t *
buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) buffer_open(ds_ctxt_t *ctxt, const char *path,
const MY_STAT *mystat, bool rewrite)
{ {
DBUG_ASSERT(rewrite == false);
ds_buffer_ctxt_t *buffer_ctxt; ds_buffer_ctxt_t *buffer_ctxt;
ds_ctxt_t *pipe_ctxt; ds_ctxt_t *pipe_ctxt;
ds_file_t *dst_file; ds_file_t *dst_file;

View File

@ -65,7 +65,7 @@ extern ulonglong xtrabackup_compress_chunk_size;
static ds_ctxt_t *compress_init(const char *root); static ds_ctxt_t *compress_init(const char *root);
static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int compress_write(ds_file_t *file, const uchar *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 int compress_close(ds_file_t *file);
static void compress_deinit(ds_ctxt_t *ctxt); static void compress_deinit(ds_ctxt_t *ctxt);
@ -74,8 +74,11 @@ datasink_t datasink_compress = {
&compress_init, &compress_init,
&compress_open, &compress_open,
&compress_write, &compress_write,
nullptr,
&compress_close, &compress_close,
&dummy_remove, &dummy_remove,
nullptr,
nullptr,
&compress_deinit &compress_deinit
}; };
@ -116,8 +119,10 @@ compress_init(const char *root)
static static
ds_file_t * ds_file_t *
compress_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) compress_open(ds_ctxt_t *ctxt, const char *path,
const MY_STAT *mystat, bool rewrite)
{ {
DBUG_ASSERT(rewrite == false);
ds_compress_ctxt_t *comp_ctxt; ds_compress_ctxt_t *comp_ctxt;
ds_ctxt_t *dest_ctxt; ds_ctxt_t *dest_ctxt;
ds_file_t *dest_file; ds_file_t *dest_file;

View File

@ -42,8 +42,9 @@ typedef struct {
static ds_ctxt_t *local_init(const char *root); static ds_ctxt_t *local_init(const char *root);
static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int local_write(ds_file_t *file, const uchar *buf, size_t len); static int local_write(ds_file_t *file, const uchar *buf, size_t len);
static int local_seek_set(ds_file_t *file, my_off_t offset);
static int local_close(ds_file_t *file); static int local_close(ds_file_t *file);
static void local_deinit(ds_ctxt_t *ctxt); static void local_deinit(ds_ctxt_t *ctxt);
@ -52,13 +53,20 @@ static int local_remove(const char *path)
return unlink(path); return unlink(path);
} }
static int local_rename(
ds_ctxt_t *ctxt, const char *old_path, const char *new_path);
static int local_mremove(ds_ctxt_t *ctxt, const char *path);
extern "C" { extern "C" {
datasink_t datasink_local = { datasink_t datasink_local = {
&local_init, &local_init,
&local_open, &local_open,
&local_write, &local_write,
&local_seek_set,
&local_close, &local_close,
&local_remove, &local_remove,
&local_rename,
&local_mremove,
&local_deinit &local_deinit
}; };
} }
@ -89,7 +97,7 @@ local_init(const char *root)
static static
ds_file_t * ds_file_t *
local_open(ds_ctxt_t *ctxt, const char *path, local_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat __attribute__((unused))) const MY_STAT *mystat __attribute__((unused)), bool rewrite)
{ {
char fullpath[FN_REFLEN]; char fullpath[FN_REFLEN];
char dirpath[FN_REFLEN]; char dirpath[FN_REFLEN];
@ -111,7 +119,9 @@ local_open(ds_ctxt_t *ctxt, const char *path,
return NULL; return NULL;
} }
fd = my_create(fullpath, 0, O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, // TODO: check in Windows and set the corresponding flags on fail
fd = my_create(fullpath, 0,
O_WRONLY | O_BINARY | (rewrite ? O_TRUNC : O_EXCL) | O_NOFOLLOW,
MYF(MY_WME)); MYF(MY_WME));
if (fd < 0) { if (fd < 0) {
return NULL; return NULL;
@ -194,8 +204,8 @@ static void init_ibd_data(ds_local_file_t *local_file, const uchar *buf, size_t
return; return;
} }
auto flags = mach_read_from_4(&buf[FIL_PAGE_DATA + FSP_SPACE_FLAGS]); uint32_t flags = mach_read_from_4(&buf[FIL_PAGE_DATA + FSP_SPACE_FLAGS]);
auto ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); uint32_t ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags);
local_file->pagesize= ssize == 0 ? UNIV_PAGE_SIZE_ORIG : ((UNIV_ZIP_SIZE_MIN >> 1) << ssize); local_file->pagesize= ssize == 0 ? UNIV_PAGE_SIZE_ORIG : ((UNIV_ZIP_SIZE_MIN >> 1) << ssize);
local_file->compressed = fil_space_t::full_crc32(flags) local_file->compressed = fil_space_t::full_crc32(flags)
? fil_space_t::is_compressed(flags) ? fil_space_t::is_compressed(flags)
@ -239,6 +249,15 @@ local_write(ds_file_t *file, const uchar *buf, size_t len)
return 1; return 1;
} }
static
int
local_seek_set(ds_file_t *file, my_off_t offset) {
ds_local_file_t *local_file= (ds_local_file_t *)file->ptr;
if (my_seek(local_file->fd, offset, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
return 1;
return 0;
}
/* Set EOF at file's current position.*/ /* Set EOF at file's current position.*/
static int set_eof(File fd) static int set_eof(File fd)
{ {
@ -276,3 +295,77 @@ local_deinit(ds_ctxt_t *ctxt)
my_free(ctxt->root); my_free(ctxt->root);
my_free(ctxt); my_free(ctxt);
} }
static int local_rename(
ds_ctxt_t *ctxt, const char *old_path, const char *new_path) {
char full_old_path[FN_REFLEN];
char full_new_path[FN_REFLEN];
fn_format(full_old_path, old_path, ctxt->root, "", MYF(MY_RELATIVE_PATH));
fn_format(full_new_path, new_path, ctxt->root, "", MYF(MY_RELATIVE_PATH));
// Ignore errors as .frm files can me copied separately.
// TODO: return error processing here after the corresponding changes in
// xtrabackup.cc
(void)my_rename(full_old_path, full_new_path, MYF(0));
// if (my_rename(full_old_path, full_new_path, MYF(0))) {
// msg("Failed to rename file %s to %s", old_path, new_path);
// return 1;
// }
return 0;
}
// It's ok if destination does not contain the file or folder
static int local_mremove(ds_ctxt_t *ctxt, const char *path) {
char full_path[FN_REFLEN];
fn_format(full_path, path, ctxt->root, "", MYF(MY_RELATIVE_PATH));
size_t full_path_len = strlen(full_path);
if (full_path[full_path_len - 1] == '*') {
full_path[full_path_len - 1] = '\0';
char *preffix = strrchr(full_path, '/');
const char *full_path_dir = full_path;
size_t preffix_len;
if (preffix) {
preffix_len = (full_path_len - 1) - (preffix - full_path);
*(preffix++) = '\0';
}
else {
preffix = full_path;
preffix_len = full_path_len - 1;
full_path_dir= IF_WIN(".\\", "./");
}
if (!preffix_len)
return 0;
MY_DIR *dir= my_dir(full_path_dir, 0);
if (!dir)
return 0;
for (size_t i = 0; i < dir->number_of_files; ++i) {
char full_fpath[FN_REFLEN];
if (strncmp(dir->dir_entry[i].name, preffix, preffix_len))
continue;
fn_format(full_fpath, dir->dir_entry[i].name,
full_path_dir, "", MYF(MY_RELATIVE_PATH));
(void)my_delete(full_fpath, MYF(0));
}
my_dirend(dir);
}
else {
MY_STAT stat;
if (!my_stat(full_path, &stat, MYF(0)))
return 0;
MY_DIR *dir= my_dir(full_path, 0);
if (!dir) {
// TODO: check for error here if necessary
(void)my_delete(full_path, MYF(0));
return 0;
}
for (size_t i = 0; i < dir->number_of_files; ++i) {
char full_fpath[FN_REFLEN];
fn_format(full_fpath, dir->dir_entry[i].name,
full_path, "", MYF(MY_RELATIVE_PATH));
(void)my_delete(full_fpath, MYF(0));
}
my_dirend(dir);
(void)my_rmtree(full_path, MYF(0));
}
return 0;
}

View File

@ -30,7 +30,7 @@ typedef struct {
static ds_ctxt_t *stdout_init(const char *root); static ds_ctxt_t *stdout_init(const char *root);
static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int stdout_write(ds_file_t *file, const uchar *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 int stdout_close(ds_file_t *file);
static void stdout_deinit(ds_ctxt_t *ctxt); static void stdout_deinit(ds_ctxt_t *ctxt);
@ -39,8 +39,11 @@ datasink_t datasink_stdout = {
&stdout_init, &stdout_init,
&stdout_open, &stdout_open,
&stdout_write, &stdout_write,
nullptr,
&stdout_close, &stdout_close,
&dummy_remove, &dummy_remove,
nullptr,
nullptr,
&stdout_deinit &stdout_deinit
}; };
@ -61,8 +64,9 @@ static
ds_file_t * ds_file_t *
stdout_open(ds_ctxt_t *ctxt __attribute__((unused)), stdout_open(ds_ctxt_t *ctxt __attribute__((unused)),
const char *path __attribute__((unused)), const char *path __attribute__((unused)),
MY_STAT *mystat __attribute__((unused))) const MY_STAT *mystat __attribute__((unused)), bool rewrite)
{ {
DBUG_ASSERT(rewrite == false);
ds_stdout_file_t *stdout_file; ds_stdout_file_t *stdout_file;
ds_file_t *file; ds_file_t *file;
size_t pathlen; size_t pathlen;

View File

@ -41,7 +41,7 @@ typedef struct {
static ds_ctxt_t *tmpfile_init(const char *root); static ds_ctxt_t *tmpfile_init(const char *root);
static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int tmpfile_write(ds_file_t *file, const uchar *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 int tmpfile_close(ds_file_t *file);
static void tmpfile_deinit(ds_ctxt_t *ctxt); static void tmpfile_deinit(ds_ctxt_t *ctxt);
@ -50,8 +50,11 @@ datasink_t datasink_tmpfile = {
&tmpfile_init, &tmpfile_init,
&tmpfile_open, &tmpfile_open,
&tmpfile_write, &tmpfile_write,
nullptr,
&tmpfile_close, &tmpfile_close,
&dummy_remove, &dummy_remove,
nullptr,
nullptr,
&tmpfile_deinit &tmpfile_deinit
}; };
@ -80,8 +83,9 @@ tmpfile_init(const char *root)
static ds_file_t * static ds_file_t *
tmpfile_open(ds_ctxt_t *ctxt, const char *path, tmpfile_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat) const MY_STAT *mystat, bool rewrite)
{ {
DBUG_ASSERT(rewrite == false);
ds_tmpfile_ctxt_t *tmpfile_ctxt; ds_tmpfile_ctxt_t *tmpfile_ctxt;
char tmp_path[FN_REFLEN]; char tmp_path[FN_REFLEN];
ds_tmp_file_t *tmp_file; ds_tmp_file_t *tmp_file;

View File

@ -40,24 +40,31 @@ General streaming interface */
static ds_ctxt_t *xbstream_init(const char *root); static ds_ctxt_t *xbstream_init(const char *root);
static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); const MY_STAT *mystat, bool rewrite);
static int xbstream_write(ds_file_t *file, const uchar *buf, size_t len); static int xbstream_write(ds_file_t *file, const uchar *buf, size_t len);
static int xbstream_seek_set(ds_file_t *file, my_off_t offset);
static int xbstream_close(ds_file_t *file); static int xbstream_close(ds_file_t *file);
static void xbstream_deinit(ds_ctxt_t *ctxt); static void xbstream_deinit(ds_ctxt_t *ctxt);
static int xbstream_rename(
ds_ctxt_t *ctxt, const char *old_path, const char *new_path);
static int xbstream_mremove(ds_ctxt_t *ctxt, const char *path);
datasink_t datasink_xbstream = { datasink_t datasink_xbstream = {
&xbstream_init, &xbstream_init,
&xbstream_open, &xbstream_open,
&xbstream_write, &xbstream_write,
&xbstream_seek_set,
&xbstream_close, &xbstream_close,
&dummy_remove, &dummy_remove,
&xbstream_rename,
&xbstream_mremove,
&xbstream_deinit &xbstream_deinit
}; };
static static
ssize_t ssize_t
my_xbstream_write_callback(xb_wstream_file_t *f __attribute__((unused)), my_xbstream_write_callback(void *userdata, const void *buf, size_t len)
void *userdata, const void *buf, size_t len)
{ {
ds_stream_ctxt_t *stream_ctxt; ds_stream_ctxt_t *stream_ctxt;
@ -89,7 +96,7 @@ xbstream_init(const char *root __attribute__((unused)))
goto err; goto err;
} }
xbstream = xb_stream_write_new(); xbstream = xb_stream_write_new(my_xbstream_write_callback, stream_ctxt);
if (xbstream == NULL) { if (xbstream == NULL) {
msg("xb_stream_write_new() failed."); msg("xb_stream_write_new() failed.");
goto err; goto err;
@ -108,7 +115,8 @@ err:
static static
ds_file_t * ds_file_t *
xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) xbstream_open(ds_ctxt_t *ctxt, const char *path,
const MY_STAT *mystat, bool rewrite)
{ {
ds_file_t *file; ds_file_t *file;
ds_stream_file_t *stream_file; ds_stream_file_t *stream_file;
@ -144,9 +152,7 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
xbstream = stream_ctxt->xbstream; xbstream = stream_ctxt->xbstream;
xbstream_file = xb_stream_write_open(xbstream, path, mystat, xbstream_file = xb_stream_write_open(xbstream, path, mystat, rewrite);
stream_ctxt,
my_xbstream_write_callback);
if (xbstream_file == NULL) { if (xbstream_file == NULL) {
msg("xb_stream_write_open() failed."); msg("xb_stream_write_open() failed.");
@ -190,6 +196,45 @@ xbstream_write(ds_file_t *file, const uchar *buf, size_t len)
return 0; return 0;
} }
static
int
xbstream_seek_set(ds_file_t *file, my_off_t offset)
{
ds_stream_file_t *stream_file;
xb_wstream_file_t *xbstream_file;
stream_file = (ds_stream_file_t *) file->ptr;
xbstream_file = stream_file->xbstream_file;
if (xb_stream_write_seek_set(xbstream_file, offset)) {
msg("xb_stream_write_seek_set() failed.");
return 1;
}
return 0;
}
static
int
xbstream_mremove(ds_ctxt_t *ctxt, const char *path) {
ds_stream_ctxt_t *stream_ctxt =
reinterpret_cast<ds_stream_ctxt_t *>(ctxt->ptr);
xb_wstream_t *xbstream = stream_ctxt->xbstream;
return xb_stream_write_remove(xbstream, path);
}
static
int
xbstream_rename(
ds_ctxt_t *ctxt, const char *old_path, const char *new_path) {
ds_stream_ctxt_t *stream_ctxt =
reinterpret_cast<ds_stream_ctxt_t *>(ctxt->ptr);
xb_wstream_t *xbstream = stream_ctxt->xbstream;
return xb_stream_write_rename(xbstream, old_path, new_path);
}
static static
int int
xbstream_close(ds_file_t *file) xbstream_close(ds_file_t *file)

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2017, 2022, MariaDB Corporation. /* Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -17,18 +17,18 @@
#include <mysqld.h> #include <mysqld.h>
#include <mysql.h> #include <mysql.h>
#include <xtrabackup.h> #include <xtrabackup.h>
#include <xb_plugin.h> #include <encryption_plugin.h>
#include <sql_plugin.h> #include <sql_plugin.h>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <common.h> #include <common.h>
#include <backup_mysql.h> #include <backup_mysql.h>
#include <srv0srv.h> #include <log0crypt.h>
extern struct st_maria_plugin *mysql_optional_plugins[]; extern struct st_maria_plugin *mysql_optional_plugins[];
extern struct st_maria_plugin *mysql_mandatory_plugins[]; extern struct st_maria_plugin *mysql_mandatory_plugins[];
static void xb_plugin_init(int argc, char **argv); static void encryption_plugin_init(int argc, char **argv);
extern char *xb_plugin_load; extern char *xb_plugin_load;
extern char *xb_plugin_dir; extern char *xb_plugin_dir;
@ -42,7 +42,7 @@ const char *QUERY_PLUGIN =
" OR (plugin_type = 'DAEMON' AND plugin_name LIKE 'provider\\_%')" " OR (plugin_type = 'DAEMON' AND plugin_name LIKE 'provider\\_%')"
" AND plugin_status='ACTIVE'"; " AND plugin_status='ACTIVE'";
std::string xb_plugin_config; std::string encryption_plugin_config;
static void add_to_plugin_load_list(const char *plugin_def) static void add_to_plugin_load_list(const char *plugin_def)
{ {
@ -52,16 +52,16 @@ static void add_to_plugin_load_list(const char *plugin_def)
static char XTRABACKUP_EXE[] = "xtrabackup"; static char XTRABACKUP_EXE[] = "xtrabackup";
/* /*
Read "plugin-load" value from backup-my.cnf during prepare phase. Read "plugin-load" value (encryption plugin) from backup-my.cnf during
prepare phase.
The value is stored during backup phase. The value is stored during backup phase.
*/ */
static std::string get_plugin_from_cnf(const char *dir) static std::string get_encryption_plugin_from_cnf()
{ {
std::string path = dir + std::string("/backup-my.cnf"); FILE *f = fopen("backup-my.cnf", "r");
FILE *f = fopen(path.c_str(), "r");
if (!f) if (!f)
{ {
die("Can't open %s for reading", path.c_str()); die("Can't open backup-my.cnf for reading");
} }
char line[512]; char line[512];
std::string plugin_load; std::string plugin_load;
@ -80,7 +80,7 @@ static std::string get_plugin_from_cnf(const char *dir)
} }
void xb_plugin_backup_init(MYSQL *mysql) void encryption_plugin_backup_init(MYSQL *mysql)
{ {
MYSQL_RES *result; MYSQL_RES *result;
MYSQL_ROW row; MYSQL_ROW row;
@ -163,7 +163,7 @@ void xb_plugin_backup_init(MYSQL *mysql)
mysql_free_result(result); mysql_free_result(result);
} }
xb_plugin_config = oss.str(); encryption_plugin_config = oss.str();
argc = 0; argc = 0;
argv[argc++] = XTRABACKUP_EXE; argv[argc++] = XTRABACKUP_EXE;
@ -175,23 +175,23 @@ void xb_plugin_backup_init(MYSQL *mysql)
} }
argv[argc] = 0; argv[argc] = 0;
xb_plugin_init(argc, argv); encryption_plugin_init(argc, argv);
} }
const char *xb_plugin_get_config() const char *encryption_plugin_get_config()
{ {
return xb_plugin_config.c_str(); return encryption_plugin_config.c_str();
} }
extern int finalize_encryption_plugin(st_plugin_int *plugin); extern int finalize_encryption_plugin(st_plugin_int *plugin);
void xb_plugin_prepare_init(int argc, char **argv, const char *dir) void encryption_plugin_prepare_init(int argc, char **argv)
{ {
std::string plugin_load= get_plugin_from_cnf(dir ? dir : "."); std::string plugin_load= get_encryption_plugin_from_cnf();
if (plugin_load.size()) if (plugin_load.size())
{ {
msg("Loading plugins from %s", plugin_load.c_str()); msg("Loading encryption plugin from %s", plugin_load.c_str());
} }
else else
{ {
@ -211,19 +211,19 @@ void xb_plugin_prepare_init(int argc, char **argv, const char *dir)
new_argv[0] = XTRABACKUP_EXE; new_argv[0] = XTRABACKUP_EXE;
memcpy(&new_argv[1], argv, argc*sizeof(char *)); memcpy(&new_argv[1], argv, argc*sizeof(char *));
xb_plugin_init(argc+1, new_argv); encryption_plugin_init(argc+1, new_argv);
delete[] new_argv; delete[] new_argv;
} }
static void xb_plugin_init(int argc, char **argv) static void encryption_plugin_init(int argc, char **argv)
{ {
/* Patch optional and mandatory plugins, we only need to load the one in xb_plugin_load. */ /* Patch optional and mandatory plugins, we only need to load the one in xb_plugin_load. */
mysql_optional_plugins[0] = mysql_mandatory_plugins[0] = 0; mysql_optional_plugins[0] = mysql_mandatory_plugins[0] = 0;
plugin_maturity = MariaDB_PLUGIN_MATURITY_UNKNOWN; /* mariabackup accepts all plugins */ plugin_maturity = MariaDB_PLUGIN_MATURITY_UNKNOWN; /* mariabackup accepts all plugins */
msg("Loading plugins"); msg("Loading encryption plugin");
for (int i= 1; i < argc; i++) for (int i= 1; i < argc; i++)
msg("\t Plugin parameter : '%s'", argv[i]); msg("\t Encryption plugin parameter : '%s'", argv[i]);
plugin_init(&argc, argv, PLUGIN_INIT_SKIP_PLUGIN_TABLE); plugin_init(&argc, argv, PLUGIN_INIT_SKIP_PLUGIN_TABLE);
} }

View File

@ -0,0 +1,7 @@
#include <mysql.h>
#include <string>
extern void encryption_plugin_backup_init(MYSQL *mysql);
extern const char* encryption_plugin_get_config();
extern void encryption_plugin_prepare_init(int argc, char **argv);
//extern void encryption_plugin_init(int argc, char **argv);

View File

@ -78,10 +78,8 @@ my_bool opt_ibx_galera_info = FALSE;
my_bool opt_ibx_slave_info = FALSE; my_bool opt_ibx_slave_info = FALSE;
my_bool opt_ibx_no_lock = FALSE; my_bool opt_ibx_no_lock = FALSE;
my_bool opt_ibx_safe_slave_backup = FALSE; my_bool opt_ibx_safe_slave_backup = FALSE;
my_bool opt_ibx_rsync = FALSE;
my_bool opt_ibx_force_non_empty_dirs = FALSE; my_bool opt_ibx_force_non_empty_dirs = FALSE;
my_bool opt_ibx_noversioncheck = FALSE; my_bool opt_ibx_noversioncheck = FALSE;
my_bool opt_ibx_no_backup_locks = FALSE;
my_bool opt_ibx_decompress = FALSE; my_bool opt_ibx_decompress = FALSE;
char *opt_ibx_incremental_history_name = NULL; char *opt_ibx_incremental_history_name = NULL;
@ -268,8 +266,10 @@ static struct my_option ibx_long_options[] =
(uchar *) &opt_ibx_incremental, (uchar *) &opt_ibx_incremental, 0, (uchar *) &opt_ibx_incremental, (uchar *) &opt_ibx_incremental, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"no-lock", OPT_NO_LOCK, "Use this option to disable table lock " {"no-lock", OPT_NO_LOCK, "This option should not be used as "
"with \"FLUSH TABLES WITH READ LOCK\". Use it only if ALL your " "mariadb-backup now is using BACKUP LOCKS, which minimizes the "
"lock time. ALTER TABLE can run in parallel with BACKUP LOCKS."
"Use the --no-lock option it only if ALL your "
"tables are InnoDB and you DO NOT CARE about the binary log " "tables are InnoDB and you DO NOT CARE about the binary log "
"position of the backup. This option shouldn't be used if there " "position of the backup. This option shouldn't be used if there "
"are any DDL statements being executed or if any updates are " "are any DDL statements being executed or if any updates are "
@ -297,15 +297,6 @@ static struct my_option ibx_long_options[] =
(uchar *) &opt_ibx_safe_slave_backup, (uchar *) &opt_ibx_safe_slave_backup,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"rsync", OPT_RSYNC, "Uses the rsync utility to optimize local file "
"transfers. When this option is specified, innobackupex uses rsync "
"to copy all non-InnoDB files instead of spawning a separate cp for "
"each file, which can be much faster for servers with a large number "
"of databases or tables. This option cannot be used together with "
"--stream.",
(uchar *) &opt_ibx_rsync, (uchar *) &opt_ibx_rsync,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"force-non-empty-directories", OPT_FORCE_NON_EMPTY_DIRS, "This " {"force-non-empty-directories", OPT_FORCE_NON_EMPTY_DIRS, "This "
"option, when specified, makes --copy-back or --move-back transfer " "option, when specified, makes --copy-back or --move-back transfer "
"files to non-empty directories. Note that no existing files will be " "files to non-empty directories. Note that no existing files will be "
@ -330,13 +321,9 @@ static struct my_option ibx_long_options[] =
(uchar *) &opt_ibx_noversioncheck, (uchar *) &opt_ibx_noversioncheck,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"no-backup-locks", OPT_NO_BACKUP_LOCKS, "This option controls if " {"no-backup-locks", OPT_NO_BACKUP_LOCKS,
"backup locks should be used instead of FLUSH TABLES WITH READ LOCK " "Old disabled option which has no effect anymore.",
"on the backup stage. The option has no effect when backup locks are " (uchar *) 0, (uchar*) 0,
"not supported by the server. This option is enabled by default, "
"disable with --no-backup-locks.",
(uchar *) &opt_ibx_no_backup_locks,
(uchar *) &opt_ibx_no_backup_locks,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"decompress", OPT_DECOMPRESS, "Decompresses all files with the .qp " {"decompress", OPT_DECOMPRESS, "Decompresses all files with the .qp "
@ -402,11 +389,10 @@ static struct my_option ibx_long_options[] =
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ftwrl-wait-query-type", OPT_LOCK_WAIT_QUERY_TYPE, {"ftwrl-wait-query-type", OPT_LOCK_WAIT_QUERY_TYPE,
"This option specifies which types of queries are allowed to complete " "Old disabled option which has no effect anymore (not needed "
"before innobackupex will issue the global lock. Default is all.", "with BACKUP LOCKS)",
(uchar*) &opt_ibx_lock_wait_query_type, (uchar*) 0, (uchar*) 0, &query_type_typelib, GET_ENUM,
(uchar*) &opt_ibx_lock_wait_query_type, &query_type_typelib, REQUIRED_ARG, QUERY_TYPE_ALL, 0, 0, 0, 0, 0},
GET_ENUM, REQUIRED_ARG, QUERY_TYPE_ALL, 0, 0, 0, 0, 0},
{"kill-long-query-type", OPT_KILL_LONG_QUERY_TYPE, {"kill-long-query-type", OPT_KILL_LONG_QUERY_TYPE,
"This option specifies which types of queries should be killed to " "This option specifies which types of queries should be killed to "
@ -447,32 +433,32 @@ static struct my_option ibx_long_options[] =
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"kill-long-queries-timeout", OPT_KILL_LONG_QUERIES_TIMEOUT, {"kill-long-queries-timeout", OPT_KILL_LONG_QUERIES_TIMEOUT,
"This option specifies the number of seconds innobackupex waits " "Old disabled option which has no effect anymore (not needed "
"between starting FLUSH TABLES WITH READ LOCK and killing those " "with BACKUP LOCKS)",
"queries that block it. Default is 0 seconds, which means " (uchar*) 0, (uchar*) 0, 0, GET_UINT,
"innobackupex will not attempt to kill any queries.",
(uchar*) &opt_ibx_kill_long_queries_timeout,
(uchar*) &opt_ibx_kill_long_queries_timeout, 0, GET_UINT,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ftwrl-wait-timeout", OPT_LOCK_WAIT_TIMEOUT, {"ftwrl-wait-timeout", OPT_LOCK_WAIT_TIMEOUT,
"This option specifies time in seconds that innobackupex should wait " "Alias for startup-wait-timeout",
"for queries that would block FTWRL before running it. If there are " (uchar*) &opt_ibx_lock_wait_timeout,
"still such queries when the timeout expires, innobackupex terminates " (uchar*) &opt_ibx_lock_wait_timeout, 0, GET_UINT,
"with an error. Default is 0, in which case innobackupex does not " REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
"wait for queries to complete and starts FTWRL immediately.",
{"startup-wait-timeout", OPT_LOCK_WAIT_TIMEOUT,
"This option specifies time in seconds that mariadb-backup should wait for "
"BACKUP STAGE START to complete. BACKUP STAGE START has to wait until all "
"currently running queries using explicite LOCK TABLES has ended. "
"If there are still such queries when the timeout expires, mariadb-backup "
"terminates with an error. Default is 0, in which case mariadb-backup waits "
"indefinitely for BACKUP STAGE START to finish",
(uchar*) &opt_ibx_lock_wait_timeout, (uchar*) &opt_ibx_lock_wait_timeout,
(uchar*) &opt_ibx_lock_wait_timeout, 0, GET_UINT, (uchar*) &opt_ibx_lock_wait_timeout, 0, GET_UINT,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ftwrl-wait-threshold", OPT_LOCK_WAIT_THRESHOLD, {"ftwrl-wait-threshold", OPT_LOCK_WAIT_THRESHOLD,
"This option specifies the query run time threshold which is used by " "Old disabled option which has no effect anymore (not needed "
"innobackupex to detect long-running queries with a non-zero value " "with BACKUP LOCKS)",
"of --ftwrl-wait-timeout. FTWRL is not started until such " (uchar*) 0, (uchar*) 0, 0, GET_UINT,
"long-running queries exist. This option has no effect if "
"--ftwrl-wait-timeout is 0. Default value is 60 seconds.",
(uchar*) &opt_ibx_lock_wait_threshold,
(uchar*) &opt_ibx_lock_wait_threshold, 0, GET_UINT,
REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, REQUIRED_ARG, 60, 0, 0, 0, 0, 0},
{"safe-slave-backup-timeout", OPT_SAFE_SLAVE_BACKUP_TIMEOUT, {"safe-slave-backup-timeout", OPT_SAFE_SLAVE_BACKUP_TIMEOUT,
@ -864,10 +850,8 @@ ibx_init()
opt_slave_info = opt_ibx_slave_info; opt_slave_info = opt_ibx_slave_info;
opt_no_lock = opt_ibx_no_lock; opt_no_lock = opt_ibx_no_lock;
opt_safe_slave_backup = opt_ibx_safe_slave_backup; opt_safe_slave_backup = opt_ibx_safe_slave_backup;
opt_rsync = opt_ibx_rsync;
opt_force_non_empty_dirs = opt_ibx_force_non_empty_dirs; opt_force_non_empty_dirs = opt_ibx_force_non_empty_dirs;
opt_noversioncheck = opt_ibx_noversioncheck; opt_noversioncheck = opt_ibx_noversioncheck;
opt_no_backup_locks = opt_ibx_no_backup_locks;
opt_decompress = opt_ibx_decompress; opt_decompress = opt_ibx_decompress;
opt_incremental_history_name = opt_ibx_incremental_history_name; opt_incremental_history_name = opt_ibx_incremental_history_name;

View File

@ -0,0 +1,50 @@
#include "thread_pool.h"
#include "common.h"
bool ThreadPool::start(size_t threads_count) {
if (!m_stopped)
return false;
m_stopped = false;
for (unsigned i = 0; i < threads_count; ++i)
m_threads.emplace_back(&ThreadPool::thread_func, this, i);
return true;
}
void ThreadPool::stop() {
if (m_stopped)
return;
m_stop = true;
m_cv.notify_all();
for (auto &t : m_threads)
t.join();
m_stopped = true;
};
void ThreadPool::push(ThreadPool::job_t &&j) {
std::unique_lock<std::mutex> lock(m_mutex);
m_jobs.push(j);
lock.unlock();
m_cv.notify_one();
}
void ThreadPool::thread_func(unsigned thread_num) {
if (my_thread_init())
die("Can't init mysql thread");
std::unique_lock<std::mutex> lock(m_mutex);
while(true) {
if (m_stop)
goto exit;
while (!m_jobs.empty()) {
if (m_stop)
goto exit;
job_t j = std::move(m_jobs.front());
m_jobs.pop();
lock.unlock();
j(thread_num);
lock.lock();
}
m_cv.wait(lock, [&] { return m_stop || !m_jobs.empty(); });
}
exit:
my_thread_end();
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <queue>
#include <vector>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include "trx0sys.h"
class ThreadPool {
public:
typedef std::function<void(unsigned)> job_t;
ThreadPool() { m_stop = false; m_stopped = true; }
ThreadPool (ThreadPool &&other) = delete;
ThreadPool & operator= (ThreadPool &&other) = delete;
ThreadPool(const ThreadPool &) = delete;
ThreadPool & operator= (const ThreadPool &) = delete;
bool start(size_t threads_count);
void stop();
void push(job_t &&j);
size_t threads_count() const { return m_threads.size(); }
private:
void thread_func(unsigned thread_num);
std::mutex m_mutex;
std::condition_variable m_cv;
std::queue<job_t> m_jobs;
std::atomic<bool> m_stop;
std::atomic<bool> m_stopped;
std::vector<std::thread> m_threads;
};
class TasksGroup {
public:
TasksGroup(ThreadPool &thread_pool) : m_thread_pool(thread_pool) {
m_tasks_count = 0;
m_tasks_result = 1;
}
void push_task(ThreadPool::job_t &&j) {
++m_tasks_count;
m_thread_pool.push(std::forward<ThreadPool::job_t>(j));
}
void finish_task(int res) {
--m_tasks_count;
m_tasks_result.fetch_and(res);
}
int get_result() const { return m_tasks_result; }
bool is_finished() const {
return !m_tasks_count;
}
bool wait_for_finish() {
while (!is_finished())
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return get_result();
}
private:
ThreadPool &m_thread_pool;
std::atomic<size_t> m_tasks_count;
std::atomic<int> m_tasks_result;
};

View File

@ -144,6 +144,18 @@ wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
return false; return false;
} }
/* Check whether TRX_SYS page has been changed */
if (mach_read_from_4(page + FIL_PAGE_SPACE_ID)
== TRX_SYS_SPACE
&& mach_read_from_4(page + FIL_PAGE_OFFSET)
== TRX_SYS_PAGE_NO) {
msg(cursor->thread_n,
"--incremental backup is impossible if "
"the server had been restarted with "
"different innodb_undo_tablespaces.");
return false;
}
/* updated page */ /* updated page */
if (cp->npages == page_size / 4) { if (cp->npages == page_size / 4) {
/* flush buffer */ /* flush buffer */

View File

@ -55,6 +55,9 @@ permission notice:
#define XB_GALERA_INFO_FILENAME "xtrabackup_galera_info" #define XB_GALERA_INFO_FILENAME "xtrabackup_galera_info"
#define XB_GALERA_DONOR_INFO_FILENAME "donor_galera_info" #define XB_GALERA_DONOR_INFO_FILENAME "donor_galera_info"
/* backup copy of galera info file as sent by donor */
#define XB_GALERA_INFO_FILENAME_SST "xtrabackup_galera_info_SST"
/*********************************************************************** /***********************************************************************
Store Galera checkpoint info in the 'xtrabackup_galera_info' file, if that Store Galera checkpoint info in the 'xtrabackup_galera_info' file, if that
information is present in the trx system header. Otherwise, do nothing. */ information is present in the trx system header. Otherwise, do nothing. */
@ -68,19 +71,45 @@ xb_write_galera_info(bool incremental_prepare)
long long seqno; long long seqno;
MY_STAT statinfo; MY_STAT statinfo;
/* Do not overwrite an existing file to be compatible with xid.null();
servers with older server versions */
if (!incremental_prepare &&
my_stat(XB_GALERA_INFO_FILENAME, &statinfo, MYF(0)) != NULL) {
/* try to read last wsrep XID from innodb rsegs, we will use it
instead of galera info file received from donor
*/
if (!trx_rseg_read_wsrep_checkpoint(xid)) {
/* no worries yet, SST may have brought in galera info file
from some old MariaDB version, which does not support
wsrep XID storing in innodb rsegs
*/
return; return;
} }
xid.null(); /* if SST brought in galera info file, copy it as *_SST file
this will not be used, saved just for future reference
*/
if (my_stat(XB_GALERA_INFO_FILENAME, &statinfo, MYF(0)) != NULL) {
FILE* fp_in = fopen(XB_GALERA_INFO_FILENAME, "r");
FILE* fp_out = fopen(XB_GALERA_INFO_FILENAME_SST, "w");
if (!trx_rseg_read_wsrep_checkpoint(xid)) { char buf[BUFSIZ] = {'\0'};
size_t size;
return; while ((size = fread(buf, 1, BUFSIZ, fp_in))) {
if (fwrite(buf, 1, size, fp_out) != strlen(buf)) {
die(
"could not write to "
XB_GALERA_INFO_FILENAME_SST
", errno = %d\n",
errno);
}
}
if (!feof(fp_in)) {
die(
XB_GALERA_INFO_FILENAME_SST
" not fully copied\n"
);
}
fclose(fp_out);
fclose(fp_in);
} }
wsrep_uuid_t uuid; wsrep_uuid_t uuid;
@ -97,7 +126,6 @@ xb_write_galera_info(bool incremental_prepare)
"could not create " XB_GALERA_INFO_FILENAME "could not create " XB_GALERA_INFO_FILENAME
", errno = %d\n", ", errno = %d\n",
errno); errno);
exit(EXIT_FAILURE);
} }
seqno = wsrep_xid_seqno(&xid); seqno = wsrep_xid_seqno(&xid);

View File

@ -1,5 +0,0 @@
#include <mysql.h>
#include <string>
extern void xb_plugin_backup_init(MYSQL *mysql);
extern const char* xb_plugin_get_config();
extern void xb_plugin_prepare_init(int argc, char **argv, const char *dir);

View File

@ -255,7 +255,7 @@ mode_create(int argc, char **argv)
return 1; return 1;
} }
stream = xb_stream_write_new(); stream = xb_stream_write_new(nullptr, nullptr);
if (stream == NULL) { if (stream == NULL) {
msg("%s: xb_stream_write_new() failed.", my_progname); msg("%s: xb_stream_write_new() failed.", my_progname);
return 1; return 1;
@ -280,7 +280,7 @@ mode_create(int argc, char **argv)
goto err; goto err;
} }
file = xb_stream_write_open(stream, filepath, &mystat, NULL, NULL); file = xb_stream_write_open(stream, filepath, &mystat, false);
if (file == NULL) { if (file == NULL) {
goto err; goto err;
} }
@ -307,7 +307,8 @@ err:
static static
file_entry_t * file_entry_t *
file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen) file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen,
uchar chunk_flags)
{ {
file_entry_t *entry; file_entry_t *entry;
ds_file_t *file; ds_file_t *file;
@ -324,7 +325,8 @@ file_entry_new(extract_ctxt_t *ctxt, const char *path, uint pathlen)
} }
entry->pathlen = pathlen; entry->pathlen = pathlen;
file = ds_open(ctxt->ds_ctxt, path, NULL); file = ds_open(ctxt->ds_ctxt, path, NULL,
chunk_flags == XB_STREAM_FLAG_REWRITE);
if (file == NULL) { if (file == NULL) {
msg("%s: failed to create file.", my_progname); msg("%s: failed to create file.", my_progname);
@ -405,10 +407,50 @@ extract_worker_thread_func(void *arg)
(uchar *) chunk.path, (uchar *) chunk.path,
chunk.pathlen); chunk.pathlen);
if (entry && (chunk.type == XB_CHUNK_TYPE_REMOVE ||
chunk.type == XB_CHUNK_TYPE_RENAME)) {
msg("%s: rename and remove chunks can not be applied to opened file: %s",
my_progname, chunk.path);
pthread_mutex_unlock(ctxt->mutex);
break;
}
if (chunk.type == XB_CHUNK_TYPE_REMOVE) {
if (ds_remove(ctxt->ds_ctxt, chunk.path)) {
msg("%s: error on file removing: %s", my_progname, chunk.path);
pthread_mutex_unlock(ctxt->mutex);
res = XB_STREAM_READ_ERROR;
break;
}
pthread_mutex_unlock(ctxt->mutex);
continue;
}
if (chunk.type == XB_CHUNK_TYPE_RENAME) {
if (my_hash_search(ctxt->filehash,
reinterpret_cast<const uchar *>(chunk.data), chunk.length)) {
msg("%s: rename chunks can not be applied to opened file: %s",
my_progname, reinterpret_cast<const uchar *>(chunk.data));
pthread_mutex_unlock(ctxt->mutex);
break;
}
if (ds_rename(ctxt->ds_ctxt, chunk.path,
reinterpret_cast<const char *>(chunk.data))) {
msg("%s: error on file renaming: %s to %s", my_progname,
reinterpret_cast<const char *>(chunk.data), chunk.path);
pthread_mutex_unlock(ctxt->mutex);
res = XB_STREAM_READ_ERROR;
break;
}
pthread_mutex_unlock(ctxt->mutex);
continue;
}
if (entry == NULL) { if (entry == NULL) {
entry = file_entry_new(ctxt, entry = file_entry_new(ctxt,
chunk.path, chunk.path,
chunk.pathlen); chunk.pathlen,
chunk.flags);
if (entry == NULL) { if (entry == NULL) {
pthread_mutex_unlock(ctxt->mutex); pthread_mutex_unlock(ctxt->mutex);
break; break;
@ -425,6 +467,18 @@ extract_worker_thread_func(void *arg)
pthread_mutex_unlock(ctxt->mutex); pthread_mutex_unlock(ctxt->mutex);
if (chunk.type == XB_CHUNK_TYPE_SEEK) {
if (ds_seek_set(entry->file, chunk.offset)) {
msg("%s: my_seek() failed.", my_progname);
pthread_mutex_unlock(&entry->mutex);
res = XB_STREAM_READ_ERROR;
break;
}
entry->offset = chunk.offset;
pthread_mutex_unlock(&entry->mutex);
continue;
}
res = xb_stream_validate_checksum(&chunk); res = xb_stream_validate_checksum(&chunk);
if (res != XB_STREAM_READ_CHUNK) { if (res != XB_STREAM_READ_CHUNK) {

View File

@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
/* Chunk flags */ /* Chunk flags */
/* Chunk can be ignored if unknown version/format */ /* Chunk can be ignored if unknown version/format */
#define XB_STREAM_FLAG_IGNORABLE 0x01 #define XB_STREAM_FLAG_IGNORABLE 0x01
#define XB_STREAM_FLAG_REWRITE 0x02
/* Magic + flags + type + path len */ /* Magic + flags + type + path len */
#define CHUNK_HEADER_CONSTANT_LEN ((sizeof(XB_STREAM_CHUNK_MAGIC) - 1) + \ #define CHUNK_HEADER_CONSTANT_LEN ((sizeof(XB_STREAM_CHUNK_MAGIC) - 1) + \
@ -48,18 +49,21 @@ typedef enum {
/************************************************************************ /************************************************************************
Write interface. */ Write interface. */
typedef ssize_t xb_stream_write_callback(xb_wstream_file_t *file, typedef ssize_t xb_stream_write_callback(
void *userdata, void *userdata,
const void *buf, size_t len); const void *buf, size_t len);
xb_wstream_t *xb_stream_write_new(void); xb_wstream_t *xb_stream_write_new(
xb_stream_write_callback *write_callback, void *user_data);
xb_wstream_file_t *xb_stream_write_open(xb_wstream_t *stream, const char *path, xb_wstream_file_t *xb_stream_write_open(xb_wstream_t *stream, const char *path,
MY_STAT *mystat, void *userdata, const MY_STAT *mystat, bool rewrite);
xb_stream_write_callback *onwrite);
int xb_stream_write_data(xb_wstream_file_t *file, const void *buf, size_t len); int xb_stream_write_data(xb_wstream_file_t *file, const void *buf, size_t len);
int xb_stream_write_seek_set(xb_wstream_file_t *file, my_off_t offset);
int xb_stream_write_remove(xb_wstream_t *stream, const char *path);
int
xb_stream_write_rename(
xb_wstream_t *stream, const char *old_path, const char *new_path);
int xb_stream_write_close(xb_wstream_file_t *file); int xb_stream_write_close(xb_wstream_file_t *file);
int xb_stream_write_done(xb_wstream_t *stream); int xb_stream_write_done(xb_wstream_t *stream);
@ -76,6 +80,9 @@ typedef enum {
typedef enum { typedef enum {
XB_CHUNK_TYPE_UNKNOWN = '\0', XB_CHUNK_TYPE_UNKNOWN = '\0',
XB_CHUNK_TYPE_PAYLOAD = 'P', XB_CHUNK_TYPE_PAYLOAD = 'P',
XB_CHUNK_TYPE_RENAME = 'R',
XB_CHUNK_TYPE_REMOVE = 'D',
XB_CHUNK_TYPE_SEEK = 'S',
XB_CHUNK_TYPE_EOF = 'E' XB_CHUNK_TYPE_EOF = 'E'
} xb_chunk_type_t; } xb_chunk_type_t;

View File

@ -59,6 +59,9 @@ validate_chunk_type(uchar code)
{ {
switch ((xb_chunk_type_t) code) { switch ((xb_chunk_type_t) code) {
case XB_CHUNK_TYPE_PAYLOAD: case XB_CHUNK_TYPE_PAYLOAD:
case XB_CHUNK_TYPE_RENAME:
case XB_CHUNK_TYPE_REMOVE:
case XB_CHUNK_TYPE_SEEK:
case XB_CHUNK_TYPE_EOF: case XB_CHUNK_TYPE_EOF:
return (xb_chunk_type_t) code; return (xb_chunk_type_t) code;
default: default:
@ -159,10 +162,29 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk)
} }
chunk->path[pathlen] = '\0'; chunk->path[pathlen] = '\0';
if (chunk->type == XB_CHUNK_TYPE_EOF) { if (chunk->type == XB_CHUNK_TYPE_EOF ||
chunk->type == XB_CHUNK_TYPE_REMOVE) {
return XB_STREAM_READ_CHUNK; return XB_STREAM_READ_CHUNK;
} }
if (chunk->type == XB_CHUNK_TYPE_RENAME) {
F_READ(tmpbuf, 4);
size_t new_pathlen = uint4korr(tmpbuf);
if (new_pathlen >= FN_REFLEN) {
msg("xb_stream_read_chunk(): path length (%lu) for new name of 'rename'"
" chunk is too large", (ulong) new_pathlen);
goto err;
}
chunk->length = new_pathlen;
stream->offset +=4;
}
else if (chunk->type == XB_CHUNK_TYPE_SEEK) {
F_READ(tmpbuf, 8);
chunk->offset = uint8korr(tmpbuf);
stream->offset += 8;
return XB_STREAM_READ_CHUNK;
}
else {
/* Payload length */ /* Payload length */
F_READ(tmpbuf, 16); F_READ(tmpbuf, 16);
ullval = uint8korr(tmpbuf); ullval = uint8korr(tmpbuf);
@ -185,19 +207,33 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk)
} }
chunk->offset = (my_off_t) ullval; chunk->offset = (my_off_t) ullval;
stream->offset += 8; stream->offset += 8;
}
/* Reallocate the buffer if needed */ /* Reallocate the buffer if needed, take into account trailing '\0' for
if (chunk->length > chunk->buflen) { new file name in the case of XB_CHUNK_TYPE_RENAME */
chunk->data = my_realloc(PSI_NOT_INSTRUMENTED, chunk->data, chunk->length, if (chunk->length + 1 > chunk->buflen) {
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); chunk->data = my_realloc(PSI_NOT_INSTRUMENTED, chunk->data,
chunk->length + 1, MYF(MY_WME | MY_ALLOW_ZERO_PTR));
if (chunk->data == NULL) { if (chunk->data == NULL) {
msg("xb_stream_read_chunk(): failed to increase buffer " msg("xb_stream_read_chunk(): failed to increase buffer "
"to %lu bytes.", (ulong) chunk->length); "to %lu bytes.", (ulong) chunk->length + 1);
goto err; goto err;
} }
chunk->buflen = chunk->length; chunk->buflen = chunk->length + 1;
} }
if (chunk->type == XB_CHUNK_TYPE_RENAME) {
if (chunk->length == 0) {
msg("xb_stream_read_chunk(): failed to read new name for file to rename "
": %s", chunk->path);
goto err;
}
F_READ(chunk->data, chunk->length);
stream->offset += chunk->length;
reinterpret_cast<char *>(chunk->data)[chunk->length] = '\0';
++chunk->length;
}
else {
/* Checksum */ /* Checksum */
F_READ(tmpbuf, 4); F_READ(tmpbuf, 4);
chunk->checksum = uint4korr(tmpbuf); chunk->checksum = uint4korr(tmpbuf);
@ -210,6 +246,7 @@ xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk)
} }
stream->offset += 4; stream->offset += 4;
}
return XB_STREAM_READ_CHUNK; return XB_STREAM_READ_CHUNK;

View File

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
#include <my_global.h> #include <my_global.h>
#include <my_base.h> #include <my_base.h>
#include <zlib.h> #include <zlib.h>
#include <stdint.h>
#include "common.h" #include "common.h"
#include "xbstream.h" #include "xbstream.h"
@ -29,6 +30,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
struct xb_wstream_struct { struct xb_wstream_struct {
pthread_mutex_t mutex; pthread_mutex_t mutex;
xb_stream_write_callback *write;
void *user_data;
}; };
struct xb_wstream_file_struct { struct xb_wstream_file_struct {
@ -39,8 +42,7 @@ struct xb_wstream_file_struct {
char *chunk_ptr; char *chunk_ptr;
size_t chunk_free; size_t chunk_free;
my_off_t offset; my_off_t offset;
void *userdata; bool rewrite;
xb_stream_write_callback *write;
}; };
static int xb_stream_flush(xb_wstream_file_t *file); static int xb_stream_flush(xb_wstream_file_t *file);
@ -50,7 +52,7 @@ static int xb_stream_write_eof(xb_wstream_file_t *file);
static static
ssize_t ssize_t
xb_stream_default_write_callback(xb_wstream_file_t *file __attribute__((unused)), xb_stream_default_write_callback(
void *userdata __attribute__((unused)), void *userdata __attribute__((unused)),
const void *buf, size_t len) const void *buf, size_t len)
{ {
@ -60,21 +62,31 @@ xb_stream_default_write_callback(xb_wstream_file_t *file __attribute__((unused))
} }
xb_wstream_t * xb_wstream_t *
xb_stream_write_new(void) xb_stream_write_new(
xb_stream_write_callback *write_callback, void *user_data)
{ {
xb_wstream_t *stream; xb_wstream_t *stream;
stream = (xb_wstream_t *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(xb_wstream_t), MYF(MY_FAE)); stream = (xb_wstream_t *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(xb_wstream_t), MYF(MY_FAE));
pthread_mutex_init(&stream->mutex, NULL); pthread_mutex_init(&stream->mutex, NULL);
if (write_callback) {
#ifdef _WIN32
setmode(fileno(stdout), _O_BINARY);
#endif
stream->write = write_callback;
stream->user_data = user_data;
}
else {
stream->write = xb_stream_default_write_callback;
stream->user_data = user_data;
}
return stream;; return stream;;
} }
xb_wstream_file_t * xb_wstream_file_t *
xb_stream_write_open(xb_wstream_t *stream, const char *path, xb_stream_write_open(xb_wstream_t *stream, const char *path,
MY_STAT *mystat __attribute__((unused)), const MY_STAT *mystat __attribute__((unused)), bool rewrite)
void *userdata,
xb_stream_write_callback *onwrite)
{ {
xb_wstream_file_t *file; xb_wstream_file_t *file;
size_t path_len; size_t path_len;
@ -109,16 +121,7 @@ xb_stream_write_open(xb_wstream_t *stream, const char *path,
file->offset = 0; file->offset = 0;
file->chunk_ptr = file->chunk; file->chunk_ptr = file->chunk;
file->chunk_free = XB_STREAM_MIN_CHUNK_SIZE; file->chunk_free = XB_STREAM_MIN_CHUNK_SIZE;
if (onwrite) { file->rewrite = rewrite;
#ifdef _WIN32
setmode(fileno(stdout), _O_BINARY);
#endif
file->userdata = userdata;
file->write = onwrite;
} else {
file->userdata = NULL;
file->write = xb_stream_default_write_callback;
}
return file; return file;
} }
@ -202,7 +205,8 @@ xb_stream_write_chunk(xb_wstream_file_t *file, const void *buf, size_t len)
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1); memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1);
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1; ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1;
*ptr++ = 0; /* Chunk flags */ *ptr++ =
file->rewrite ? XB_STREAM_FLAG_REWRITE : 0; /* Chunk flags */
*ptr++ = (uchar) XB_CHUNK_TYPE_PAYLOAD; /* Chunk type */ *ptr++ = (uchar) XB_CHUNK_TYPE_PAYLOAD; /* Chunk type */
@ -227,11 +231,11 @@ xb_stream_write_chunk(xb_wstream_file_t *file, const void *buf, size_t len)
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); xb_ad(ptr <= tmpbuf + sizeof(tmpbuf));
if (file->write(file, file->userdata, tmpbuf, ptr-tmpbuf) == -1) if (stream->write(stream->user_data, tmpbuf, ptr-tmpbuf) == -1)
goto err; goto err;
if (file->write(file, file->userdata, buf, len) == -1) /* Payload */ if (stream->write(stream->user_data, buf, len) == -1) /* Payload */
goto err; goto err;
file->offset+= len; file->offset+= len;
@ -247,6 +251,38 @@ err:
return 1; return 1;
} }
int xb_stream_write_seek_set(xb_wstream_file_t *file, my_off_t offset)
{
/* Chunk magic + flags + chunk type + path_len + path + offset */
uchar tmpbuf[sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1 + 4 +
FN_REFLEN + 8];
int error = 0;
xb_wstream_t *stream = file->stream;
uchar *ptr = tmpbuf;
/* Chunk magic */
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1);
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1;
*ptr++ = 0; /* Chunk flags */
*ptr++ = (uchar) XB_CHUNK_TYPE_SEEK; /* Chunk type */
int4store(ptr, file->path_len); /* Path length */
ptr += 4;
memcpy(ptr, file->path, file->path_len); /* Path */
ptr += file->path_len;
int8store(ptr, static_cast<int64_t>(offset)); /* Offset */
ptr += 8;
if (xb_stream_flush(file))
return 1;
pthread_mutex_lock(&stream->mutex);
if (stream->write(stream->user_data, tmpbuf, ptr-tmpbuf) == -1)
error = 1;
if (!error)
file->offset = offset;
pthread_mutex_unlock(&stream->mutex);
if (xb_stream_flush(file))
return 1;
return error;
}
static static
int int
xb_stream_write_eof(xb_wstream_file_t *file) xb_stream_write_eof(xb_wstream_file_t *file)
@ -278,7 +314,7 @@ xb_stream_write_eof(xb_wstream_file_t *file)
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); xb_ad(ptr <= tmpbuf + sizeof(tmpbuf));
if (file->write(file, file->userdata, tmpbuf, if (stream->write(stream->user_data, tmpbuf,
(ulonglong) (ptr - tmpbuf)) == -1) (ulonglong) (ptr - tmpbuf)) == -1)
goto err; goto err;
@ -291,3 +327,77 @@ err:
return 1; return 1;
} }
int
xb_stream_write_remove(xb_wstream_t *stream, const char *path) {
/* Chunk magic + flags + chunk type + path_len + path */
uchar tmpbuf[sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1 + 4 + FN_REFLEN];
uchar *ptr = tmpbuf;
/* Chunk magic */
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1);
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1;
*ptr++ = 0; /* Chunk flags */
*ptr++ = (uchar) XB_CHUNK_TYPE_REMOVE; /* Chunk type */
size_t path_len = strlen(path);
int4store(ptr, path_len); /* Path length */
ptr += 4;
memcpy(ptr, path, path_len); /* Path */
ptr += path_len;
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf));
pthread_mutex_lock(&stream->mutex);
ssize_t result = stream->write(stream->user_data, tmpbuf,
(ulonglong) (ptr - tmpbuf));
pthread_mutex_unlock(&stream->mutex);
return result < 0;
}
int
xb_stream_write_rename(
xb_wstream_t *stream, const char *old_path, const char *new_path) {
/* Chunk magic + flags + chunk type + path_len + path + path_len + path*/
uchar tmpbuf[sizeof(XB_STREAM_CHUNK_MAGIC) - 1 + 1 + 1 +
4 + FN_REFLEN + 4 + FN_REFLEN];
uchar *ptr = tmpbuf;
/* Chunk magic */
memcpy(ptr, XB_STREAM_CHUNK_MAGIC, sizeof(XB_STREAM_CHUNK_MAGIC) - 1);
ptr += sizeof(XB_STREAM_CHUNK_MAGIC) - 1;
*ptr++ = 0; /* Chunk flags */
*ptr++ = (uchar) XB_CHUNK_TYPE_RENAME; /* Chunk type */
size_t path_len = strlen(old_path);
int4store(ptr, path_len); /* Path length */
ptr += 4;
memcpy(ptr, old_path, path_len); /* Path */
ptr += path_len;
path_len = strlen(new_path);
int4store(ptr, path_len); /* Path length */
ptr += 4;
memcpy(ptr, new_path, path_len); /* Path */
ptr += path_len;
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf));
pthread_mutex_lock(&stream->mutex);
ssize_t result = stream->write(stream->user_data, tmpbuf,
(ulonglong) (ptr - tmpbuf));
pthread_mutex_unlock(&stream->mutex);
return result < 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
#include "xbstream.h" #include "xbstream.h"
#include "fil0fil.h" #include "fil0fil.h"
#include <set> #include <set>
#include "handler.h"
#include <utility>
#include <vector>
#include <tuple>
#include <functional>
#define XB_TOOL_NAME "mariadb-backup" #define XB_TOOL_NAME "mariadb-backup"
#define XB_HISTORY_TABLE "mysql.mariadb_backup_history" #define XB_HISTORY_TABLE "mysql.mariadb_backup_history"
@ -110,7 +117,7 @@ extern my_bool xtrabackup_decrypt_decompress;
extern char *innobase_data_file_path; extern char *innobase_data_file_path;
extern longlong innobase_page_size; extern longlong innobase_page_size;
extern int xtrabackup_parallel; extern uint xtrabackup_parallel;
extern my_bool xb_close_files; extern my_bool xb_close_files;
extern const char *xtrabackup_compress_alg; extern const char *xtrabackup_compress_alg;
@ -129,7 +136,6 @@ extern my_bool opt_galera_info;
extern my_bool opt_slave_info; extern my_bool opt_slave_info;
extern my_bool opt_no_lock; extern my_bool opt_no_lock;
extern my_bool opt_safe_slave_backup; extern my_bool opt_safe_slave_backup;
extern my_bool opt_rsync;
extern my_bool opt_force_non_empty_dirs; extern my_bool opt_force_non_empty_dirs;
extern my_bool opt_noversioncheck; extern my_bool opt_noversioncheck;
extern my_bool opt_no_backup_locks; extern my_bool opt_no_backup_locks;
@ -286,15 +292,40 @@ fil_file_readdir_next_file(
os_file_stat_t* info); /*!< in/out: buffer where the os_file_stat_t* info); /*!< in/out: buffer where the
info is returned */ info is returned */
#ifndef DBUG_OFF const char *convert_dst(const char *dst);
#include <fil0fil.h>
extern void dbug_mariabackup_event(const char *event,
const fil_space_t::name_type key);
#define DBUG_MARIABACKUP_EVENT(A, B) \ std::string get_table_version_from_image(const std::vector<uchar> &frm_image);
DBUG_EXECUTE_IF("mariabackup_events", dbug_mariabackup_event(A, B);) std::pair<bool, legacy_db_type>
#else get_table_engine_from_image(const std::vector<uchar> &frm_image);
#define DBUG_MARIABACKUP_EVENT(A, B) /* empty */ std::string read_table_version_id(File file);
#endif // DBUG_OFF
std::string convert_tablename_to_filepath(
const char *data_dir_path, const std::string &db, const std::string &table);
std::tuple<std::string, std::string, std::string>
convert_filepath_to_tablename(const char *filepath);
typedef std::string table_key_t;
inline table_key_t table_key(const std::string &db, const std::string &table) {
return std::string(db).append(".").append(table);
};
inline table_key_t table_key(const char *db, const char *table) {
return std::string(db).append(".").append(table);
};
typedef std::function<void(std::string, std::string, std::string)>
post_copy_table_hook_t;
my_bool
check_if_skip_table(
/******************/
const char* name); /*!< in: path to the table */
bool is_log_table(const char *dbname, const char *tablename);
bool is_stats_table(const char *dbname, const char *tablename);
extern my_bool xtrabackup_copy_back;
extern my_bool xtrabackup_move_back;
#endif /* XB_XTRABACKUP_H */ #endif /* XB_XTRABACKUP_H */

View File

@ -7,30 +7,21 @@ ELSE()
ENDIF() ENDIF()
IF(CMAKE_SIZEOF_VOID_P MATCHES 8) IF(CMAKE_SIZEOF_VOID_P MATCHES 8)
IF(MSVC_INTEL) IF(MSVC_INTEL AND NOT (CMAKE_C_COMPILER_ID MATCHES Clang))
SET(WOLFSSL_INTELASM ON) SET(WOLFSSL_INTELASM ON)
SET(WOLFSSL_X86_64_BUILD 1)
SET(HAVE_INTEL_RDSEED 1) SET(HAVE_INTEL_RDSEED 1)
SET(HAVE_INTEL_RDRAND 1) SET(HAVE_INTEL_RDRAND 1)
ELSEIF(CMAKE_ASM_COMPILER_ID MATCHES "Clang" AND CMAKE_VERSION VERSION_LESS 3.16)
# WolfSSL 5.5.4 bug workaround below does not work, due to some CMake bug
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64")
SET(WOLFSSL_X86_64_BUILD 1)
IF(CMAKE_C_COMPILER_ID MATCHES GNU AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) IF(CMAKE_C_COMPILER_ID MATCHES GNU AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9)
MESSAGE_ONCE(NO_INTEL_ASSEMBLY "Disable Intel assembly for WolfSSL - compiler is too old") MESSAGE_ONCE(NO_INTEL_ASSEMBLY "Disable Intel assembly for WolfSSL - compiler is too old")
ELSE() ELSEIF(WITH_MSAN)
IF(WITH_MSAN) MESSAGE_ONCE(MSAN_CANT_HANDLE_IT "Disable Intel assembly for WolfSSL - MSAN can't handle it")
MESSAGE_ONCE(MSAN_CANT_HANDLE_IT
"Disable Intel assembly for WolfSSL - MSAN can't handle it")
ELSE() ELSE()
MY_CHECK_C_COMPILER_FLAG(-maes) MY_CHECK_C_COMPILER_FLAG(-maes)
MY_CHECK_C_COMPILER_FLAG(-msse4) MY_CHECK_C_COMPILER_FLAG(-msse4)
MY_CHECK_C_COMPILER_FLAG(-mpclmul) MY_CHECK_C_COMPILER_FLAG(-mpclmul)
IF(have_C__maes AND have_C__msse4 AND have_C__mpclmul) IF(have_C__maes AND have_C__msse4 AND have_C__mpclmul)
SET(WOLFSSL_INTELASM ON) SET(WOLFSSL_INTELASM ON)
ENDIF()
ENDIF()
MY_CHECK_C_COMPILER_FLAG(-mrdrnd) MY_CHECK_C_COMPILER_FLAG(-mrdrnd)
MY_CHECK_C_COMPILER_FLAG(-mrdseed) MY_CHECK_C_COMPILER_FLAG(-mrdseed)
IF(have_C__mrdrnd) IF(have_C__mrdrnd)
@ -42,11 +33,17 @@ ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64")
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDIF()
SET(WOLFSSL_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/src) SET(WOLFSSL_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/src)
SET(WOLFCRYPT_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfcrypt/src)
ADD_DEFINITIONS(${SSL_DEFINES}) ADD_DEFINITIONS(${SSL_DEFINES})
ADD_DEFINITIONS(-DWOLFSSL_LIB -DBUILDING_WOLFSSL)
ADD_DEFINITIONS(-DWOLFSSL_SP_4096)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl)
INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS})
SET(WOLFSSL_SOURCES add_library(wolfssl STATIC
${WOLFSSL_SRCDIR}/crl.c ${WOLFSSL_SRCDIR}/crl.c
${WOLFSSL_SRCDIR}/internal.c ${WOLFSSL_SRCDIR}/internal.c
${WOLFSSL_SRCDIR}/keys.c ${WOLFSSL_SRCDIR}/keys.c
@ -54,33 +51,7 @@ SET(WOLFSSL_SOURCES
${WOLFSSL_SRCDIR}/wolfio.c ${WOLFSSL_SRCDIR}/wolfio.c
${WOLFSSL_SRCDIR}/ocsp.c ${WOLFSSL_SRCDIR}/ocsp.c
${WOLFSSL_SRCDIR}/ssl.c ${WOLFSSL_SRCDIR}/ssl.c
${WOLFSSL_SRCDIR}/tls13.c) ${WOLFSSL_SRCDIR}/tls13.c
ADD_DEFINITIONS(-DWOLFSSL_LIB -DBUILDING_WOLFSSL)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl)
IF(MSVC)
# size_t to long truncation warning
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd4267 -wd4334 -wd4028 -wd4244")
ENDIF()
ADD_CONVENIENCE_LIBRARY(wolfssl ${WOLFSSL_SOURCES})
# Workaround linker crash with older Ubuntu binutils
# e.g aborting at ../../bfd/merge.c line 873 in _bfd_merged_section_offset
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
STRING(REPLACE "-g " "-g1 " CMAKE_C_FLAGS_RELWITHDEBINFO
${CMAKE_C_FLAGS_RELWITHDEBINFO})
STRING(REPLACE "-g " "-g1 " CMAKE_C_FLAGS_DEBUG
${CMAKE_C_FLAGS_DEBUG})
STRING(REPLACE "-ggdb3 " " " CMAKE_C_FLAGS_RELWITHDEBINFO
${CMAKE_C_FLAGS_RELWITHDEBINFO})
STRING(REPLACE "-ggdb3 " " " CMAKE_C_FLAGS_DEBUG
${CMAKE_C_FLAGS_DEBUG})
ENDIF()
SET(WOLFCRYPT_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfcrypt/src)
SET(WOLFCRYPT_SOURCES
${WOLFCRYPT_SRCDIR}/aes.c ${WOLFCRYPT_SRCDIR}/aes.c
${WOLFCRYPT_SRCDIR}/arc4.c ${WOLFCRYPT_SRCDIR}/arc4.c
${WOLFCRYPT_SRCDIR}/asn.c ${WOLFCRYPT_SRCDIR}/asn.c
@ -110,69 +81,56 @@ ${WOLFCRYPT_SRCDIR}/wc_encrypt.c
${WOLFCRYPT_SRCDIR}/hash.c ${WOLFCRYPT_SRCDIR}/hash.c
${WOLFCRYPT_SRCDIR}/wolfmath.c ${WOLFCRYPT_SRCDIR}/wolfmath.c
${WOLFCRYPT_SRCDIR}/kdf.c ${WOLFCRYPT_SRCDIR}/kdf.c
${WOLFCRYPT_SRCDIR}/sp_int.c
${WOLFCRYPT_SRCDIR}/sp_c32.c
${WOLFCRYPT_SRCDIR}/sp_c64.c
) )
# Use fastmath large number math library. # Optimizations, assembly
IF(NOT (MSVC AND CMAKE_C_COMPILER_ID MATCHES Clang)) if(WOLFSSL_INTELASM)
# Can't use clang-cl with WOLFSSL_FASTMATH set(WOLFSSL_X86_64_BUILD 1)
# due to https://bugs.llvm.org/show_bug.cgi?id=25305 set(WOLFSSL_SP_X86_64 1)
SET(WOLFSSL_FASTMATH 1) set(WOLFSSL_SP_X86_64_ASM 1)
ENDIF() set(WOLFSSL_AESNI 1)
target_sources(wolfssl PRIVATE
IF(WOLFSSL_FASTMATH) ${WOLFCRYPT_SRCDIR}/cpuid.c
SET(USE_FAST_MATH 1) ${WOLFCRYPT_SRCDIR}/sp_x86_64.c
SET(TFM_TIMING_RESISTANT 1) )
# FP_MAX_BITS is set high solely to satisfy ssl_8k_key.test if(MSVC_INTEL)
# WolfSSL will use more stack space with it target_sources(wolfssl PRIVATE
SET(FP_MAX_BITS 16384)
SET(WOLFCRYPT_SOURCES ${WOLFCRYPT_SOURCES} ${WOLFCRYPT_SRCDIR}/tfm.c)
IF((CMAKE_SIZEOF_VOID_P MATCHES 4) AND (CMAKE_SYSTEM_PROCESSOR MATCHES "86")
AND (NOT MSVC))
# Workaround https://github.com/wolfSSL/wolfssl/issues/4245
# On 32bit Intel, to satisfy inline assembly's wish for free registers
# 1. use -fomit-frame-pointer
# 2. With GCC 4, additionally use -fno-PIC, which works on x86
# (modern GCC has PIC optimizations, that make it unnecessary)
# The following assumes GCC or Clang
SET(TFM_COMPILE_FLAGS "-fomit-frame-pointer")
IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "5")
SET(TFM_COMPILE_FLAGS "${TFM_COMPILE_FLAGS} -fno-PIC")
ENDIF()
SET_SOURCE_FILES_PROPERTIES(${WOLFCRYPT_SRCDIR}/tfm.c
PROPERTIES COMPILE_FLAGS ${TFM_COMPILE_FLAGS})
ENDIF()
ELSE()
SET(WOLFSSL_SP_MATH_ALL 1)
SET(WOLFCRYPT_SOURCES ${WOLFCRYPT_SOURCES} ${WOLFCRYPT_SRCDIR}/sp_int.c)
ENDIF()
IF(WOLFSSL_X86_64_BUILD)
LIST(APPEND WOLFCRYPT_SOURCES ${WOLFCRYPT_SRCDIR}/cpuid.c)
IF(MSVC)
SET(WOLFSSL_AESNI 1)
LIST(APPEND WOLFCRYPT_SOURCES
${WOLFCRYPT_SRCDIR}/aes_asm.asm ${WOLFCRYPT_SRCDIR}/aes_asm.asm
${WOLFCRYPT_SRCDIR}/aes_gcm_asm.asm) ${WOLFCRYPT_SRCDIR}/aes_gcm_asm.asm
IF(CMAKE_C_COMPILER_ID MATCHES Clang) ${WOLFCRYPT_SRCDIR}/sp_x86_64_asm.asm
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -msse4.2 -mpclmul -mrdrnd -mrdseed") )
ENDIF() target_compile_options(wolfssl PRIVATE
ELSEIF(WOLFSSL_INTELASM) $<$<COMPILE_LANG_AND_ID:C,Clang>:-maes -msse4.2 -mpclmul -mrdrnd -mrdseed>
SET(WOLFSSL_AESNI 1) $<$<COMPILE_LANGUAGE:ASM_MASM>:/Zi>
SET(USE_INTEL_SPEEDUP 1) )
LIST(APPEND WOLFCRYPT_SOURCES else()
set(USE_INTEL_SPEEDUP 1)
target_sources(wolfssl PRIVATE
${WOLFCRYPT_SRCDIR}/aes_asm.S ${WOLFCRYPT_SRCDIR}/aes_asm.S
${WOLFCRYPT_SRCDIR}/aes_gcm_asm.S ${WOLFCRYPT_SRCDIR}/aes_gcm_asm.S
${WOLFCRYPT_SRCDIR}/chacha_asm.S ${WOLFCRYPT_SRCDIR}/chacha_asm.S
${WOLFCRYPT_SRCDIR}/poly1305_asm.S ${WOLFCRYPT_SRCDIR}/poly1305_asm.S
${WOLFCRYPT_SRCDIR}/sha512_asm.S ${WOLFCRYPT_SRCDIR}/sha512_asm.S
${WOLFCRYPT_SRCDIR}/sha256_asm.S) ${WOLFCRYPT_SRCDIR}/sha256_asm.S
ADD_DEFINITIONS(-maes -msse4.2 -mpclmul) ${WOLFCRYPT_SRCDIR}/sp_x86_64_asm.S
# WolfSSL 5.5.4 bug - user_settings.h not included into aes_asm.S )
SET_PROPERTY(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD") target_compile_options(wolfssl PRIVATE -maes -msse4.2 -mpclmul)
ENDIF() # Workaround 5.5.4 bug (user_settings.h not included into aes_asm.S)
ENDIF() set_property(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD")
endif()
endif()
# Silence some warnings
if(MSVC)
# truncation warnings
target_compile_options(wolfssl PRIVATE $<$<COMPILE_LANGUAGE:C>:/wd4244>)
if(CMAKE_C_COMPILER_ID MATCHES Clang)
target_compile_options(wolfssl PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-incompatible-function-pointer-types>)
endif()
endif()
CONFIGURE_FILE(user_settings.h.in user_settings.h) CONFIGURE_FILE(user_settings.h.in user_settings.h)
INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS})
ADD_CONVENIENCE_LIBRARY(wolfcrypt ${WOLFCRYPT_SOURCES})

View File

@ -21,6 +21,7 @@
#define HAVE_AESGCM #define HAVE_AESGCM
#define HAVE_CHACHA #define HAVE_CHACHA
#define HAVE_POLY1305 #define HAVE_POLY1305
#define HAVE_THREAD_LS
#define WOLFSSL_AES_COUNTER #define WOLFSSL_AES_COUNTER
#define NO_WOLFSSL_STUB #define NO_WOLFSSL_STUB
#define OPENSSL_ALL #define OPENSSL_ALL
@ -51,20 +52,19 @@
#define NO_RABBIT #define NO_RABBIT
#define NO_RC4 #define NO_RC4
/*
FP_MAX_BITS is set high solely to satisfy ssl_8k_key.test
WolfSSL will use more stack space with it, with fastmath
*/
#cmakedefine FP_MAX_BITS 16384
#define RSA_MAX_SIZE 8192 #define RSA_MAX_SIZE 8192
#define WOLFSSL_SP_MATH_ALL
#define WOLFSSL_HAVE_SP_RSA
#ifndef WOLFSSL_SP_4096
#define WOLFSSL_SP_4096
#endif
#cmakedefine WOLFSSL_AESNI #cmakedefine WOLFSSL_AESNI
#cmakedefine USE_FAST_MATH
#cmakedefine TFM_TIMING_RESISTANT
#cmakedefine HAVE_INTEL_RDSEED #cmakedefine HAVE_INTEL_RDSEED
#cmakedefine HAVE_INTEL_RDRAND #cmakedefine HAVE_INTEL_RDRAND
#cmakedefine USE_INTEL_SPEEDUP #cmakedefine USE_INTEL_SPEEDUP
#cmakedefine USE_FAST_MATH
#cmakedefine WOLFSSL_X86_64_BUILD #cmakedefine WOLFSSL_X86_64_BUILD
#cmakedefine WOLFSSL_SP_MATH_ALL #cmakedefine WOLFSSL_SP_X86_64
#cmakedefine WOLFSSL_SP_X86_64_ASM
#endif /* WOLFSSL_USER_SETTINGS_H */ #endif /* WOLFSSL_USER_SETTINGS_H */

View File

@ -49,6 +49,7 @@
#define HA_OPEN_MERGE_TABLE 2048U #define HA_OPEN_MERGE_TABLE 2048U
#define HA_OPEN_FOR_CREATE 4096U #define HA_OPEN_FOR_CREATE 4096U
#define HA_OPEN_FOR_DROP (1U << 13) /* Open part of drop */ #define HA_OPEN_FOR_DROP (1U << 13) /* Open part of drop */
#define HA_OPEN_GLOBAL_TMP_TABLE (1U << 14) /* TMP table used by repliction */
/* /*
Allow opening even if table is incompatible as this is for ALTER TABLE which Allow opening even if table is incompatible as this is for ALTER TABLE which
@ -377,6 +378,12 @@ enum ha_base_keytype {
#define HA_CREATE_INTERNAL_TABLE 256U #define HA_CREATE_INTERNAL_TABLE 256U
#define HA_PRESERVE_INSERT_ORDER 512U #define HA_PRESERVE_INSERT_ORDER 512U
#define HA_CREATE_NO_ROLLBACK 1024U #define HA_CREATE_NO_ROLLBACK 1024U
/*
A temporary table that can be used by different threads, eg. replication
threads. This flag ensure that memory is not allocated with THREAD_SPECIFIC,
as we do for other temporary tables.
*/
#define HA_CREATE_GLOBAL_TMP_TABLE 2048U
/* Flags used by start_bulk_insert */ /* Flags used by start_bulk_insert */

View File

@ -22,14 +22,15 @@
#include <m_string.h> #include <m_string.h>
#include <my_pthread.h> #include <my_pthread.h>
typedef uint32 my_bitmap_map; typedef ulonglong my_bitmap_map;
typedef struct st_bitmap typedef struct st_bitmap
{ {
my_bitmap_map *bitmap; my_bitmap_map *bitmap;
my_bitmap_map *last_word_ptr; my_bitmap_map *last_word_ptr;
my_bitmap_map last_word_mask; my_bitmap_map last_bit_mask;
uint32 n_bits; /* number of bits occupied by the above */ uint32 n_bits; /* number of bits occupied by the above */
my_bool bitmap_allocated;
} MY_BITMAP; } MY_BITMAP;
#ifdef __cplusplus #ifdef __cplusplus
@ -39,7 +40,7 @@ extern "C" {
/* Reset memory. Faster then doing a full bzero */ /* Reset memory. Faster then doing a full bzero */
#define my_bitmap_clear(A) ((A)->bitmap= 0) #define my_bitmap_clear(A) ((A)->bitmap= 0)
extern void create_last_word_mask(MY_BITMAP *map); extern void create_last_bit_mask(MY_BITMAP *map);
extern my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits); extern my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits);
extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); extern my_bool bitmap_is_clear_all(const MY_BITMAP *map);
extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size);
@ -53,12 +54,12 @@ extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_union_is_set_all(const MY_BITMAP *map1, extern my_bool bitmap_union_is_set_all(const MY_BITMAP *map1,
const MY_BITMAP *map2); const MY_BITMAP *map2);
extern my_bool bitmap_exists_intersection(const MY_BITMAP **bitmap_array, extern my_bool bitmap_exists_intersection(MY_BITMAP **bitmap_array,
uint bitmap_count, uint bitmap_count,
uint start_bit, uint end_bit); uint start_bit, uint end_bit);
extern uint bitmap_set_next(MY_BITMAP *map); extern uint bitmap_set_next(MY_BITMAP *map);
extern uint bitmap_get_first(const MY_BITMAP *map); extern uint bitmap_get_first_clear(const MY_BITMAP *map);
extern uint bitmap_get_first_set(const MY_BITMAP *map); extern uint bitmap_get_first_set(const MY_BITMAP *map);
extern uint bitmap_bits_set(const MY_BITMAP *map); extern uint bitmap_bits_set(const MY_BITMAP *map);
extern uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit); extern uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit);
@ -71,54 +72,70 @@ extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_invert(MY_BITMAP *map); extern void bitmap_invert(MY_BITMAP *map);
extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2);
/* Functions to export/import bitmaps to an architecture independent format */
extern void bitmap_export(uchar *to, MY_BITMAP *map);
extern void bitmap_import(MY_BITMAP *map, uchar *from);
#define my_bitmap_map_bytes sizeof(my_bitmap_map)
#define my_bitmap_map_bits (my_bitmap_map_bytes*8)
/* Size in bytes to store 'bits' number of bits */
#define bitmap_buffer_size(bits) (MY_ALIGN((bits), my_bitmap_map_bits)/8)
#define my_bitmap_buffer_size(map) bitmap_buffer_size((map)->n_bits)
#define no_bytes_in_export_map(map) (((map)->n_bits + 7)/8)
#define no_words_in_map(map) (((map)->n_bits + (my_bitmap_map_bits-1))/my_bitmap_map_bits)
/* Fast, not thread safe, bitmap functions */ /* Fast, not thread safe, bitmap functions */
#define bitmap_buffer_size(bits) (((bits)+31)/32)*4 /* The following functions must be compatible with create_last_bit_mask()! */
#define no_bytes_in_map(map) (((map)->n_bits + 7)/8)
#define no_words_in_map(map) (((map)->n_bits + 31)/32)
#define bytes_word_aligned(bytes) (4*((bytes + 3)/4))
/* The following functions must be compatible with create_last_word_mask()! */
static inline void static inline void
bitmap_set_bit(MY_BITMAP *map,uint bit) bitmap_set_bit(MY_BITMAP *map,uint bit)
{ {
uchar *b= (uchar*) map->bitmap + bit / 8;
DBUG_ASSERT(bit < map->n_bits); DBUG_ASSERT(bit < map->n_bits);
*b= (uchar) (*b | 1U << (bit & 7)); map->bitmap[bit/my_bitmap_map_bits]|=
(1ULL << (bit & (my_bitmap_map_bits-1)));
} }
static inline void static inline void
bitmap_flip_bit(MY_BITMAP *map,uint bit) bitmap_flip_bit(MY_BITMAP *map,uint bit)
{ {
uchar *b= (uchar*) map->bitmap + bit / 8;
DBUG_ASSERT(bit < map->n_bits); DBUG_ASSERT(bit < map->n_bits);
*b= (uchar) (*b ^ 1U << (bit & 7)); map->bitmap[bit/my_bitmap_map_bits]^=
(1ULL << (bit & (my_bitmap_map_bits-1)));
} }
static inline void static inline void
bitmap_clear_bit(MY_BITMAP *map,uint bit) bitmap_clear_bit(MY_BITMAP *map,uint bit)
{ {
uchar *b= (uchar*) map->bitmap + bit / 8;
DBUG_ASSERT(bit < map->n_bits); DBUG_ASSERT(bit < map->n_bits);
*b= (uchar) (*b & ~(1U << (bit & 7))); map->bitmap[bit/my_bitmap_map_bits]&=
~(1ULL << (bit & (my_bitmap_map_bits-1)));
} }
static inline uint static inline uint
bitmap_is_set(const MY_BITMAP *map,uint bit) bitmap_is_set(const MY_BITMAP *map,uint bit)
{ {
const uchar *b= (const uchar*) map->bitmap + bit / 8;
DBUG_ASSERT(bit < map->n_bits); DBUG_ASSERT(bit < map->n_bits);
return !!(*b & (1U << (bit & 7))); return (!!(map->bitmap[bit/my_bitmap_map_bits] &
(1ULL << (bit & (my_bitmap_map_bits-1)))));
} }
/* Return true if bitmaps are equal */
static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2) static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
{ {
if (memcmp(map1->bitmap, map2->bitmap, 4*(no_words_in_map(map1)-1)) != 0) DBUG_ASSERT(map1->n_bits == map2->n_bits);
return FALSE; return (memcmp(map1->bitmap, map2->bitmap,
return ((*map1->last_word_ptr | map1->last_word_mask) == my_bitmap_buffer_size(map1)) == 0);
(*map2->last_word_ptr | map2->last_word_mask));
} }
#define bitmap_clear_all(MAP) \ #define bitmap_clear_all(MAP) \
{ memset((MAP)->bitmap, 0, 4*no_words_in_map((MAP))); } { memset((MAP)->bitmap, 0, my_bitmap_buffer_size(MAP)); }
#define bitmap_set_all(MAP) \
(memset((MAP)->bitmap, 0xFF, 4*no_words_in_map((MAP)))) static inline void
bitmap_set_all(const MY_BITMAP *map)
{
if (map->n_bits)
{
memset(map->bitmap, 0xFF, my_bitmap_map_bytes * (no_words_in_map(map)-1));
DBUG_ASSERT(map->bitmap + no_words_in_map(map)-1 == map->last_word_ptr);
*map->last_word_ptr= ~map->last_bit_mask;
}
}
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -974,6 +974,7 @@ typedef struct st_mysql_lex_string LEX_STRING;
#define SOCKET_ECONNRESET WSAECONNRESET #define SOCKET_ECONNRESET WSAECONNRESET
#define SOCKET_ENFILE ENFILE #define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE #define SOCKET_EMFILE EMFILE
#define SOCKET_CLOSED EIO
#else /* Unix */ #else /* Unix */
#define socket_errno errno #define socket_errno errno
#define closesocket(A) close(A) #define closesocket(A) close(A)
@ -983,6 +984,7 @@ typedef struct st_mysql_lex_string LEX_STRING;
#define SOCKET_EADDRINUSE EADDRINUSE #define SOCKET_EADDRINUSE EADDRINUSE
#define SOCKET_ETIMEDOUT ETIMEDOUT #define SOCKET_ETIMEDOUT ETIMEDOUT
#define SOCKET_ECONNRESET ECONNRESET #define SOCKET_ECONNRESET ECONNRESET
#define SOCKET_CLOSED EIO
#define SOCKET_ENFILE ENFILE #define SOCKET_ENFILE ENFILE
#define SOCKET_EMFILE EMFILE #define SOCKET_EMFILE EMFILE
#endif #endif

View File

@ -457,6 +457,7 @@ typedef struct st_net {
my_bool thread_specific_malloc; my_bool thread_specific_malloc;
unsigned char compress; unsigned char compress;
my_bool pkt_nr_can_be_reset; my_bool pkt_nr_can_be_reset;
my_bool using_proxy_protocol;
/* /*
Pointer to query object in query cache, do not equal NULL (0) for Pointer to query object in query cache, do not equal NULL (0) for
queries in cache that have not stored its results yet queries in cache that have not stored its results yet

View File

@ -41,6 +41,13 @@ enum enum_vio_type
VIO_TYPE_SSL VIO_TYPE_SSL
/* see also vio_type_names[] */ /* see also vio_type_names[] */
}; };
enum enum_vio_state
{
VIO_STATE_NOT_INITIALIZED, VIO_STATE_ACTIVE, VIO_STATE_SHUTDOWN,
VIO_STATE_CLOSED
};
#define FIRST_VIO_TYPE VIO_CLOSED #define FIRST_VIO_TYPE VIO_CLOSED
#define LAST_VIO_TYPE VIO_TYPE_SSL #define LAST_VIO_TYPE VIO_TYPE_SSL
@ -244,6 +251,7 @@ struct st_vio
struct sockaddr_storage local; /* Local internet address */ struct sockaddr_storage local; /* Local internet address */
struct sockaddr_storage remote; /* Remote internet address */ struct sockaddr_storage remote; /* Remote internet address */
enum enum_vio_type type; /* Type of connection */ enum enum_vio_type type; /* Type of connection */
enum enum_vio_state state; /* State of the connection */
const char *desc; /* String description */ const char *desc; /* String description */
char *read_buffer; /* buffer for vio_read_buff */ char *read_buffer; /* buffer for vio_read_buff */
char *read_pos; /* start of unfetched data in the char *read_pos; /* start of unfetched data in the

View File

@ -23,6 +23,8 @@ void init_embedded_mysql(MYSQL *mysql, ulong client_flag);
void *create_embedded_thd(ulong client_flag); void *create_embedded_thd(ulong client_flag);
int check_embedded_connection(MYSQL *mysql, const char *db); int check_embedded_connection(MYSQL *mysql, const char *db);
void free_old_query(MYSQL *mysql); void free_old_query(MYSQL *mysql);
THD *embedded_get_current_thd();
void embedded_set_current_thd(THD *thd);
extern MYSQL_METHODS embedded_methods; extern MYSQL_METHODS embedded_methods;
/* This one is used by embedded library to gather returning data */ /* This one is used by embedded library to gather returning data */

View File

@ -111,7 +111,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
MYSQL_STMT *stmt) MYSQL_STMT *stmt)
{ {
my_bool result= 1; my_bool result= 1;
THD *thd=(THD *) mysql->thd; THD *thd=(THD *) mysql->thd, *old_current_thd= current_thd;
NET *net= &mysql->net; NET *net= &mysql->net;
my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE; my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
@ -122,6 +122,8 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
else else
{ {
free_embedded_thd(mysql); free_embedded_thd(mysql);
if (old_current_thd == thd)
old_current_thd= 0;
thd= 0; thd= 0;
} }
} }
@ -179,6 +181,8 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
end: end:
thd->reset_globals(); thd->reset_globals();
if (old_current_thd)
old_current_thd->store_globals();
return result; return result;
} }
@ -265,6 +269,7 @@ static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->server_status|= SERVER_STATUS_IN_TRANS;
stmt->fields= mysql->fields; stmt->fields= mysql->fields;
free_root(&stmt->mem_root, MYF(0));
stmt->mem_root= res->alloc; stmt->mem_root= res->alloc;
mysql->fields= NULL; mysql->fields= NULL;
my_free(res); my_free(res);
@ -374,6 +379,7 @@ int emb_read_binary_rows(MYSQL_STMT *stmt)
set_stmt_errmsg(stmt, &stmt->mysql->net); set_stmt_errmsg(stmt, &stmt->mysql->net);
return 1; return 1;
} }
free_root(&stmt->result.alloc, MYF(0));
stmt->result= *data; stmt->result= *data;
my_free(data); my_free(data);
set_stmt_errmsg(stmt, &stmt->mysql->net); set_stmt_errmsg(stmt, &stmt->mysql->net);
@ -432,12 +438,15 @@ int emb_unbuffered_fetch(MYSQL *mysql, char **row)
static void free_embedded_thd(MYSQL *mysql) static void free_embedded_thd(MYSQL *mysql)
{ {
THD *thd= (THD*)mysql->thd; THD *thd= (THD*)mysql->thd, *org_current_thd= current_thd;
server_threads.erase(thd); server_threads.erase(thd);
thd->clear_data_list(); thd->clear_data_list();
thd->store_globals(); thd->store_globals();
delete thd; delete thd;
if (thd == org_current_thd)
set_current_thd(nullptr); set_current_thd(nullptr);
else
set_current_thd(org_current_thd);
mysql->thd=0; mysql->thd=0;
} }
@ -727,6 +736,17 @@ void *create_embedded_thd(ulong client_flag)
} }
THD *embedded_get_current_thd()
{
return current_thd;
}
void embedded_set_current_thd(THD *thd)
{
set_current_thd(thd);
}
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
static void static void
emb_transfer_connect_attrs(MYSQL *mysql) emb_transfer_connect_attrs(MYSQL *mysql)

View File

@ -78,7 +78,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
uint port, const char *unix_socket,ulong client_flag) uint port, const char *unix_socket,ulong client_flag)
{ {
char name_buff[USERNAME_LENGTH]; char name_buff[USERNAME_LENGTH];
THD *org_current_thd= embedded_get_current_thd();
DBUG_ENTER("mysql_real_connect"); DBUG_ENTER("mysql_real_connect");
DBUG_PRINT("enter",("host: %s db: %s user: %s (libmysqld)", DBUG_PRINT("enter",("host: %s db: %s user: %s (libmysqld)",
host ? host : "(Null)", host ? host : "(Null)",
@ -200,6 +200,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
} }
} }
} }
embedded_set_current_thd(org_current_thd);
DBUG_PRINT("exit",("Mysql handler: %p", mysql)); DBUG_PRINT("exit",("Mysql handler: %p", mysql));
DBUG_RETURN(mysql); DBUG_RETURN(mysql);
@ -216,6 +217,7 @@ error:
mysql_close(mysql); mysql_close(mysql);
mysql->free_me=free_me; mysql->free_me=free_me;
} }
embedded_set_current_thd(org_current_thd);
DBUG_RETURN(0); DBUG_RETURN(0);
} }

View File

@ -0,0 +1,11 @@
#
# This file loads aria_log_control file into a user variable @aria_log_control.
# Set $ARIA_DATADIR before including this file
#
--disable_query_log
--copy_file $ARIA_DATADIR/aria_log_control $MYSQLTEST_VARDIR/aria_log_control_tmp
--chmod 0777 $MYSQLTEST_VARDIR/aria_log_control_tmp
--eval SET @aria_log_control=(SELECT LOAD_FILE('$MYSQLTEST_VARDIR/aria_log_control_tmp'))
--remove_file $MYSQLTEST_VARDIR/aria_log_control_tmp
--enable_query_log

View File

@ -32,7 +32,6 @@ if ($tmp)
--echo Relay_Master_Log_File # --echo Relay_Master_Log_File #
--echo Slave_IO_Running No --echo Slave_IO_Running No
--echo Slave_SQL_Running No --echo Slave_SQL_Running No
--echo Replicate_Rewrite_DB #
--echo Replicate_Do_DB # --echo Replicate_Do_DB #
--echo Replicate_Ignore_DB # --echo Replicate_Ignore_DB #
--echo Replicate_Do_Table # --echo Replicate_Do_Table #
@ -74,13 +73,22 @@ if ($tmp)
--echo Slave_DDL_Groups # --echo Slave_DDL_Groups #
--echo Slave_Non_Transactional_Groups # --echo Slave_Non_Transactional_Groups #
--echo Slave_Transactional_Groups # --echo Slave_Transactional_Groups #
--echo Replicate_Rewrite_DB #
} }
if (!$tmp) { if (!$tmp) {
# Note: after WL#5177, fields 13-18 shall not be filtered-out. # Note: after WL#5177, fields 13-18 shall not be filtered-out.
--replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 19 # 23 # 24 # 25 # 26 # 27 # 41 # 42 # 43 # 45 # 52 # 53 # 54 # --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 22 # 23 # 24 # 25 # 26 # 40 # 41 # 42 # 44 # 51 # 52 # 53 # 54 #
query_vertical query_vertical
SHOW SLAVE STATUS; SHOW SLAVE STATUS;
} }
#
# Note, we must never, _ever_, add extra rows to this output of SHOW SLAVE
# STATUS, except at the very end, as this breaks backwards compatibility
# with applications or scripts that parse the output. This also means that
# we cannot add _any_ new rows in a GA version if a different row was
# already added in a later MariaDB version, as this would make it impossible
# to merge the change up while preserving the order of rows.
#
# #
# Ensure that we don't get warnings from mysql.proc (used by check_mysqld) # Ensure that we don't get warnings from mysql.proc (used by check_mysqld)

View File

@ -103,7 +103,6 @@ connection con2;
# The following query should hang because con1 is locking the record # The following query should hang because con1 is locking the record
update t2 set a=2 where b = 0; update t2 set a=2 where b = 0;
select * from t2;
--send --send
update t1 set x=2 where id = 0; update t1 set x=2 where id = 0;
--sleep 2 --sleep 2

View File

@ -22,7 +22,6 @@ select * from t1;
connection con1; connection con1;
begin work; begin work;
insert into t1 values (5); insert into t1 values (5);
select * from t1;
# Lock wait timeout set to 2 seconds in <THIS TEST>-master.opt; this # Lock wait timeout set to 2 seconds in <THIS TEST>-master.opt; this
# statement will time out; in 5.0.13+, it will not roll back transaction. # statement will time out; in 5.0.13+, it will not roll back transaction.
--error ER_LOCK_WAIT_TIMEOUT --error ER_LOCK_WAIT_TIMEOUT

View File

@ -9,9 +9,6 @@
# #
# The environment variables SEARCH_FILE and SEARCH_PATTERN must be set # The environment variables SEARCH_FILE and SEARCH_PATTERN must be set
# before sourcing this routine. # before sourcing this routine.
# SEARCH_TYPE can also be set to either NULL(default) or _gm_
# NULL is equivalent of using m/SEARCH_PATTERN/gs
# _gm_ is equivalent of using m/SEARCH_RANGE/gm
# #
# Optionally, SEARCH_RANGE can be set to the max number of bytes of the file # Optionally, SEARCH_RANGE can be set to the max number of bytes of the file
# to search. If negative, it will search that many bytes at the end of the # to search. If negative, it will search that many bytes at the end of the
@ -25,6 +22,7 @@
# Supported formats: # Supported formats:
# - (default) : "FOUND n /pattern/ in FILE " or "NOT FOUND ..." # - (default) : "FOUND n /pattern/ in FILE " or "NOT FOUND ..."
# - "matches" : Each match is printed, on a separate line # - "matches" : Each match is printed, on a separate line
# - "count" : "FOUND n matches in FILE" or "NOT FOUND ..." (omit pattern)
# #
# In case of # In case of
# - SEARCH_FILE and/or SEARCH_PATTERN is not set # - SEARCH_FILE and/or SEARCH_PATTERN is not set
@ -51,15 +49,12 @@
# Created: 2011-11-11 mleich # Created: 2011-11-11 mleich
# #
--error 0,1
perl; perl;
use strict; use strict;
die "SEARCH_FILE not set" unless $ENV{SEARCH_FILE}; die "SEARCH_FILE not set" unless $ENV{SEARCH_FILE};
my @search_files= glob($ENV{SEARCH_FILE}); my @search_files= glob($ENV{SEARCH_FILE});
my $search_pattern= $ENV{SEARCH_PATTERN} or die "SEARCH_PATTERN not set"; my $search_pattern= $ENV{SEARCH_PATTERN} or die "SEARCH_PATTERN not set";
my $search_range= $ENV{SEARCH_RANGE}; my $search_range= $ENV{SEARCH_RANGE};
my $silent= $ENV{SEARCH_SILENT};
my $search_result= 0;
my $content; my $content;
foreach my $search_file (@search_files) { foreach my $search_file (@search_files) {
open(FILE, '<', $search_file) || die("Can't open file $search_file: $!"); open(FILE, '<', $search_file) || die("Can't open file $search_file: $!");
@ -83,48 +78,23 @@ perl;
close(FILE); close(FILE);
$content.= $file_content; $content.= $file_content;
} }
my @matches; my @matches= ($content =~ /$search_pattern/gs);
if (not defined($ENV{SEARCH_TYPE})) my $res=@matches ? "FOUND " . scalar(@matches) : "NOT FOUND";
{
@matches=($content =~ /$search_pattern/gs);
}
elsif($ENV{SEARCH_TYPE} == "_gm_")
{
@matches=($content =~ /$search_pattern/gm);
}
my $res;
if (@matches)
{
$res="FOUND " . scalar(@matches);
$search_result= 1;
}
else
{
$res= "NOT FOUND";
}
$ENV{SEARCH_FILE} =~ s{^.*?([^/\\]+)$}{$1}; $ENV{SEARCH_FILE} =~ s{^.*?([^/\\]+)$}{$1};
if (!$silent || $search_result) if ($ENV{SEARCH_OUTPUT} eq "matches") {
{ foreach (@matches) {
if ($ENV{SEARCH_OUTPUT} eq "matches")
{
foreach (@matches)
{
print $_ . "\n"; print $_ . "\n";
} }
} }
else elsif ($ENV{SEARCH_OUTPUT} eq "count")
{ {
print "$res matches in $ENV{SEARCH_FILE}\n";
}
elsif ($ENV{SEARCH_ABORT} and $res =~ /^$ENV{SEARCH_ABORT}/) {
die "$res /$search_pattern/ in $ENV{SEARCH_FILE}\n";
} else {
print "$res /$search_pattern/ in $ENV{SEARCH_FILE}\n"; print "$res /$search_pattern/ in $ENV{SEARCH_FILE}\n";
} }
}
die "$ENV{SEARCH_ABORT}\n"
if $ENV{SEARCH_ABORT} && $res =~ /^$ENV{SEARCH_ABORT}/;
exit($search_result != 1);
EOF EOF
let $SEARCH_RESULT= 1; # Found pattern
if ($errno)
{
let $SEARCH_RESULT= 0; # Did not find pattern
}

View File

@ -25,23 +25,23 @@ if (!$_timeout)
} }
let $_timeout_counter=`SELECT $_timeout * 10`; let $_timeout_counter=`SELECT $_timeout * 10`;
let SEARCH_SILENT=1; let SEARCH_ABORT=NOT FOUND;
let $_continue= 1; let $_continue= 1;
disable_abort_on_error;
while ($_continue) while ($_continue)
{ {
source include/search_pattern_in_file.inc; source include/search_pattern_in_file.inc;
if ($SEARCH_RESULT) if (!$errno)
{ {
# Found match # Found match
let $_continue= 0; let $_continue= 0;
} }
if (!$SEARCH_RESULT) if ($errno)
{ {
dec $_timeout_counter; dec $_timeout_counter;
if ($_timeout_counter == 1) if ($_timeout_counter == 1)
{ {
let $SEARCH_SILENT= 0; enable_abort_on_error;
} }
if (!$_timeout_counter) if (!$_timeout_counter)
{ {
@ -49,8 +49,7 @@ while ($_continue)
} }
} }
} }
enable_abort_on_error;
let SEARCH_SILENT=0;
--source include/end_include_file.inc --source include/end_include_file.inc
--let $keep_include_silent=$wait_save_keep_include_silent --let $keep_include_silent=$wait_save_keep_include_silent

View File

@ -11,7 +11,7 @@ let $counter= 5000;
let $mysql_errno= 9999; let $mysql_errno= 9999;
while ($mysql_errno) while ($mysql_errno)
{ {
--error 0,ER_ACCESS_DENIED_ERROR,ER_SERVER_SHUTDOWN,ER_CONNECTION_KILLED,ER_LOCK_WAIT_TIMEOUT,2002,2006,2013,HA_ERR_NO_ENCRYPTION --error 0,ER_ACCESS_DENIED_ERROR,ER_SERVER_SHUTDOWN,ER_CONNECTION_KILLED,ER_LOCK_WAIT_TIMEOUT,2002,2006,2013,HA_ERR_NO_ENCRYPTION,2026
select 1; select 1;
dec $counter; dec $counter;

View File

@ -3102,6 +3102,14 @@ CREATE TEMPORARY TABLE t2 LIKE t1;
DROP TEMPORARY TABLE t2; DROP TEMPORARY TABLE t2;
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-33313 Incorrect error message for "ALTER TABLE ... DROP CONSTRAINT ..., DROP col, DROP col"
#
create table t2(id int primary key) engine=innodb;
create table t1(id int primary key, t2_id int, constraint t1_fk_t2_id foreign key(t2_id) references t2(id)) engine=innodb;
alter table t1 drop constraint t1_fk_t2_id, drop t2_id, drop t2_id;
ERROR 42000: Can't DROP COLUMN `t2_id`; check that it exists
drop table t1, t2;
#
# End of 10.6 tests # End of 10.6 tests
# #
# #

View File

@ -2392,6 +2392,15 @@ CREATE TEMPORARY TABLE t2 LIKE t1;
DROP TEMPORARY TABLE t2; DROP TEMPORARY TABLE t2;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-33313 Incorrect error message for "ALTER TABLE ... DROP CONSTRAINT ..., DROP col, DROP col"
--echo #
create table t2(id int primary key) engine=innodb;
create table t1(id int primary key, t2_id int, constraint t1_fk_t2_id foreign key(t2_id) references t2(id)) engine=innodb;
--error ER_CANT_DROP_FIELD_OR_KEY
alter table t1 drop constraint t1_fk_t2_id, drop t2_id, drop t2_id;
drop table t1, t2;
--echo # --echo #
--echo # End of 10.6 tests --echo # End of 10.6 tests
--echo # --echo #

View File

@ -74,7 +74,7 @@ SELECT 'bug' as '' FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
--echo # MDEV-13063 Server crashes in intern_plugin_lock or assertion `plugin_ptr->ref_count == 1' fails in plugin_init --echo # MDEV-13063 Server crashes in intern_plugin_lock or assertion `plugin_ptr->ref_count == 1' fails in plugin_init
--echo # --echo #
--error 1 --error 1
--exec $MYSQLD_BOOTSTRAP_CMD --myisam_recover_options=NONE --exec $MYSQLD_BOOTSTRAP_CMD --myisam_recover_options=NONE 2>/dev/null
--echo # --echo #
--echo # MDEV-19349 mysql_install_db: segfault at tmp_file_prefix check --echo # MDEV-19349 mysql_install_db: segfault at tmp_file_prefix check

View File

@ -780,3 +780,27 @@ string
# #
# End of 10.2 tests # End of 10.2 tests
# #
#
# MDEV-33318 ORDER BY COLLATE improperly applied to non-character columns
#
set names utf8;
create table t1 (ts datetime);
insert t1 values ('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'),
('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'),
('2024-01-26 21:37:58'), ('2024-01-26 21:37:58'),
('2024-01-26 21:37:58'), ('2024-01-26 21:38:02'),
('2024-01-26 21:38:02'), ('2024-01-26 21:38:02');
select * from t1 order by ts collate utf8_bin;
ts
2024-01-26 21:37:54
2024-01-26 21:37:54
2024-01-26 21:37:54
2024-01-26 21:37:54
2024-01-26 21:37:58
2024-01-26 21:37:58
2024-01-26 21:37:58
2024-01-26 21:38:02
2024-01-26 21:38:02
2024-01-26 21:38:02
drop table t1;
# End of 10.6 tests

View File

@ -357,3 +357,18 @@ SELECT COLUMN_GET(COLUMN_CREATE(0, 'string'),0 AS CHAR CHARACTER SET latin1 COLL
--echo # --echo #
--echo # End of 10.2 tests --echo # End of 10.2 tests
--echo # --echo #
--echo #
--echo # MDEV-33318 ORDER BY COLLATE improperly applied to non-character columns
--echo #
set names utf8;
create table t1 (ts datetime);
insert t1 values ('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'),
('2024-01-26 21:37:54'), ('2024-01-26 21:37:54'),
('2024-01-26 21:37:58'), ('2024-01-26 21:37:58'),
('2024-01-26 21:37:58'), ('2024-01-26 21:38:02'),
('2024-01-26 21:38:02'), ('2024-01-26 21:38:02');
select * from t1 order by ts collate utf8_bin;
drop table t1;
--echo # End of 10.6 tests

View File

@ -6517,5 +6517,25 @@ SELECT 1 COLLATE latin1_swedish_ci;
ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'ucs2' ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'ucs2'
SET NAMES utf8; SET NAMES utf8;
# #
# MDEV-33772 Bad SEPARATOR value in GROUP_CONCAT on character set conversion
#
SET NAMES utf8mb3, @@collation_connection=ucs2_general_ci;
CREATE TABLE t1 (c VARCHAR(10)) CHARACTER SET ucs2;
INSERT INTO t1 VALUES ('a'),('A');
CREATE OR REPLACE VIEW v1 AS
SELECT COUNT(*) AS cnt, GROUP_CONCAT(c) AS c1 FROM t1 GROUP BY c;
SELECT * FROM v1;
cnt c1
2 a,A
SELECT HEX(c1) FROM v1;
HEX(c1)
0061002C0041
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select count(0) AS `cnt`,group_concat(`t1`.`c` separator ',') AS `c1` from `t1` group by `t1`.`c` utf8mb3 ucs2_general_ci
DROP VIEW v1;
DROP TABLE t1;
SET NAMES utf8mb3;
#
# End of 10.5 tests # End of 10.5 tests
# #

View File

@ -1193,6 +1193,23 @@ SELECT HEX(1 COLLATE ucs2_bin);
SELECT 1 COLLATE latin1_swedish_ci; SELECT 1 COLLATE latin1_swedish_ci;
SET NAMES utf8; SET NAMES utf8;
--echo #
--echo # MDEV-33772 Bad SEPARATOR value in GROUP_CONCAT on character set conversion
--echo #
SET NAMES utf8mb3, @@collation_connection=ucs2_general_ci;
CREATE TABLE t1 (c VARCHAR(10)) CHARACTER SET ucs2;
INSERT INTO t1 VALUES ('a'),('A');
CREATE OR REPLACE VIEW v1 AS
SELECT COUNT(*) AS cnt, GROUP_CONCAT(c) AS c1 FROM t1 GROUP BY c;
SELECT * FROM v1;
SELECT HEX(c1) FROM v1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP TABLE t1;
SET NAMES utf8mb3;
--echo # --echo #
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #

View File

@ -89,11 +89,6 @@ id x
300 300 300 300
connection con2; connection con2;
update t2 set a=2 where b = 0; update t2 set a=2 where b = 0;
select * from t2;
b a
0 2
1 20
2 30
update t1 set x=2 where id = 0; update t1 set x=2 where id = 0;
connection con1; connection con1;
update t1 set x=1 where id = 0; update t1 set x=1 where id = 0;

View File

@ -4390,6 +4390,38 @@ dim1 dim2 dim3 p SUM(p)
DROP VIEW v; DROP VIEW v;
# End of 10.4 tests # End of 10.4 tests
# #
# MDEV-31277: 2-nd execution of PS to select from materialized view
# specified as left join whose inner table is mergeable
# derived containing a constant column
#
create table t1 (
Election int(10) unsigned NOT NULL
) engine=MyISAM;
insert into t1 (Election) values (1), (4);
create table t2 (
VoteID int(10),
ElectionID int(10),
UserID int(10)
);
insert into t2 (ElectionID, UserID) values (2, 30), (3, 30);
create view v1 as select * from t1
left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T
on T.ElectionID = t1.Election
limit 9;
prepare stmt1 from "select * from v1";
execute stmt1;
Election Voted ElectionID
1 NULL NULL
4 NULL NULL
execute stmt1;
Election Voted ElectionID
1 NULL NULL
4 NULL NULL
deallocate prepare stmt1;
drop view v1;
drop table t1, t2;
# End of 10.5 tests
#
# MDEV-31143: view with ORDER BY used in query with rownum() in WHERE # MDEV-31143: view with ORDER BY used in query with rownum() in WHERE
# #
create table t1 (id int primary key); create table t1 (id int primary key);

View File

@ -2841,6 +2841,42 @@ DROP VIEW v;
--echo # End of 10.4 tests --echo # End of 10.4 tests
--echo #
--echo # MDEV-31277: 2-nd execution of PS to select from materialized view
--echo # specified as left join whose inner table is mergeable
--echo # derived containing a constant column
--echo #
create table t1 (
Election int(10) unsigned NOT NULL
) engine=MyISAM;
insert into t1 (Election) values (1), (4);
create table t2 (
VoteID int(10),
ElectionID int(10),
UserID int(10)
);
insert into t2 (ElectionID, UserID) values (2, 30), (3, 30);
create view v1 as select * from t1
left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T
on T.ElectionID = t1.Election
limit 9;
prepare stmt1 from "select * from v1";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
drop view v1;
drop table t1, t2;
--echo # End of 10.5 tests
--echo # --echo #
--echo # MDEV-31143: view with ORDER BY used in query with rownum() in WHERE --echo # MDEV-31143: view with ORDER BY used in query with rownum() in WHERE
--echo # --echo #

View File

@ -64,7 +64,7 @@ SET sql_mode=@mode;
# Test litteral concat # Test litteral concat
# #
SELECT 'a' 'b'; SELECT 'a' 'b';
a ab
ab ab
SELECT 'a' ''; SELECT 'a' '';
a a
@ -76,13 +76,13 @@ SELECT '' '';
NULL NULL
NULL NULL
SELECT '' 'b' 'c'; SELECT '' 'b' 'c';
b bc
bc bc
SELECT '' '' 'c'; SELECT '' '' 'c';
c c
c c
SELECT 'a' '' 'c'; SELECT 'a' '' 'c';
a ac
ac ac
SELECT 'a' '' ''; SELECT 'a' '' '';
a a
@ -208,3 +208,22 @@ t1 CREATE TABLE `t1` (
KEY `a` (`a`,`b`) KEY `a` (`a`,`b`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
drop table t1; drop table t1;
#
# MDEV-33460 select '123' 'x'; unexpected result
#
SELECT '';
NULL
NULL
SELECT '' 'b' 'c';
bc
bc
SELECT '' '' 'c';
c
c
SELECT 'a' '' 'c';
ac
ac
SELECT 'a' '' '';
a
a
# End of 10.5 test

View File

@ -25,3 +25,15 @@ flush tables;
update t1 set a = 2; update t1 set a = 2;
show create table t1; show create table t1;
drop table t1; drop table t1;
--echo #
--echo # MDEV-33460 select '123' 'x'; unexpected result
--echo #
SELECT '';
SELECT '' 'b' 'c';
SELECT '' '' 'c';
SELECT 'a' '' 'c';
SELECT 'a' '' '';
--echo # End of 10.5 test

View File

@ -590,3 +590,885 @@ Warning 1292 Truncated incorrect time value: '01:02:03/'
Warning 1292 Truncated incorrect time value: '01:02:03/' Warning 1292 Truncated incorrect time value: '01:02:03/'
Warning 1292 Truncated incorrect INTERVAL DAY TO SECOND value: '01:02:03/' Warning 1292 Truncated incorrect INTERVAL DAY TO SECOND value: '01:02:03/'
DROP TABLE t1; DROP TABLE t1;
#
# Start of 10.5 tests
#
#
# MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type
#
CREATE FUNCTION select01() RETURNS TEXT RETURN 'SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?';
CREATE FUNCTION select02() RETURNS TEXT RETURN 'SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)';
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('2001-12-31 10:20:30.999999');
CREATE FUNCTION params(expr TEXT, count INT) RETURNS TEXT
BEGIN
RETURN CONCAT(expr, REPEAT(CONCAT(', ', expr), count-1));
END;
$$
CREATE PROCEDURE show_drop()
BEGIN
SELECT TABLE_NAME, COLUMN_TYPE, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm',
't1e_ps','t1f_ps','t2e_ps','t2f_ps')
ORDER BY LEFT(TABLE_NAME, 2), ORDINAL_POSITION, TABLE_NAME;
FOR rec IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm',
't1e_ps','t1f_ps','t2e_ps','t2f_ps'))
DO
EXECUTE IMMEDIATE CONCAT('DROP TABLE ', rec.TABLE_NAME);
END FOR;
END;
$$
CREATE PROCEDURE p1(unit VARCHAR(32))
BEGIN
DECLARE do_extract BOOL DEFAULT unit NOT IN('DAYOFYEAR');
DECLARE query01 TEXT DEFAULT
CONCAT('CREATE TABLE t2 AS ', select01(), ' FROM t1');
DECLARE query02 TEXT DEFAULT
CONCAT('CREATE TABLE t2 AS ', select02(), ' FROM t1');
IF (do_extract)
THEN
EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)'));
EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)'));
END IF;
EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1f_nm'),'?', CONCAT(unit,'(a)'));
EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2f_nm'),'?', CONCAT(unit,'(a)'));
END;
$$
# EXTRACT(YEAR FROM expr) and YEAR(expr) are equivalent
CALL p1('YEAR');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(5) EXTRACT(YEAR FROM a)
t1e_ps int(5) ?
t1f_nm int(5) YEAR(a)
t1f_ps int(5) ?
t1e_nm int(4) unsigned CAST(EXTRACT(YEAR FROM a) AS UNSIGNED)
t1e_ps int(4) unsigned CAST(? AS UNSIGNED)
t1f_nm int(4) unsigned CAST(YEAR(a) AS UNSIGNED)
t1f_ps int(4) unsigned CAST(? AS UNSIGNED)
t1e_nm int(5) CAST(EXTRACT(YEAR FROM a) AS SIGNED)
t1e_ps int(5) CAST(? AS SIGNED)
t1f_nm int(5) CAST(YEAR(a) AS SIGNED)
t1f_ps int(5) CAST(? AS SIGNED)
t1e_nm int(5) ABS(EXTRACT(YEAR FROM a))
t1e_ps int(5) ABS(?)
t1f_nm int(5) ABS(YEAR(a))
t1f_ps int(5) ABS(?)
t1e_nm int(5) ROUND(EXTRACT(YEAR FROM a))
t1e_ps int(5) ROUND(?)
t1f_nm int(5) ROUND(YEAR(a))
t1f_ps int(5) ROUND(?)
t1e_nm int(5) -EXTRACT(YEAR FROM a)
t1e_ps int(5) -?
t1f_nm int(5) -YEAR(a)
t1f_ps int(5) -?
t1e_nm int(6) ROUND(EXTRACT(YEAR FROM a),-1)
t1e_ps int(6) ROUND(?,-1)
t1f_nm int(6) ROUND(YEAR(a),-1)
t1f_ps int(6) ROUND(?,-1)
t1e_nm int(6) EXTRACT(YEAR FROM a)+0
t1e_ps int(6) ?+0
t1f_nm int(6) YEAR(a)+0
t1f_ps int(6) ?+0
t1e_nm decimal(6,1) EXTRACT(YEAR FROM a)+0.0
t1e_ps decimal(6,1) ?+0.0
t1f_nm decimal(6,1) YEAR(a)+0.0
t1f_ps decimal(6,1) ?+0.0
t1e_nm varchar(4) CONCAT(EXTRACT(YEAR FROM a))
t1e_ps varchar(4) CONCAT(?)
t1f_nm varchar(4) CONCAT(YEAR(a))
t1f_ps varchar(4) CONCAT(?)
t1e_nm int(5) LEAST(EXTRACT(YEAR FROM a),EXTRACT(YEAR FROM a))
t1e_ps int(5) LEAST(?,?)
t1f_nm int(5) LEAST(YEAR(a),YEAR(a))
t1f_ps int(5) LEAST(?,?)
t1e_nm int(5) COALESCE(EXTRACT(YEAR FROM a))
t1e_ps int(5) COALESCE(?)
t1f_nm int(5) COALESCE(YEAR(a))
t1f_ps int(5) COALESCE(?)
t1e_nm int(5) COALESCE(EXTRACT(YEAR FROM a),CAST(1 AS SIGNED))
t1e_ps int(5) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(5) COALESCE(YEAR(a),CAST(1 AS SIGNED))
t1f_ps int(5) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(4,0) COALESCE(EXTRACT(YEAR FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(4,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(4,0) COALESCE(YEAR(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(4,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(5) @a:=EXTRACT(YEAR FROM a)
t1e_ps int(5) @a:=?
t1f_nm int(5) @a:=YEAR(a)
t1f_ps int(5) @a:=?
t2e_nm decimal(8,4) AVG(EXTRACT(YEAR FROM a))
t2e_ps decimal(8,4) AVG(?)
t2f_nm decimal(8,4) AVG(YEAR(a))
t2f_ps decimal(8,4) AVG(?)
t2e_nm bigint(5) MIN(EXTRACT(YEAR FROM a))
t2e_ps bigint(5) MIN(?)
t2f_nm bigint(5) MIN(YEAR(a))
t2f_ps bigint(5) MIN(?)
t2e_nm bigint(5) MAX(EXTRACT(YEAR FROM a))
t2e_ps bigint(5) MAX(?)
t2f_nm bigint(5) MAX(YEAR(a))
t2f_ps bigint(5) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(YEAR FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(YEAR(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(QUARTER FROM expr) and QUARTER(expr) are equavalent
CALL p1('QUARTER');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(2) EXTRACT(QUARTER FROM a)
t1e_ps int(2) ?
t1f_nm int(2) QUARTER(a)
t1f_ps int(2) ?
t1e_nm int(1) unsigned CAST(EXTRACT(QUARTER FROM a) AS UNSIGNED)
t1e_ps int(1) unsigned CAST(? AS UNSIGNED)
t1f_nm int(1) unsigned CAST(QUARTER(a) AS UNSIGNED)
t1f_ps int(1) unsigned CAST(? AS UNSIGNED)
t1e_nm int(2) CAST(EXTRACT(QUARTER FROM a) AS SIGNED)
t1e_ps int(2) CAST(? AS SIGNED)
t1f_nm int(2) CAST(QUARTER(a) AS SIGNED)
t1f_ps int(2) CAST(? AS SIGNED)
t1e_nm int(2) ABS(EXTRACT(QUARTER FROM a))
t1e_ps int(2) ABS(?)
t1f_nm int(2) ABS(QUARTER(a))
t1f_ps int(2) ABS(?)
t1e_nm int(2) ROUND(EXTRACT(QUARTER FROM a))
t1e_ps int(2) ROUND(?)
t1f_nm int(2) ROUND(QUARTER(a))
t1f_ps int(2) ROUND(?)
t1e_nm int(2) -EXTRACT(QUARTER FROM a)
t1e_ps int(2) -?
t1f_nm int(2) -QUARTER(a)
t1f_ps int(2) -?
t1e_nm int(3) ROUND(EXTRACT(QUARTER FROM a),-1)
t1e_ps int(3) ROUND(?,-1)
t1f_nm int(3) ROUND(QUARTER(a),-1)
t1f_ps int(3) ROUND(?,-1)
t1e_nm int(3) EXTRACT(QUARTER FROM a)+0
t1e_ps int(3) ?+0
t1f_nm int(3) QUARTER(a)+0
t1f_ps int(3) ?+0
t1e_nm decimal(3,1) EXTRACT(QUARTER FROM a)+0.0
t1e_ps decimal(3,1) ?+0.0
t1f_nm decimal(3,1) QUARTER(a)+0.0
t1f_ps decimal(3,1) ?+0.0
t1e_nm varchar(1) CONCAT(EXTRACT(QUARTER FROM a))
t1e_ps varchar(1) CONCAT(?)
t1f_nm varchar(1) CONCAT(QUARTER(a))
t1f_ps varchar(1) CONCAT(?)
t1e_nm int(2) LEAST(EXTRACT(QUARTER FROM a),EXTRACT(QUARTER FROM a))
t1e_ps int(2) LEAST(?,?)
t1f_nm int(2) LEAST(QUARTER(a),QUARTER(a))
t1f_ps int(2) LEAST(?,?)
t1e_nm int(2) COALESCE(EXTRACT(QUARTER FROM a))
t1e_ps int(2) COALESCE(?)
t1f_nm int(2) COALESCE(QUARTER(a))
t1f_ps int(2) COALESCE(?)
t1e_nm int(2) COALESCE(EXTRACT(QUARTER FROM a),CAST(1 AS SIGNED))
t1e_ps int(2) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(2) COALESCE(QUARTER(a),CAST(1 AS SIGNED))
t1f_ps int(2) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(1,0) COALESCE(EXTRACT(QUARTER FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(1,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(1,0) COALESCE(QUARTER(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(1,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(2) @a:=EXTRACT(QUARTER FROM a)
t1e_ps int(2) @a:=?
t1f_nm int(2) @a:=QUARTER(a)
t1f_ps int(2) @a:=?
t2e_nm decimal(5,4) AVG(EXTRACT(QUARTER FROM a))
t2e_ps decimal(5,4) AVG(?)
t2f_nm decimal(5,4) AVG(QUARTER(a))
t2f_ps decimal(5,4) AVG(?)
t2e_nm bigint(2) MIN(EXTRACT(QUARTER FROM a))
t2e_ps bigint(2) MIN(?)
t2f_nm bigint(2) MIN(QUARTER(a))
t2f_ps bigint(2) MIN(?)
t2e_nm bigint(2) MAX(EXTRACT(QUARTER FROM a))
t2e_ps bigint(2) MAX(?)
t2f_nm bigint(2) MAX(QUARTER(a))
t2f_ps bigint(2) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(QUARTER FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(QUARTER(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(MONTH FROM expr) and MONTH(expr) are equavalent
CALL p1('MONTH');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(MONTH FROM a)
t1e_ps int(3) ?
t1f_nm int(3) MONTH(a)
t1f_ps int(3) ?
t1e_nm int(2) unsigned CAST(EXTRACT(MONTH FROM a) AS UNSIGNED)
t1e_ps int(2) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(MONTH(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(MONTH FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(MONTH(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(MONTH FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(MONTH(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(MONTH FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(MONTH(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(3) -EXTRACT(MONTH FROM a)
t1e_ps int(3) -?
t1f_nm int(3) -MONTH(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(MONTH FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(MONTH(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(MONTH FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) MONTH(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(MONTH FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) MONTH(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(2) CONCAT(EXTRACT(MONTH FROM a))
t1e_ps varchar(2) CONCAT(?)
t1f_nm varchar(2) CONCAT(MONTH(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(MONTH FROM a),EXTRACT(MONTH FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(MONTH(a),MONTH(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(MONTH FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(MONTH(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(MONTH FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(MONTH(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(MONTH FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(MONTH(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(MONTH FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=MONTH(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(MONTH FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(MONTH(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(MONTH FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(MONTH(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(MONTH FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(MONTH(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MONTH FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(MONTH(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(WEEK FROM expr) and WEEK(expr) are equavalent
CALL p1('WEEK');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(WEEK FROM a)
t1e_ps int(3) ?
t1f_nm int(3) WEEK(a)
t1f_ps int(3) ?
t1e_nm int(2) unsigned CAST(EXTRACT(WEEK FROM a) AS UNSIGNED)
t1e_ps int(2) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(WEEK(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(WEEK FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(WEEK(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(WEEK FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(WEEK(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(WEEK FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(WEEK(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(3) -EXTRACT(WEEK FROM a)
t1e_ps int(3) -?
t1f_nm int(3) -WEEK(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(WEEK FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(WEEK(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(WEEK FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) WEEK(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(WEEK FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) WEEK(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(2) CONCAT(EXTRACT(WEEK FROM a))
t1e_ps varchar(2) CONCAT(?)
t1f_nm varchar(2) CONCAT(WEEK(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(WEEK FROM a),EXTRACT(WEEK FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(WEEK(a),WEEK(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(WEEK FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(WEEK(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(WEEK FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(WEEK(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(WEEK FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(WEEK(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(WEEK FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=WEEK(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(WEEK FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(WEEK(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(WEEK FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(WEEK(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(WEEK FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(WEEK(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(WEEK FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(WEEK(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(DAY FROM expr) returns hours/24 and includes the sign for TIME
# DAY(expr) returns the DD part of CAST(expr AS DATETIME)
CALL p1('DAY');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(DAY FROM a)
t1e_ps int(3) ?
t1f_nm int(3) DAY(a)
t1f_ps int(3) ?
t1e_nm bigint(20) unsigned CAST(EXTRACT(DAY FROM a) AS UNSIGNED)
t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(DAY(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(DAY FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(DAY(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(DAY FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(DAY(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(DAY FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(DAY(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(4) -EXTRACT(DAY FROM a)
t1e_ps int(4) -?
t1f_nm int(3) -DAY(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(DAY FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(DAY(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(DAY FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) DAY(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(DAY FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) DAY(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(3) CONCAT(EXTRACT(DAY FROM a))
t1e_ps varchar(3) CONCAT(?)
t1f_nm varchar(2) CONCAT(DAY(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(DAY FROM a),EXTRACT(DAY FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(DAY(a),DAY(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(DAY FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(DAY(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(DAY FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(DAY(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(DAY FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(DAY(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(DAY FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=DAY(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(DAY FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(DAY(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(DAY FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(DAY(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(DAY FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(DAY(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(DAY FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(DAY(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(HOUR FROM expr) returns hours%24 and includes the sign for TIME
# HOUR(expr) returns the hh part of CAST(expr AS DATETIME)
CALL p1('HOUR');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(HOUR FROM a)
t1e_ps int(3) ?
t1f_nm int(3) HOUR(a)
t1f_ps int(3) ?
t1e_nm bigint(20) unsigned CAST(EXTRACT(HOUR FROM a) AS UNSIGNED)
t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(HOUR(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(HOUR FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(HOUR(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(HOUR FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(HOUR(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(HOUR FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(HOUR(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(4) -EXTRACT(HOUR FROM a)
t1e_ps int(4) -?
t1f_nm int(3) -HOUR(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(HOUR FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(HOUR(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(HOUR FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) HOUR(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(HOUR FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) HOUR(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(3) CONCAT(EXTRACT(HOUR FROM a))
t1e_ps varchar(3) CONCAT(?)
t1f_nm varchar(2) CONCAT(HOUR(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(HOUR FROM a),EXTRACT(HOUR FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(HOUR(a),HOUR(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(HOUR FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(HOUR(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(HOUR FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(HOUR(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(HOUR FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(HOUR(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(HOUR FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=HOUR(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(HOUR FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(HOUR(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(HOUR FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(HOUR(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(HOUR FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(HOUR(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(HOUR FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(HOUR(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(MINUTE FROM expr) includes the sign for TIME
# MINUTE(expr) returns the absolute value
CALL p1('MINUTE');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(MINUTE FROM a)
t1e_ps int(3) ?
t1f_nm int(3) MINUTE(a)
t1f_ps int(3) ?
t1e_nm bigint(20) unsigned CAST(EXTRACT(MINUTE FROM a) AS UNSIGNED)
t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(MINUTE(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(MINUTE FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(MINUTE(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(MINUTE FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(MINUTE(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(MINUTE FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(MINUTE(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(4) -EXTRACT(MINUTE FROM a)
t1e_ps int(4) -?
t1f_nm int(3) -MINUTE(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(MINUTE FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(MINUTE(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(MINUTE FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) MINUTE(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(MINUTE FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) MINUTE(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(3) CONCAT(EXTRACT(MINUTE FROM a))
t1e_ps varchar(3) CONCAT(?)
t1f_nm varchar(2) CONCAT(MINUTE(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(MINUTE FROM a),EXTRACT(MINUTE FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(MINUTE(a),MINUTE(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(MINUTE FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(MINUTE(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(MINUTE FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(MINUTE(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(MINUTE FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(MINUTE(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(MINUTE FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=MINUTE(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(MINUTE FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(MINUTE(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(MINUTE FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(MINUTE(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(MINUTE FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(MINUTE(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MINUTE FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(MINUTE(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(SECONDS FROM expr) includes the sign for TIME
# SECONDS(expr) returns the absolute value
CALL p1('SECOND');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(3) EXTRACT(SECOND FROM a)
t1e_ps int(3) ?
t1f_nm int(3) SECOND(a)
t1f_ps int(3) ?
t1e_nm bigint(20) unsigned CAST(EXTRACT(SECOND FROM a) AS UNSIGNED)
t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED)
t1f_nm int(2) unsigned CAST(SECOND(a) AS UNSIGNED)
t1f_ps int(2) unsigned CAST(? AS UNSIGNED)
t1e_nm int(3) CAST(EXTRACT(SECOND FROM a) AS SIGNED)
t1e_ps int(3) CAST(? AS SIGNED)
t1f_nm int(3) CAST(SECOND(a) AS SIGNED)
t1f_ps int(3) CAST(? AS SIGNED)
t1e_nm int(3) ABS(EXTRACT(SECOND FROM a))
t1e_ps int(3) ABS(?)
t1f_nm int(3) ABS(SECOND(a))
t1f_ps int(3) ABS(?)
t1e_nm int(3) ROUND(EXTRACT(SECOND FROM a))
t1e_ps int(3) ROUND(?)
t1f_nm int(3) ROUND(SECOND(a))
t1f_ps int(3) ROUND(?)
t1e_nm int(4) -EXTRACT(SECOND FROM a)
t1e_ps int(4) -?
t1f_nm int(3) -SECOND(a)
t1f_ps int(3) -?
t1e_nm int(4) ROUND(EXTRACT(SECOND FROM a),-1)
t1e_ps int(4) ROUND(?,-1)
t1f_nm int(4) ROUND(SECOND(a),-1)
t1f_ps int(4) ROUND(?,-1)
t1e_nm int(4) EXTRACT(SECOND FROM a)+0
t1e_ps int(4) ?+0
t1f_nm int(4) SECOND(a)+0
t1f_ps int(4) ?+0
t1e_nm decimal(4,1) EXTRACT(SECOND FROM a)+0.0
t1e_ps decimal(4,1) ?+0.0
t1f_nm decimal(4,1) SECOND(a)+0.0
t1f_ps decimal(4,1) ?+0.0
t1e_nm varchar(3) CONCAT(EXTRACT(SECOND FROM a))
t1e_ps varchar(3) CONCAT(?)
t1f_nm varchar(2) CONCAT(SECOND(a))
t1f_ps varchar(2) CONCAT(?)
t1e_nm int(3) LEAST(EXTRACT(SECOND FROM a),EXTRACT(SECOND FROM a))
t1e_ps int(3) LEAST(?,?)
t1f_nm int(3) LEAST(SECOND(a),SECOND(a))
t1f_ps int(3) LEAST(?,?)
t1e_nm int(3) COALESCE(EXTRACT(SECOND FROM a))
t1e_ps int(3) COALESCE(?)
t1f_nm int(3) COALESCE(SECOND(a))
t1f_ps int(3) COALESCE(?)
t1e_nm int(3) COALESCE(EXTRACT(SECOND FROM a),CAST(1 AS SIGNED))
t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(3) COALESCE(SECOND(a),CAST(1 AS SIGNED))
t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(2,0) COALESCE(EXTRACT(SECOND FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(2,0) COALESCE(SECOND(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(3) @a:=EXTRACT(SECOND FROM a)
t1e_ps int(3) @a:=?
t1f_nm int(3) @a:=SECOND(a)
t1f_ps int(3) @a:=?
t2e_nm decimal(6,4) AVG(EXTRACT(SECOND FROM a))
t2e_ps decimal(6,4) AVG(?)
t2f_nm decimal(6,4) AVG(SECOND(a))
t2f_ps decimal(6,4) AVG(?)
t2e_nm bigint(3) MIN(EXTRACT(SECOND FROM a))
t2e_ps bigint(3) MIN(?)
t2f_nm bigint(3) MIN(SECOND(a))
t2f_ps bigint(3) MIN(?)
t2e_nm bigint(3) MAX(EXTRACT(SECOND FROM a))
t2e_ps bigint(3) MAX(?)
t2f_nm bigint(3) MAX(SECOND(a))
t2f_ps bigint(3) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(SECOND FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(SECOND(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# EXTRACT(MICROSECONDS FROM expr) includes the sign for TIME
# MICROSECONDS(expr) returns the absolute value
CALL p1('MICROSECOND');
EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1e_nm int(7) EXTRACT(MICROSECOND FROM a)
t1e_ps int(7) ?
t1f_nm int(7) MICROSECOND(a)
t1f_ps int(7) ?
t1e_nm bigint(20) unsigned CAST(EXTRACT(MICROSECOND FROM a) AS UNSIGNED)
t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED)
t1f_nm int(6) unsigned CAST(MICROSECOND(a) AS UNSIGNED)
t1f_ps int(6) unsigned CAST(? AS UNSIGNED)
t1e_nm int(7) CAST(EXTRACT(MICROSECOND FROM a) AS SIGNED)
t1e_ps int(7) CAST(? AS SIGNED)
t1f_nm int(7) CAST(MICROSECOND(a) AS SIGNED)
t1f_ps int(7) CAST(? AS SIGNED)
t1e_nm int(7) ABS(EXTRACT(MICROSECOND FROM a))
t1e_ps int(7) ABS(?)
t1f_nm int(7) ABS(MICROSECOND(a))
t1f_ps int(7) ABS(?)
t1e_nm int(7) ROUND(EXTRACT(MICROSECOND FROM a))
t1e_ps int(7) ROUND(?)
t1f_nm int(7) ROUND(MICROSECOND(a))
t1f_ps int(7) ROUND(?)
t1e_nm int(8) -EXTRACT(MICROSECOND FROM a)
t1e_ps int(8) -?
t1f_nm int(7) -MICROSECOND(a)
t1f_ps int(7) -?
t1e_nm int(8) ROUND(EXTRACT(MICROSECOND FROM a),-1)
t1e_ps int(8) ROUND(?,-1)
t1f_nm int(8) ROUND(MICROSECOND(a),-1)
t1f_ps int(8) ROUND(?,-1)
t1e_nm int(8) EXTRACT(MICROSECOND FROM a)+0
t1e_ps int(8) ?+0
t1f_nm int(8) MICROSECOND(a)+0
t1f_ps int(8) ?+0
t1e_nm decimal(8,1) EXTRACT(MICROSECOND FROM a)+0.0
t1e_ps decimal(8,1) ?+0.0
t1f_nm decimal(8,1) MICROSECOND(a)+0.0
t1f_ps decimal(8,1) ?+0.0
t1e_nm varchar(7) CONCAT(EXTRACT(MICROSECOND FROM a))
t1e_ps varchar(7) CONCAT(?)
t1f_nm varchar(6) CONCAT(MICROSECOND(a))
t1f_ps varchar(6) CONCAT(?)
t1e_nm int(7) LEAST(EXTRACT(MICROSECOND FROM a),EXTRACT(MICROSECOND FROM a))
t1e_ps int(7) LEAST(?,?)
t1f_nm int(7) LEAST(MICROSECOND(a),MICROSECOND(a))
t1f_ps int(7) LEAST(?,?)
t1e_nm int(7) COALESCE(EXTRACT(MICROSECOND FROM a))
t1e_ps int(7) COALESCE(?)
t1f_nm int(7) COALESCE(MICROSECOND(a))
t1f_ps int(7) COALESCE(?)
t1e_nm int(7) COALESCE(EXTRACT(MICROSECOND FROM a),CAST(1 AS SIGNED))
t1e_ps int(7) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm int(7) COALESCE(MICROSECOND(a),CAST(1 AS SIGNED))
t1f_ps int(7) COALESCE(?,CAST(1 AS SIGNED))
t1e_nm decimal(6,0) COALESCE(EXTRACT(MICROSECOND FROM a),CAST(1 AS UNSIGNED))
t1e_ps decimal(6,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm decimal(6,0) COALESCE(MICROSECOND(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(6,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1e_nm int(7) @a:=EXTRACT(MICROSECOND FROM a)
t1e_ps int(7) @a:=?
t1f_nm int(7) @a:=MICROSECOND(a)
t1f_ps int(7) @a:=?
t2e_nm decimal(10,4) AVG(EXTRACT(MICROSECOND FROM a))
t2e_ps decimal(10,4) AVG(?)
t2f_nm decimal(10,4) AVG(MICROSECOND(a))
t2f_ps decimal(10,4) AVG(?)
t2e_nm bigint(7) MIN(EXTRACT(MICROSECOND FROM a))
t2e_ps bigint(7) MIN(?)
t2f_nm bigint(7) MIN(MICROSECOND(a))
t2f_ps bigint(7) MIN(?)
t2e_nm bigint(7) MAX(EXTRACT(MICROSECOND FROM a))
t2e_ps bigint(7) MAX(?)
t2f_nm bigint(7) MAX(MICROSECOND(a))
t2f_ps bigint(7) MAX(?)
t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MICROSECOND FROM a))
t2e_ps mediumtext GROUP_CONCAT(?)
t2f_nm mediumtext GROUP_CONCAT(MICROSECOND(a))
t2f_ps mediumtext GROUP_CONCAT(?)
# DAYOFYEAR
CALL p1('DAYOFYEAR');
EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999');
EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999');
CALL show_drop;
TABLE_NAME COLUMN_TYPE COLUMN_NAME
t1f_nm int(4) DAYOFYEAR(a)
t1f_ps int(4) ?
t1f_nm int(3) unsigned CAST(DAYOFYEAR(a) AS UNSIGNED)
t1f_ps int(3) unsigned CAST(? AS UNSIGNED)
t1f_nm int(4) CAST(DAYOFYEAR(a) AS SIGNED)
t1f_ps int(4) CAST(? AS SIGNED)
t1f_nm int(4) ABS(DAYOFYEAR(a))
t1f_ps int(4) ABS(?)
t1f_nm int(4) ROUND(DAYOFYEAR(a))
t1f_ps int(4) ROUND(?)
t1f_nm int(4) -DAYOFYEAR(a)
t1f_ps int(4) -?
t1f_nm int(5) ROUND(DAYOFYEAR(a),-1)
t1f_ps int(5) ROUND(?,-1)
t1f_nm int(5) DAYOFYEAR(a)+0
t1f_ps int(5) ?+0
t1f_nm decimal(5,1) DAYOFYEAR(a)+0.0
t1f_ps decimal(5,1) ?+0.0
t1f_nm varchar(3) CONCAT(DAYOFYEAR(a))
t1f_ps varchar(3) CONCAT(?)
t1f_nm int(4) LEAST(DAYOFYEAR(a),DAYOFYEAR(a))
t1f_ps int(4) LEAST(?,?)
t1f_nm int(4) COALESCE(DAYOFYEAR(a))
t1f_ps int(4) COALESCE(?)
t1f_nm int(4) COALESCE(DAYOFYEAR(a),CAST(1 AS SIGNED))
t1f_ps int(4) COALESCE(?,CAST(1 AS SIGNED))
t1f_nm decimal(3,0) COALESCE(DAYOFYEAR(a),CAST(1 AS UNSIGNED))
t1f_ps decimal(3,0) COALESCE(?,CAST(1 AS UNSIGNED))
t1f_nm int(4) @a:=DAYOFYEAR(a)
t1f_ps int(4) @a:=?
t2f_nm decimal(7,4) AVG(DAYOFYEAR(a))
t2f_ps decimal(7,4) AVG(?)
t2f_nm bigint(4) MIN(DAYOFYEAR(a))
t2f_ps bigint(4) MIN(?)
t2f_nm bigint(4) MAX(DAYOFYEAR(a))
t2f_ps bigint(4) MAX(?)
t2f_nm mediumtext GROUP_CONCAT(DAYOFYEAR(a))
t2f_ps mediumtext GROUP_CONCAT(?)
DROP TABLE t1;
DROP PROCEDURE p1;
DROP PROCEDURE show_drop;
DROP FUNCTION params;
DROP FUNCTION select01;
DROP FUNCTION select02;
#
# End of 10.5 tests
#

View File

@ -263,3 +263,254 @@ SELECT
FROM t1; FROM t1;
DROP TABLE t1; DROP TABLE t1;
--enable_view_protocol --enable_view_protocol
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type
--echo #
let select01=SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?;
let pcount01=16;
let select02=SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?);
let pcount02=4;
let ts=TIMESTAMP'2001-12-13 10:20:30.999999';
eval CREATE FUNCTION select01() RETURNS TEXT RETURN '$select01';
eval CREATE FUNCTION select02() RETURNS TEXT RETURN '$select02';
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('2001-12-31 10:20:30.999999');
DELIMITER $$;
CREATE FUNCTION params(expr TEXT, count INT) RETURNS TEXT
BEGIN
RETURN CONCAT(expr, REPEAT(CONCAT(', ', expr), count-1));
END;
$$
CREATE PROCEDURE show_drop()
BEGIN
SELECT TABLE_NAME, COLUMN_TYPE, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm',
't1e_ps','t1f_ps','t2e_ps','t2f_ps')
ORDER BY LEFT(TABLE_NAME, 2), ORDINAL_POSITION, TABLE_NAME;
FOR rec IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA='test'
AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm',
't1e_ps','t1f_ps','t2e_ps','t2f_ps'))
DO
EXECUTE IMMEDIATE CONCAT('DROP TABLE ', rec.TABLE_NAME);
END FOR;
END;
$$
CREATE PROCEDURE p1(unit VARCHAR(32))
BEGIN
DECLARE do_extract BOOL DEFAULT unit NOT IN('DAYOFYEAR');
DECLARE query01 TEXT DEFAULT
CONCAT('CREATE TABLE t2 AS ', select01(), ' FROM t1');
DECLARE query02 TEXT DEFAULT
CONCAT('CREATE TABLE t2 AS ', select02(), ' FROM t1');
IF (do_extract)
THEN
EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)'));
EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)'));
END IF;
EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1f_nm'),'?', CONCAT(unit,'(a)'));
EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2f_nm'),'?', CONCAT(unit,'(a)'));
END;
$$
DELIMITER ;$$
--echo
--echo
--echo # EXTRACT(YEAR FROM expr) and YEAR(expr) are equivalent
CALL p1('YEAR');
let extr=EXTRACT(YEAR FROM $ts);
let func=YEAR($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(QUARTER FROM expr) and QUARTER(expr) are equavalent
CALL p1('QUARTER');
let extr=EXTRACT(QUARTER FROM $ts);
let func=QUARTER($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(MONTH FROM expr) and MONTH(expr) are equavalent
CALL p1('MONTH');
let extr=EXTRACT(MONTH FROM $ts);
let func=MONTH($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(WEEK FROM expr) and WEEK(expr) are equavalent
CALL p1('WEEK');
let extr=EXTRACT(WEEK FROM $ts);
let func=WEEK($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(DAY FROM expr) returns hours/24 and includes the sign for TIME
--echo # DAY(expr) returns the DD part of CAST(expr AS DATETIME)
CALL p1('DAY');
let extr=EXTRACT(DAY FROM $ts);
let func=DAY($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(HOUR FROM expr) returns hours%24 and includes the sign for TIME
--echo # HOUR(expr) returns the hh part of CAST(expr AS DATETIME)
CALL p1('HOUR');
let extr=EXTRACT(HOUR FROM $ts);
let func=HOUR($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(MINUTE FROM expr) includes the sign for TIME
--echo # MINUTE(expr) returns the absolute value
CALL p1('MINUTE');
let extr=EXTRACT(MINUTE FROM $ts);
let func=MINUTE($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(SECONDS FROM expr) includes the sign for TIME
--echo # SECONDS(expr) returns the absolute value
CALL p1('SECOND');
let extr=EXTRACT(SECOND FROM $ts);
let func=SECOND($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # EXTRACT(MICROSECONDS FROM expr) includes the sign for TIME
--echo # MICROSECONDS(expr) returns the absolute value
CALL p1('MICROSECOND');
let extr=EXTRACT(MICROSECOND FROM $ts);
let func=MICROSECOND($ts);
let extr01=`SELECT params("$extr", $pcount01) AS p`;
let func01=`SELECT params("$func", $pcount01) AS p`;
let extr02=`SELECT params("$extr", $pcount02) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
--echo
--echo
--echo # DAYOFYEAR
CALL p1('DAYOFYEAR');
let func=DAYOFYEAR($ts);
let func01=`SELECT params("$func", $pcount01) AS p`;
let func02=`SELECT params("$func", $pcount02) AS p`;
eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01;
eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02;
CALL show_drop;
DROP TABLE t1;
DROP PROCEDURE p1;
DROP PROCEDURE show_drop;
DROP FUNCTION params;
DROP FUNCTION select01;
DROP FUNCTION select02;
--echo #
--echo # End of 10.5 tests
--echo #

View File

@ -1443,3 +1443,98 @@ drop table t1;
# #
# End of 10.3 tests # End of 10.3 tests
# #
#
# MDEV-31276: Execution of PS from grouping query with join
# and GROUP_CONCAT set function
#
create table t1 (a int, b varchar(20)) engine=myisam;
create table t2 (a int, c varchar(20)) engine=myisam;
insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb");
insert into t2 values (1,"cccccccccc"),(2,"dddddddddd");
insert into t2 values (1,"eeeeeee"),(2,"fffffff");
set group_concat_max_len=5;
select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
explain select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
prepare stmt from "select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a";
execute stmt;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
execute stmt;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
deallocate prepare stmt;
set join_cache_level=0;
select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
explain select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using filesort
1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where
prepare stmt from "select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a";
execute stmt;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
execute stmt;
count(*) group_concat(t1.b,t2.c)
2 aaaaa
2 bbbbb
Warnings:
Warning 1260 Row 1 was cut by GROUP_CONCAT()
Warning 1260 Row 2 was cut by GROUP_CONCAT()
deallocate prepare stmt;
set join_cache_level=default;
set group_concat_max_len=default;
drop table t1,t2;
#
# MDEV-33772 Bad SEPARATOR value in GROUP_CONCAT on character set conversion
#
SET NAMES utf8, @@collation_connection=latin1_swedish_ci;
CREATE TABLE t1 (c VARCHAR(10)) CHARACTER SET latin1;
INSERT INTO t1 VALUES ('a'),('A');
CREATE OR REPLACE VIEW v1 AS
SELECT GROUP_CONCAT(c SEPARATOR 'ß') AS c1 FROM t1 GROUP BY c;
SELECT * FROM v1;
c1
aßA
SELECT HEX(c1) FROM v1;
HEX(c1)
61DF41
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select group_concat(`t1`.`c` separator 'ß') AS `c1` from `t1` group by `t1`.`c` utf8mb3 latin1_swedish_ci
DROP VIEW v1;
DROP TABLE t1;
SET NAMES latin1;
# End of 10.5 tests

View File

@ -1066,3 +1066,59 @@ drop table t1;
--echo # --echo #
--echo # End of 10.3 tests --echo # End of 10.3 tests
--echo # --echo #
--echo #
--echo # MDEV-31276: Execution of PS from grouping query with join
--echo # and GROUP_CONCAT set function
--echo #
create table t1 (a int, b varchar(20)) engine=myisam;
create table t2 (a int, c varchar(20)) engine=myisam;
insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb");
insert into t2 values (1,"cccccccccc"),(2,"dddddddddd");
insert into t2 values (1,"eeeeeee"),(2,"fffffff");
let $q=
select count(*), group_concat(t1.b,t2.c)
from t1 join t2 on t1.a=t2.a group by t1.a;
set group_concat_max_len=5;
eval $q;
eval explain $q;
eval prepare stmt from "$q";
execute stmt;
execute stmt;
deallocate prepare stmt;
set join_cache_level=0;
eval $q;
eval explain $q;
eval prepare stmt from "$q";
execute stmt;
execute stmt;
deallocate prepare stmt;
set join_cache_level=default;
set group_concat_max_len=default;
drop table t1,t2;
--echo #
--echo # MDEV-33772 Bad SEPARATOR value in GROUP_CONCAT on character set conversion
--echo #
SET NAMES utf8, @@collation_connection=latin1_swedish_ci;
CREATE TABLE t1 (c VARCHAR(10)) CHARACTER SET latin1;
INSERT INTO t1 VALUES ('a'),('A');
CREATE OR REPLACE VIEW v1 AS
SELECT GROUP_CONCAT(c SEPARATOR 'ß') AS c1 FROM t1 GROUP BY c;
SELECT * FROM v1;
SELECT HEX(c1) FROM v1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP TABLE t1;
SET NAMES latin1;
--echo # End of 10.5 tests

View File

@ -272,7 +272,7 @@ create table t1 as select json_object('id', 87, 'name', 'carrot') as f;
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`f` varchar(32) DEFAULT NULL `f` varchar(46) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
select * from t1; select * from t1;
f f

View File

@ -87,15 +87,12 @@ select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]') as exp;
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]') as exp; select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]') as exp;
select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a') as exp; select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a') as exp;
#enable after MDEV-32454 fix
--disable_view_protocol
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word') as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word') as exp;
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3) as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3) as exp;
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2) as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2) as exp;
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word') as exp; select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word') as exp;
select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp; select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp;
--enable_view_protocol
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp; select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') as exp;
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]') as exp; select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]') as exp;
@ -137,14 +134,11 @@ select json_merge('a','b');
select json_merge('{"a":"b"}','{"c":"d"}'); select json_merge('{"a":"b"}','{"c":"d"}');
SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); SELECT JSON_MERGE('[1, 2]', '{"id": 47}');
#enable after MDEV-32454 fix
--disable_view_protocol
select json_type('{"k1":123, "k2":345}'); select json_type('{"k1":123, "k2":345}');
select json_type('[123, "k2", 345]'); select json_type('[123, "k2", 345]');
select json_type("true"); select json_type("true");
select json_type('123'); select json_type('123');
select json_type('123.12'); select json_type('123.12');
--enable_view_protocol
select json_keys('{"a":{"c":1, "d":2}, "b":2}'); select json_keys('{"a":{"c":1, "d":2}, "b":2}');
select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a"); select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a");
@ -173,11 +167,8 @@ select json_search( json_col, 'all', 'foot' ) as ex from t1;
drop table t1; drop table t1;
#enable after MDEV-32454 fix
--disable_view_protocol
select json_unquote('"abc"'); select json_unquote('"abc"');
select json_unquote('abc'); select json_unquote('abc');
--enable_view_protocol
# #
# MDEV-13703 Illegal mix of collations for operation 'json_object' on using JSON_UNQUOTE as an argument. # MDEV-13703 Illegal mix of collations for operation 'json_object' on using JSON_UNQUOTE as an argument.
# #
@ -188,13 +179,9 @@ select json_object('foo', json_unquote(json_object('bar', c)),'qux', c) as fld f
drop table t1; drop table t1;
#enable after MDEV-32454 fix
--disable_view_protocol
select json_object("a", json_object("b", "abcd")); select json_object("a", json_object("b", "abcd"));
select json_object("a", '{"b": "abcd"}'); select json_object("a", '{"b": "abcd"}');
select json_object("a", json_compact('{"b": "abcd"}')); select json_object("a", json_compact('{"b": "abcd"}'));
--enable_view_protocol
select json_compact(NULL); select json_compact(NULL);
select json_depth(json_compact(NULL)); select json_depth(json_compact(NULL));
@ -270,11 +257,8 @@ select json_merge('{"a":{"u":12, "x":"b"}}', '{"a":{"x":"c"}}') as ex ;
select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') as ex ; select json_merge('{"a":{"u":12, "x":"b", "r":1}}', '{"a":{"x":"c", "r":2}}') as ex ;
select json_compact('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; select json_compact('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex;
#enable after MDEV-32454 fix
--disable_view_protocol
select json_loose('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; select json_loose('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex;
select json_detailed('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex; select json_detailed('{"a":1, "b":[1,2,3], "c":{"aa":"v1", "bb": "v2"}}') as ex;
--enable_view_protocol
# #
# MDEV-11856 json_search doesn't search for values with double quotes character (") # MDEV-11856 json_search doesn't search for values with double quotes character (")
@ -469,12 +453,9 @@ drop table t1;
--echo # MDEV-16750 JSON_SET mishandles unicode every second pair of arguments. --echo # MDEV-16750 JSON_SET mishandles unicode every second pair of arguments.
--echo # --echo #
#enable after MDEV-32454 fix
--disable_view_protocol
SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6) as exp; SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6) as exp;
SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6, '$.b', _utf8 0xC3B6) as exp; SELECT JSON_SET('{}', '$.a', _utf8 0xC3B6, '$.b', _utf8 0xC3B6) as exp;
SELECT JSON_SET('{}', '$.a', _utf8 X'C3B6', '$.x', 1, '$.b', _utf8 X'C3B6') as exp; SELECT JSON_SET('{}', '$.a', _utf8 X'C3B6', '$.x', 1, '$.b', _utf8 X'C3B6') as exp;
--enable_view_protocol
--echo # --echo #
--echo # MDEV-17121 JSON_ARRAY_APPEND --echo # MDEV-17121 JSON_ARRAY_APPEND

View File

@ -110,7 +110,7 @@ R2
R3 R3
deallocate prepare stmt1; deallocate prepare stmt1;
drop table t1; drop table t1;
End of 4.1 tests # End of 4.1 tests
SELECT 1 REGEXP NULL; SELECT 1 REGEXP NULL;
1 REGEXP NULL 1 REGEXP NULL
NULL NULL
@ -126,7 +126,7 @@ NULL
SELECT "ABC" REGEXP BINARY NULL; SELECT "ABC" REGEXP BINARY NULL;
"ABC" REGEXP BINARY NULL "ABC" REGEXP BINARY NULL
NULL NULL
End of 5.0 tests # End of 5.0 tests
CREATE TABLE t1(a INT, b CHAR(4)); CREATE TABLE t1(a INT, b CHAR(4));
INSERT INTO t1 VALUES (1, '6.1'), (1, '7.0'), (1, '8.0'); INSERT INTO t1 VALUES (1, '6.1'), (1, '7.0'), (1, '8.0');
PREPARE stmt1 FROM "SELECT a FROM t1 WHERE a=1 AND '7.0' REGEXP b LIMIT 1"; PREPARE stmt1 FROM "SELECT a FROM t1 WHERE a=1 AND '7.0' REGEXP b LIMIT 1";
@ -144,7 +144,7 @@ a
1 1
DEALLOCATE PREPARE stmt1; DEALLOCATE PREPARE stmt1;
DROP TABLE t1; DROP TABLE t1;
End of 5.1 tests # End of 5.1 tests
SELECT ' ' REGEXP '[[:blank:]]'; SELECT ' ' REGEXP '[[:blank:]]';
' ' REGEXP '[[:blank:]]' ' ' REGEXP '[[:blank:]]'
1 1
@ -163,3 +163,19 @@ SELECT '\t' REGEXP '[[:space:]]';
SELECT REGEXP_INSTR('111222333',2); SELECT REGEXP_INSTR('111222333',2);
REGEXP_INSTR('111222333',2) REGEXP_INSTR('111222333',2)
4 4
# End of 10.3 tests
#
# MDEV-33344 REGEXP empty string inconsistent
#
create table t1 (x char(5));
insert t1 values (''), ('x');
select 'foo' regexp x from t1 order by x asc;
'foo' regexp x
1
0
select 'foo' regexp x from t1 order by x desc;
'foo' regexp x
0
1
drop table t1;
# End of 10.5 tests

View File

@ -55,7 +55,7 @@ execute stmt1 using @a;
deallocate prepare stmt1; deallocate prepare stmt1;
drop table t1; drop table t1;
--echo End of 4.1 tests --echo # End of 4.1 tests
# #
@ -74,7 +74,7 @@ SELECT NULL REGEXP BINARY NULL;
SELECT 'A' REGEXP BINARY NULL; SELECT 'A' REGEXP BINARY NULL;
SELECT "ABC" REGEXP BINARY NULL; SELECT "ABC" REGEXP BINARY NULL;
--echo End of 5.0 tests --echo # End of 5.0 tests
# #
@ -91,7 +91,7 @@ DEALLOCATE PREPARE stmt1;
DROP TABLE t1; DROP TABLE t1;
--echo End of 5.1 tests --echo # End of 5.1 tests
# #
# MDEV-5820 MySQL Bug #54805 definitions in regex/my_regex.h conflict with /usr/include/regex.h # MDEV-5820 MySQL Bug #54805 definitions in regex/my_regex.h conflict with /usr/include/regex.h
@ -110,3 +110,15 @@ SELECT '\t' REGEXP '[[:space:]]';
--echo # --echo #
SELECT REGEXP_INSTR('111222333',2); SELECT REGEXP_INSTR('111222333',2);
--echo # End of 10.3 tests
--echo #
--echo # MDEV-33344 REGEXP empty string inconsistent
--echo #
create table t1 (x char(5));
insert t1 values (''), ('x');
select 'foo' regexp x from t1 order by x asc;
select 'foo' regexp x from t1 order by x desc;
drop table t1;
--echo # End of 10.5 tests

View File

@ -7,7 +7,7 @@ select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo';
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo
select 'hello' 'monty'; select 'hello' 'monty';
hello hellomonty
hellomonty hellomonty
select length('\n\t\r\b\0\_\%\\'); select length('\n\t\r\b\0\_\%\\');
length('\n\t\r\b\0\_\%\\') length('\n\t\r\b\0\_\%\\')

View File

@ -3142,7 +3142,7 @@ Catalog Database Table Table_alias Column Column_alias Type Length Max length Is
def test t1 t1 a a 12 26 26 Y 128 6 63 def test t1 t1 a a 12 26 26 Y 128 6 63
def EXTRACT(YEAR FROM a) 3 4 4 Y 32896 0 63 def EXTRACT(YEAR FROM a) 3 4 4 Y 32896 0 63
def EXTRACT(YEAR_MONTH FROM a) 3 6 6 Y 32896 0 63 def EXTRACT(YEAR_MONTH FROM a) 3 6 6 Y 32896 0 63
def EXTRACT(QUARTER FROM a) 3 2 1 Y 32896 0 63 def EXTRACT(QUARTER FROM a) 3 1 1 Y 32896 0 63
def EXTRACT(MONTH FROM a) 3 2 2 Y 32896 0 63 def EXTRACT(MONTH FROM a) 3 2 2 Y 32896 0 63
def EXTRACT(WEEK FROM a) 3 2 2 Y 32896 0 63 def EXTRACT(WEEK FROM a) 3 2 2 Y 32896 0 63
def EXTRACT(DAY FROM a) 3 3 2 Y 32896 0 63 def EXTRACT(DAY FROM a) 3 3 2 Y 32896 0 63
@ -3230,11 +3230,11 @@ SHOW CREATE TABLE t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
`a` datetime(6) DEFAULT NULL, `a` datetime(6) DEFAULT NULL,
`EXTRACT(YEAR FROM a)` int(4) DEFAULT NULL, `EXTRACT(YEAR FROM a)` int(5) DEFAULT NULL,
`EXTRACT(YEAR_MONTH FROM a)` int(6) DEFAULT NULL, `EXTRACT(YEAR_MONTH FROM a)` int(7) DEFAULT NULL,
`EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL, `EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL,
`EXTRACT(MONTH FROM a)` int(2) DEFAULT NULL, `EXTRACT(MONTH FROM a)` int(3) DEFAULT NULL,
`EXTRACT(WEEK FROM a)` int(2) DEFAULT NULL, `EXTRACT(WEEK FROM a)` int(3) DEFAULT NULL,
`EXTRACT(DAY FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY FROM a)` int(3) DEFAULT NULL,
`EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL, `EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL,
`EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL, `EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL,
@ -3281,7 +3281,7 @@ Catalog Database Table Table_alias Column Column_alias Type Length Max length Is
def test t1 t1 a a 11 17 17 Y 128 6 63 def test t1 t1 a a 11 17 17 Y 128 6 63
def EXTRACT(YEAR FROM a) 3 4 1 Y 32896 0 63 def EXTRACT(YEAR FROM a) 3 4 1 Y 32896 0 63
def EXTRACT(YEAR_MONTH FROM a) 3 6 1 Y 32896 0 63 def EXTRACT(YEAR_MONTH FROM a) 3 6 1 Y 32896 0 63
def EXTRACT(QUARTER FROM a) 3 2 1 Y 32896 0 63 def EXTRACT(QUARTER FROM a) 3 1 1 Y 32896 0 63
def EXTRACT(MONTH FROM a) 3 2 1 Y 32896 0 63 def EXTRACT(MONTH FROM a) 3 2 1 Y 32896 0 63
def EXTRACT(WEEK FROM a) 3 2 9 Y 32896 0 63 def EXTRACT(WEEK FROM a) 3 2 9 Y 32896 0 63
def EXTRACT(DAY FROM a) 3 3 3 Y 32896 0 63 def EXTRACT(DAY FROM a) 3 3 3 Y 32896 0 63
@ -3411,11 +3411,11 @@ SHOW CREATE TABLE t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
`a` time(6) DEFAULT NULL, `a` time(6) DEFAULT NULL,
`EXTRACT(YEAR FROM a)` int(4) DEFAULT NULL, `EXTRACT(YEAR FROM a)` int(5) DEFAULT NULL,
`EXTRACT(YEAR_MONTH FROM a)` int(6) DEFAULT NULL, `EXTRACT(YEAR_MONTH FROM a)` int(7) DEFAULT NULL,
`EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL, `EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL,
`EXTRACT(MONTH FROM a)` int(2) DEFAULT NULL, `EXTRACT(MONTH FROM a)` int(3) DEFAULT NULL,
`EXTRACT(WEEK FROM a)` int(2) DEFAULT NULL, `EXTRACT(WEEK FROM a)` int(3) DEFAULT NULL,
`EXTRACT(DAY FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY FROM a)` int(3) DEFAULT NULL,
`EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL, `EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL,
`EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL, `EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL,

View File

@ -894,7 +894,7 @@ show status like 'Last_query_cost';
Variable_name Value Variable_name Value
Last_query_cost 0.011600 Last_query_cost 0.011600
select 'The cost of accessing t1 (dont care if it changes' '^'; select 'The cost of accessing t1 (dont care if it changes' '^';
The cost of accessing t1 (dont care if it changes The cost of accessing t1 (dont care if it changes^
The cost of accessing t1 (dont care if it changes^ The cost of accessing t1 (dont care if it changes^
select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z; select 'vv: Following query must use ALL(t1), eq_ref(A), eq_ref(B): vv' Z;
Z Z
@ -3435,6 +3435,62 @@ SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.
COUNT(*) COUNT(*)
2 2
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# MDEV-30975: Wrong result with cross Join given join order
#
CREATE TABLE `t1` (
`t1_seq` INT NOT NULL,
`c1` VARCHAR(10) NOT NULL ,
PRIMARY KEY (`t1_seq`) USING BTREE
);
CREATE TABLE `t2` (
`t2_seq` INT NOT NULL,
`t1_seq` INT NOT NULL,
`c2` VARCHAR(10) NOT NULL ,
PRIMARY KEY (`t2_seq`, `t1_seq`) USING BTREE
);
INSERT INTO t1 VALUES(1, 'A');
INSERT INTO t2 VALUES(1, 1, 'T2-1-1');
INSERT INTO t2 VALUES(2, 1, 'T2-1-2');
INSERT INTO t2 VALUES(3, 1, 'T2-1-3');
SELECT LPAD(@rownum := @rownum + 1, 8, 0) AS str_num
, t1.t1_seq
, t2.t2_seq
, t1.c1
, t2.c2
FROM t1
INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq)
CROSS JOIN ( SELECT @rownum := 0 ) X;
str_num t1_seq t2_seq c1 c2
00000001 1 1 A T2-1-1
00000002 1 2 A T2-1-2
00000003 1 3 A T2-1-3
SELECT STRAIGHT_JOIN LPAD(@rownum := @rownum + 1, 8, 0) AS str_num
, t1.t1_seq
, t2.t2_seq
, t1.c1
, t2.c2
FROM t1
INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq)
CROSS JOIN ( SELECT @rownum := 0 ) X;
str_num t1_seq t2_seq c1 c2
00000001 1 1 A T2-1-1
00000002 1 2 A T2-1-2
00000003 1 3 A T2-1-3
SELECT STRAIGHT_JOIN * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x;
t1_seq c1 t2_seq t1_seq c2 @a := 0
1 A 1 1 T2-1-1 0
1 A 2 1 T2-1-2 0
1 A 3 1 T2-1-3 0
SELECT * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x;
t1_seq c1 t2_seq t1_seq c2 @a := 0
1 A 1 1 T2-1-1 0
1 A 2 1 T2-1-2 0
1 A 3 1 T2-1-3 0
SELECT STRAIGHT_JOIN c1 FROM t1 JOIN (SELECT @a := 0) x;
c1
A
DROP TABLE t1, t2;
# End of 10.5 tests # End of 10.5 tests
# #
# MDEV-31449: Assertion s->table->opt_range_condition_rows <= s->found_records # MDEV-31449: Assertion s->table->opt_range_condition_rows <= s->found_records

View File

@ -1842,6 +1842,52 @@ SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b;
SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
--echo #
--echo # MDEV-30975: Wrong result with cross Join given join order
--echo #
CREATE TABLE `t1` (
`t1_seq` INT NOT NULL,
`c1` VARCHAR(10) NOT NULL ,
PRIMARY KEY (`t1_seq`) USING BTREE
);
CREATE TABLE `t2` (
`t2_seq` INT NOT NULL,
`t1_seq` INT NOT NULL,
`c2` VARCHAR(10) NOT NULL ,
PRIMARY KEY (`t2_seq`, `t1_seq`) USING BTREE
);
INSERT INTO t1 VALUES(1, 'A');
INSERT INTO t2 VALUES(1, 1, 'T2-1-1');
INSERT INTO t2 VALUES(2, 1, 'T2-1-2');
INSERT INTO t2 VALUES(3, 1, 'T2-1-3');
SELECT LPAD(@rownum := @rownum + 1, 8, 0) AS str_num
, t1.t1_seq
, t2.t2_seq
, t1.c1
, t2.c2
FROM t1
INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq)
CROSS JOIN ( SELECT @rownum := 0 ) X;
SELECT STRAIGHT_JOIN LPAD(@rownum := @rownum + 1, 8, 0) AS str_num
, t1.t1_seq
, t2.t2_seq
, t1.c1
, t2.c2
FROM t1
INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq)
CROSS JOIN ( SELECT @rownum := 0 ) X;
SELECT STRAIGHT_JOIN * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x;
SELECT * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x;
SELECT STRAIGHT_JOIN c1 FROM t1 JOIN (SELECT @a := 0) x;
DROP TABLE t1, t2;
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #

View File

@ -685,15 +685,9 @@ create table t1 (a int, b varchar(20));
create table t2 (a int, c varchar(20)); create table t2 (a int, c varchar(20));
insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb");
insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd");
#Enable after fix MDEV-31276
--disable_ps2_protocol
select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a;
--enable_ps2_protocol
select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a;
#Enable after fix MDEV-31276
--disable_ps2_protocol
select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a;
--enable_ps2_protocol
select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a;
drop table t1, t2; drop table t1, t2;
set group_concat_max_len=default; set group_concat_max_len=default;
@ -2372,11 +2366,8 @@ create view v1 as select * from t1
left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T
on T.ElectionID = t1.Election on T.ElectionID = t1.Election
limit 9; limit 9;
#enable after fix MDEV-31277
--disable_ps2_protocol
# limit X causes merge algorithm select as opposed to temp table # limit X causes merge algorithm select as opposed to temp table
select * from v1; select * from v1;
--enable_ps2_protocol
drop table t1, t2; drop table t1, t2;
drop view v1; drop view v1;
@ -2391,10 +2382,7 @@ create view v10 as select *, 'U' as u from t10 left join (select 'Y' as y, t20.b
create table t30 (c int); create table t30 (c int);
insert into t30 values (1),(3); insert into t30 values (1),(3);
create view v20 as select * from t30 left join (select 'X' as x, v10.u, v10.y, v10.b from v10) dt2 on t30.c=dt2.b limit 6; create view v20 as select * from t30 left join (select 'X' as x, v10.u, v10.y, v10.b from v10) dt2 on t30.c=dt2.b limit 6;
#check after fix MDEV-31277
--disable_ps2_protocol
select * from v20 limit 9; select * from v20 limit 9;
--enable_ps2_protocol
drop view v10, v20; drop view v10, v20;
drop table t10, t20, t30; drop table t10, t20, t30;
@ -2408,8 +2396,6 @@ insert into t3 values (3),(1);
create table t1 (a int); create table t1 (a int);
insert into t1 values (1),(2),(7),(1); insert into t1 values (1),(2),(7),(1);
#check after fix MDEV-31277
--disable_ps2_protocol
select * from select * from
( (
select * from select * from
@ -2422,7 +2408,6 @@ select * from
on dt1.a=dt2.b on dt1.a=dt2.b
limit 9 limit 9
) dt; ) dt;
--enable_ps2_protocol
## Same as dt3 above ## Same as dt3 above
create view v3(x,c) as select * from (select 'X' as x, t3.c from t3) dt3; create view v3(x,c) as select * from (select 'X' as x, t3.c from t3) dt3;
@ -2436,10 +2421,7 @@ create view v0(y,b,x,c) as select * from v2 left join v3 on v2.b=v3.c;
# Same as above select statement # Same as above select statement
create view v1 as select 'Z' as z, t1.a, v0.* from t1 left join v0 on t1.a=v0.b limit 9; create view v1 as select 'Z' as z, t1.a, v0.* from t1 left join v0 on t1.a=v0.b limit 9;
#check after fix MDEV-31277
--disable_ps2_protocol
select * from v1; select * from v1;
--enable_ps2_protocol
set statement join_cache_level=0 for set statement join_cache_level=0 for
select * from v1; select * from v1;

View File

@ -1,4 +1,8 @@
SET DEBUG_SYNC='dispatch_command_end SIGNAL ready WAIT_FOR go';
select 1;
connect con1,localhost,root,,; connect con1,localhost,root,,;
SET DEBUG_SYNC='now wait_for ready';
SET DEBUG_SYNC='now signal go';
SHOW PROCESSLIST; SHOW PROCESSLIST;
Id User Host db Command Time State Info Progress Id User Host db Command Time State Info Progress
# root # test Sleep # # NULL 0.000 # root # test Sleep # # NULL 0.000
@ -6,6 +10,8 @@ Id User Host db Command Time State Info Progress
SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go'; SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go';
SHOW PROCESSLIST; SHOW PROCESSLIST;
connection default; connection default;
1
1
SET DEBUG_SYNC='now WAIT_FOR ready'; SET DEBUG_SYNC='now WAIT_FOR ready';
KILL QUERY con_id; KILL QUERY con_id;
SET DEBUG_SYNC='now SIGNAL go'; SET DEBUG_SYNC='now SIGNAL go';

View File

@ -4,7 +4,14 @@
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/have_debug_sync.inc --source include/have_debug_sync.inc
# This is to ensure that the following SHOW PROCESSLIST does not show the query
SET DEBUG_SYNC='dispatch_command_end SIGNAL ready WAIT_FOR go';
--send select 1
--connect (con1,localhost,root,,) --connect (con1,localhost,root,,)
SET DEBUG_SYNC='now wait_for ready';
SET DEBUG_SYNC='now signal go';
--let $con_id = `SELECT CONNECTION_ID()` --let $con_id = `SELECT CONNECTION_ID()`
--replace_result Execute Query --replace_result Execute Query
--replace_column 1 # 3 # 6 # 7 # --replace_column 1 # 3 # 6 # 7 #
@ -12,6 +19,8 @@ SHOW PROCESSLIST;
SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go'; SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go';
send SHOW PROCESSLIST; send SHOW PROCESSLIST;
--connection default --connection default
--reap
# We must wait for the SHOW PROCESSLIST query to have started before sending # We must wait for the SHOW PROCESSLIST query to have started before sending
# the kill. Otherwise, the KILL may be lost since it is reset at the start of # the kill. Otherwise, the KILL may be lost since it is reset at the start of
# query execution. # query execution.

View File

@ -884,6 +884,6 @@ set debug_sync= 'now wait_for s1';
SELECT * FROM ( SELECT * FROM v1 ) sq; SELECT * FROM ( SELECT * FROM v1 ) sq;
COMMIT; COMMIT;
DROP VIEW v1; DROP VIEW v1;
DROP FUNCTION f; DROP FUNCTION IF EXISTS f;
DROP TABLE t1, t2; DROP TABLE t1, t2;
set debug_sync= 'reset'; set debug_sync= 'reset';

View File

@ -1219,6 +1219,6 @@ COMMIT;
--disconnect con2 --disconnect con2
--connection default --connection default
DROP VIEW v1; DROP VIEW v1;
DROP FUNCTION f; DROP FUNCTION IF EXISTS f;
DROP TABLE t1, t2; DROP TABLE t1, t2;
set debug_sync= 'reset'; set debug_sync= 'reset';

View File

@ -3,6 +3,8 @@
--echo # --echo #
source include/not_embedded.inc; source include/not_embedded.inc;
source include/not_windows.inc; source include/not_windows.inc;
# this would need an instrumented ncurses library
source include/not_msan.inc;
error 0,1; error 0,1;
exec $MYSQL -V|grep -q readline; exec $MYSQL -V|grep -q readline;

View File

@ -261,3 +261,4 @@ SET @@global.character_set_server= @save_character_set_server;
SET @@global.collation_server= @save_collation_server; SET @@global.collation_server= @save_collation_server;
SET @@global.character_set_client= @save_character_set_client; SET @@global.character_set_client= @save_character_set_client;
SET @@global.collation_connection= @save_collation_connection; SET @@global.collation_connection= @save_collation_connection;
FOUND 1 /Aborted connection.*'u' host: '192.0.2.1' real ip: '(localhost|::1)'/ in mysqld.1.err

View File

@ -57,3 +57,9 @@ SET @@global.character_set_server= @save_character_set_server;
SET @@global.collation_server= @save_collation_server; SET @@global.collation_server= @save_collation_server;
SET @@global.character_set_client= @save_character_set_client; SET @@global.character_set_client= @save_character_set_client;
SET @@global.collation_connection= @save_collation_connection; SET @@global.collation_connection= @save_collation_connection;
# Search for "real ip" in Aborted message
# This is indicator for abort of the proxied connections.
let SEARCH_FILE=$MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_PATTERN= Aborted connection.*'u' host: '192.0.2.1' real ip: '(localhost|::1)';
source include/search_pattern_in_file.inc;

View File

@ -1926,7 +1926,7 @@ slave-run-triggers-for-rbr NO
slave-skip-errors OFF slave-skip-errors OFF
slave-sql-verify-checksum TRUE slave-sql-verify-checksum TRUE
slave-transaction-retries 10 slave-transaction-retries 10
slave-transaction-retry-errors 1158,1159,1160,1161,1205,1213,1429,2013,12701 slave-transaction-retry-errors 1158,1159,1160,1161,1205,1213,1020,1429,2013,12701
slave-transaction-retry-interval 0 slave-transaction-retry-interval 0
slave-type-conversions slave-type-conversions
slow-launch-time 2 slow-launch-time 2

View File

@ -3,6 +3,14 @@ Test bad binlog format.
Test bad default storage engine. Test bad default storage engine.
Test non-numeric value passed to number option. Test non-numeric value passed to number option.
Test that bad value for plugin enum option is rejected correctly. Test that bad value for plugin enum option is rejected correctly.
Test to see if multiple unknown options will be displayed in the error output
unknown option '--nonexistentoption'
unknown option '--alsononexistent'
unknown variable 'nonexistentvariable=1'
Test to see if multiple ambiguous options and invalid arguments will be displayed in the error output
Error while setting value 'invalid_value' to 'sql_mode'
ambiguous option '--character' (character-set-client-handshake, character_sets_dir)
option '--bootstrap' cannot take an argument
Test that --help --verbose works Test that --help --verbose works
Test that --not-known-option --help --verbose gives error Test that --not-known-option --help --verbose gives error
Done. Done.

View File

@ -46,6 +46,18 @@ mkdir $MYSQLTEST_VARDIR/tmp/mysqld_option_err;
--error 7 --error 7
--exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --plugin-dir=$MYSQLTEST_VARDIR/plugins --plugin-load=example=ha_example.so --plugin-example-enum-var=noexist >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 --exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --plugin-dir=$MYSQLTEST_VARDIR/plugins --plugin-load=example=ha_example.so --plugin-example-enum-var=noexist >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1
--echo Test to see if multiple unknown options will be displayed in the error output
# Remove the noise to make the test robust
--replace_regex /^((?!nonexistent).)*$// /.*unknown/unknown/
--error 7
--exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --nonexistentoption --alsononexistent --nonexistentvariable=1 2>&1
--echo Test to see if multiple ambiguous options and invalid arguments will be displayed in the error output
# Remove the noise to make the test robust
--replace_regex /^((?!('sql_mode'|'--character'|'--bootstrap')).)*$// /.*Error while setting value/Error while setting value/ /.*ambiguous option/ambiguous option/ /.*option '--bootstrap'/option '--bootstrap'/
--error 1
--exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --getopt-prefix-matching --sql-mode=invalid_value --character --bootstrap=partstoob 2>&1
# #
# Test that an wrong option with --help --verbose gives an error # Test that an wrong option with --help --verbose gives an error
# #

View File

@ -5926,5 +5926,55 @@ a b
2 30 2 30
DROP TABLE t1, t2; DROP TABLE t1, t2;
# #
# MDEV-33549: Incorrect handling of UPDATE in PS mode in case a table's colum declared as NOT NULL
#
CREATE TABLE t1 (a INT, b INT DEFAULT NULL);
INSERT INTO t1 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1 SET b=?' USING DEFAULT;
SELECT * FROM t1;
a b
20 NULL
# Run twice the same update in PS mode to check
# that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1 SET b=?';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
# Clean up
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
# The same test for multi-table update
CREATE TABLE t1 (a INT, b INT DEFAULT NULL);
CREATE TABLE t2 (a INT, c INT DEFAULT NULL);
INSERT INTO t1 VALUES (20, 30);
INSERT INTO t2 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT;
SELECT * FROM t1;
a b
20 NULL
# Run twice the same multi-table update in PS mode to check
# that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
DEALLOCATE PREPARE stmt;
# Clean up
DROP TABLE t1;
# This time checks that a default value for table's column
# represented by a function call is handled correctly on UPDATE in PS mode
CREATE TABLE t1 (a INT, b INT DEFAULT MOD(a, 3));
INSERT INTO t1 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT;
SELECT * FROM t1;
a b
20 2
# Run twice the same multi-table update in PS mode to check
# that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
# Clean up
DEALLOCATE PREPARE stmt;
DROP TABLE t1, t2;
#
# End of 10.4 tests # End of 10.4 tests
# #

View File

@ -5367,6 +5367,60 @@ SELECT * FROM t2;
# Cleanup # Cleanup
DROP TABLE t1, t2; DROP TABLE t1, t2;
--echo #
--echo # MDEV-33549: Incorrect handling of UPDATE in PS mode in case a table's colum declared as NOT NULL
--echo #
CREATE TABLE t1 (a INT, b INT DEFAULT NULL);
INSERT INTO t1 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1 SET b=?' USING DEFAULT;
SELECT * FROM t1;
--echo # Run twice the same update in PS mode to check
--echo # that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1 SET b=?';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
--echo # Clean up
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
--echo # The same test for multi-table update
CREATE TABLE t1 (a INT, b INT DEFAULT NULL);
CREATE TABLE t2 (a INT, c INT DEFAULT NULL);
INSERT INTO t1 VALUES (20, 30);
INSERT INTO t2 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT;
SELECT * FROM t1;
--echo # Run twice the same multi-table update in PS mode to check
--echo # that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1,t2 SET b=? WHERE t1.a=t2.a';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
DEALLOCATE PREPARE stmt;
--echo # Clean up
DROP TABLE t1;
--echo # This time checks that a default value for table's column
--echo # represented by a function call is handled correctly on UPDATE in PS mode
CREATE TABLE t1 (a INT, b INT DEFAULT MOD(a, 3));
INSERT INTO t1 VALUES (20, 30);
EXECUTE IMMEDIATE 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a' USING DEFAULT;
SELECT * FROM t1;
--echo # Run twice the same multi-table update in PS mode to check
--echo # that no memory relating issues taken place.
PREPARE stmt FROM 'UPDATE t1, t2 SET b=? WHERE t1.a=t2.a';
EXECUTE stmt USING DEFAULT;
EXECUTE stmt USING DEFAULT;
--echo # Clean up
DEALLOCATE PREPARE stmt;
DROP TABLE t1, t2;
--echo # --echo #
--echo # End of 10.4 tests --echo # End of 10.4 tests
--echo # --echo #

View File

@ -1798,7 +1798,7 @@ t5 CREATE TABLE `t5` (
`param09` longtext DEFAULT NULL, `param09` longtext DEFAULT NULL,
`const10` bigint(17) DEFAULT NULL, `const10` bigint(17) DEFAULT NULL,
`param10` bigint(20) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL,
`const11` int(4) DEFAULT NULL, `const11` int(5) DEFAULT NULL,
`param11` bigint(20) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL,
`const12` binary(0) DEFAULT NULL, `const12` binary(0) DEFAULT NULL,
`param12` bigint(20) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL,
@ -1828,7 +1828,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63
def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8
def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 const11 const11 3 5 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63

View File

@ -1781,7 +1781,7 @@ t5 CREATE TABLE `t5` (
`param09` longtext DEFAULT NULL, `param09` longtext DEFAULT NULL,
`const10` bigint(17) DEFAULT NULL, `const10` bigint(17) DEFAULT NULL,
`param10` bigint(20) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL,
`const11` int(4) DEFAULT NULL, `const11` int(5) DEFAULT NULL,
`param11` bigint(20) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL,
`const12` binary(0) DEFAULT NULL, `const12` binary(0) DEFAULT NULL,
`param12` bigint(20) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL,
@ -1811,7 +1811,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63
def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8
def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 const11 const11 3 5 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63

View File

@ -1782,7 +1782,7 @@ t5 CREATE TABLE `t5` (
`param09` longtext DEFAULT NULL, `param09` longtext DEFAULT NULL,
`const10` bigint(17) DEFAULT NULL, `const10` bigint(17) DEFAULT NULL,
`param10` bigint(20) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL,
`const11` int(4) DEFAULT NULL, `const11` int(5) DEFAULT NULL,
`param11` bigint(20) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL,
`const12` binary(0) DEFAULT NULL, `const12` binary(0) DEFAULT NULL,
`param12` bigint(20) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL,
@ -1812,7 +1812,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63
def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8
def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 const11 const11 3 5 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63

View File

@ -1719,7 +1719,7 @@ t5 CREATE TABLE `t5` (
`param09` longtext DEFAULT NULL, `param09` longtext DEFAULT NULL,
`const10` bigint(17) DEFAULT NULL, `const10` bigint(17) DEFAULT NULL,
`param10` bigint(20) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL,
`const11` int(4) DEFAULT NULL, `const11` int(5) DEFAULT NULL,
`param11` bigint(20) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL,
`const12` binary(0) DEFAULT NULL, `const12` binary(0) DEFAULT NULL,
`param12` bigint(20) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL,
@ -1749,7 +1749,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63
def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8
def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 const11 const11 3 5 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
@ -5087,7 +5087,7 @@ t5 CREATE TABLE `t5` (
`param09` longtext DEFAULT NULL, `param09` longtext DEFAULT NULL,
`const10` bigint(17) DEFAULT NULL, `const10` bigint(17) DEFAULT NULL,
`param10` bigint(20) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL,
`const11` int(4) DEFAULT NULL, `const11` int(5) DEFAULT NULL,
`param11` bigint(20) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL,
`const12` binary(0) DEFAULT NULL, `const12` binary(0) DEFAULT NULL,
`param12` bigint(20) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL,
@ -5117,7 +5117,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63
def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8
def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63
def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 const11 const11 3 5 4 Y 32768 0 63
def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63
def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63

View File

@ -219,4 +219,8 @@ connection master;
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START; -- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=BINLOG_START;
connection slave; connection slave;
include/start_slave.inc include/start_slave.inc
connection master;
connection slave;
connection master;
FOUND 1 matches in MDEV-33212.sql
include/rpl_end.inc include/rpl_end.inc

View File

@ -198,4 +198,20 @@ if ($postdump_first_binary_log_filename != $postdump_binlog_filename)
connection slave; connection slave;
--source include/start_slave.inc --source include/start_slave.inc
# MDEV-33212: mysqldump uses MASTER_LOG_POS with dump-slave
# The bug was that the MASTER_LOG_POS was wrong. So check that it is correct.
--connection master
--let $pos= query_get_value(SHOW MASTER STATUS, Position, 1)
--sync_slave_with_master
--connection master
--exec $MYSQL_DUMP_SLAVE --compact --dump-slave test >$MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
--let SEARCH_RANGE=500000000
--let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
--let SEARCH_PATTERN= MASTER_LOG_POS=$pos
--let SEARCH_OUTPUT=count
--source include/search_pattern_in_file.inc
--remove_file $MYSQLTEST_VARDIR/tmp/MDEV-33212.sql
--source include/rpl_end.inc --source include/rpl_end.inc

View File

@ -563,9 +563,12 @@ SET debug_dbug=@old_debug;
# Try to do SHOW EXPLAIN for a query that runs a SET command: # Try to do SHOW EXPLAIN for a query that runs a SET command:
# I've found experimentally that select_id==2 here... # I've found experimentally that select_id==2 here...
# #
set @show_explain_probe_select_id=2; create table t2 (a int);
insert into t2 values (1),(2);
set @show_explain_probe_select_id=3;
SET debug_dbug='+d,show_explain_probe_join_exec_start'; SET debug_dbug='+d,show_explain_probe_join_exec_start';
set @foo= (select max(a) from t0 where sin(a) >0); set @foo= (select max(a) from t2
where a + (select max(a) from t0 where t0.a>t2.a) < 10000);
connection default; connection default;
show explain format=JSON for $thr2; show explain format=JSON for $thr2;
ERROR HY000: Target is not executing an operation with a query plan ERROR HY000: Target is not executing an operation with a query plan
@ -573,6 +576,7 @@ kill query $thr2;
connection con1; connection con1;
ERROR 70100: Query execution was interrupted ERROR 70100: Query execution was interrupted
SET debug_dbug=@old_debug; SET debug_dbug=@old_debug;
drop table t2;
# #
# Attempt SHOW EXPLAIN for an UPDATE # Attempt SHOW EXPLAIN for an UPDATE
# #

View File

@ -281,9 +281,16 @@ SET debug_dbug=@old_debug;
--echo # Try to do SHOW EXPLAIN for a query that runs a SET command: --echo # Try to do SHOW EXPLAIN for a query that runs a SET command:
--echo # I've found experimentally that select_id==2 here... --echo # I've found experimentally that select_id==2 here...
--echo # --echo #
set @show_explain_probe_select_id=2;
create table t2 (a int);
insert into t2 values (1),(2);
set @show_explain_probe_select_id=3; # Stop in the subquery.
SET debug_dbug='+d,show_explain_probe_join_exec_start'; SET debug_dbug='+d,show_explain_probe_join_exec_start';
send set @foo= (select max(a) from t0 where sin(a) >0); # t2 has 2 rows so we will stop in the subquery twice:
# - first one to serve the SHOW ANALYZE request
# - second one when waiting to be KILLed.
send set @foo= (select max(a) from t2
where a + (select max(a) from t0 where t0.a>t2.a) < 10000);
connection default; connection default;
--source include/wait_condition.inc --source include/wait_condition.inc
--error ER_TARGET_NOT_EXPLAINABLE --error ER_TARGET_NOT_EXPLAINABLE
@ -293,6 +300,7 @@ connection con1;
--error ER_QUERY_INTERRUPTED --error ER_QUERY_INTERRUPTED
reap; reap;
SET debug_dbug=@old_debug; SET debug_dbug=@old_debug;
drop table t2;
--echo # --echo #
--echo # Attempt SHOW EXPLAIN for an UPDATE --echo # Attempt SHOW EXPLAIN for an UPDATE

View File

@ -524,8 +524,6 @@ where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0');
# group_concat with a blob argument - depends on # group_concat with a blob argument - depends on
# the variable group_concat_max_len, and # the variable group_concat_max_len, and
# convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB
#Check after fix MDEV-31276
--disable_ps2_protocol
explain extended select left(a1,7), left(a2,7) explain extended select left(a1,7), left(a2,7)
from t1_512 from t1_512
where a1 in (select group_concat(b1) from t2_512 group by b2); where a1 in (select group_concat(b1) from t2_512 group by b2);
@ -543,7 +541,6 @@ where a1 in (select group_concat(b1) from t2_512 group by b2);
select left(a1,7), left(a2,7) select left(a1,7), left(a2,7)
from t1_512 from t1_512
where a1 in (select group_concat(b1) from t2_512 group by b2); where a1 in (select group_concat(b1) from t2_512 group by b2);
--enable_ps2_protocol
drop table t1_512, t2_512, t3_512; drop table t1_512, t2_512, t3_512;
@ -609,8 +606,6 @@ where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0');
# group_concat with a blob argument - depends on # group_concat with a blob argument - depends on
# the variable group_concat_max_len, and # the variable group_concat_max_len, and
# convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB
#Check after fix MDEV-31276
--disable_ps2_protocol
explain extended select left(a1,7), left(a2,7) explain extended select left(a1,7), left(a2,7)
from t1_1024 from t1_1024
where a1 in (select group_concat(b1) from t2_1024 group by b2); where a1 in (select group_concat(b1) from t2_1024 group by b2);
@ -628,7 +623,6 @@ where a1 in (select group_concat(b1) from t2_1024 group by b2);
select left(a1,7), left(a2,7) select left(a1,7), left(a2,7)
from t1_1024 from t1_1024
where a1 in (select group_concat(b1) from t2_1024 group by b2); where a1 in (select group_concat(b1) from t2_1024 group by b2);
--enable_ps2_protocol
drop table t1_1024, t2_1024, t3_1024; drop table t1_1024, t2_1024, t3_1024;
@ -694,8 +688,6 @@ where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0');
# group_concat with a blob argument - depends on # group_concat with a blob argument - depends on
# the variable group_concat_max_len, and # the variable group_concat_max_len, and
# convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB
#Check after fix MDEV-31276
--disable_ps2_protocol
explain extended select left(a1,7), left(a2,7) explain extended select left(a1,7), left(a2,7)
from t1_1025 from t1_1025
where a1 in (select group_concat(b1) from t2_1025 group by b2); where a1 in (select group_concat(b1) from t2_1025 group by b2);
@ -713,7 +705,6 @@ where a1 in (select group_concat(b1) from t2_1025 group by b2);
select left(a1,7), left(a2,7) select left(a1,7), left(a2,7)
from t1_1025 from t1_1025
where a1 in (select group_concat(b1) from t2_1025 group by b2); where a1 in (select group_concat(b1) from t2_1025 group by b2);
--enable_ps2_protocol
drop table t1_1025, t2_1025, t3_1025; drop table t1_1025, t2_1025, t3_1025;

Some files were not shown because too many files have changed in this diff Show More