From 0248fb2e8a3c6a02f443140cfcf68a0190354e23 Mon Sep 17 00:00:00 2001 From: Chaithra Gopalareddy Date: Thu, 18 Aug 2016 09:56:48 +0530 Subject: [PATCH 001/124] Bug #23135667: CRASH AFTER DEEPLY NESTED BUILD_EQUAL_ITEMS_FOR_COND Problem: When build_equal_items_for_cond gets called for a big query recursively, the specified thread_stack_size exceeds. But optimizer does not handle this condition. As a result, server exits. Solution: Check if we exceed specified stack size and if yes exit gracefully by throwing an error. --- sql/sql_select.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fb705e9ba6a..80d4b87e916 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8154,6 +8154,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond, COND_EQUAL cond_equal; cond_equal.upper_levels= inherited; + if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL)) + return cond; // Fatal error flag is set! + if (cond->type() == Item::COND_ITEM) { List eq_list; From 04bad164e7d4bad2b2ed63485ea6361029392d68 Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Thu, 18 Aug 2016 12:12:09 +0530 Subject: [PATCH 002/124] From 8b1f4d84cafe393e92f942278f9f020a62ceb5b9 Mon Sep 17 00:00:00 2001 From: Terje Rosten Date: Fri, 12 Aug 2016 12:38:20 +0200 Subject: [PATCH 003/124] Bug#24464380 PRIVILEGE ESCALATION USING MYSQLD_SAFE Argument to malloc-lib must be included in restricted list of directories, symlink guards added, and mysqld and mysqld-version options restricted to command line only. Don't redirect errors to stderr. --- packaging/rpm-oel/mysql.init | 2 +- packaging/rpm-sles/mysql.init | 2 +- scripts/mysqld_safe.sh | 79 +++++++++++++++++++++-------------- support-files/mysql.server.sh | 2 +- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/packaging/rpm-oel/mysql.init b/packaging/rpm-oel/mysql.init index 262d0582f68..aaea498d153 100644 --- a/packaging/rpm-oel/mysql.init +++ b/packaging/rpm-oel/mysql.init @@ -102,7 +102,7 @@ start(){ # alarms, per bug #547485 $exec --datadir="$datadir" --socket="$socketfile" \ --pid-file="$mypidfile" \ - --basedir=/usr --user=mysql >/dev/null 2>&1 & + --basedir=/usr --user=mysql >/dev/null & safe_pid=$! # Spin for a maximum of N seconds waiting for the server to come up; # exit the loop immediately if mysqld_safe process disappears. diff --git a/packaging/rpm-sles/mysql.init b/packaging/rpm-sles/mysql.init index 50ca4c9033c..dda0bebba56 100644 --- a/packaging/rpm-sles/mysql.init +++ b/packaging/rpm-sles/mysql.init @@ -137,7 +137,7 @@ start () { rc_failed 6 ; rc_status -v ; rc_exit fi - $PROG --basedir=/usr --datadir="$datadir" --pid-file="$pidfile" >/dev/null 2>&1 & + $PROG --basedir=/usr --datadir="$datadir" --pid-file="$pidfile" >/dev/null & if pinger $! ; then echo -n "Starting service MySQL:" touch $lockfile diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index f705953059e..11b692ec928 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -208,8 +208,17 @@ parse_arguments() { --core-file-size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; --malloc-lib=*) set_malloc_lib "$val" ;; - --mysqld=*) MYSQLD="$val" ;; + --mysqld=*) + if [ -z "$pick_args" ]; then + log_error "--mysqld option can only be used as command line option, found in config file" + exit 1 + fi + MYSQLD="$val" ;; --mysqld-version=*) + if [ -z "$pick_args" ]; then + log_error "--mysqld-version option can only be used as command line option, found in config file" + exit 1 + fi if test -n "$val" then MYSQLD="mysqld-$val" @@ -297,38 +306,22 @@ mysqld_ld_preload_text() { echo "$text" } - -mysql_config= -get_mysql_config() { - if [ -z "$mysql_config" ]; then - mysql_config=`echo "$0" | sed 's,/[^/][^/]*$,/mysql_config,'` - if [ ! -x "$mysql_config" ]; then - log_error "Can not run mysql_config $@ from '$mysql_config'" - exit 1 - fi - fi - - "$mysql_config" "$@" -} - - # set_malloc_lib LIB # - If LIB is empty, do nothing and return -# - If LIB is 'tcmalloc', look for tcmalloc shared library in /usr/lib -# then pkglibdir. tcmalloc is part of the Google perftools project. +# - If LIB is 'tcmalloc', look for tcmalloc shared library in $malloc_dirs. +# tcmalloc is part of the Google perftools project. # - If LIB is an absolute path, assume it is a malloc shared library # # Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when # running mysqld. See ld.so for details. set_malloc_lib() { + # This list is kept intentionally simple. + malloc_dirs="/usr/lib /usr/lib64 /usr/lib/i386-linux-gnu /usr/lib/x86_64-linux-gnu" malloc_lib="$1" if [ "$malloc_lib" = tcmalloc ]; then - pkglibdir=`get_mysql_config --variable=pkglibdir` malloc_lib= - # This list is kept intentionally simple. Simply set --malloc-lib - # to a full path if another location is desired. - for libdir in /usr/lib "$pkglibdir" "$pkglibdir/mysql"; do + for libdir in $(echo $malloc_dirs); do for flavor in _minimal '' _and_profiler _debug; do tmp="$libdir/libtcmalloc$flavor.so" #log_notice "DEBUG: Checking for malloc lib '$tmp'" @@ -339,7 +332,7 @@ set_malloc_lib() { done if [ -z "$malloc_lib" ]; then - log_error "no shared library for --malloc-lib=tcmalloc found in /usr/lib or $pkglibdir" + log_error "no shared library for --malloc-lib=tcmalloc found in $malloc_dirs" exit 1 fi fi @@ -350,9 +343,21 @@ set_malloc_lib() { case "$malloc_lib" in /*) if [ ! -r "$malloc_lib" ]; then - log_error "--malloc-lib '$malloc_lib' can not be read and will not be used" + log_error "--malloc-lib can not be read and will not be used" exit 1 fi + + # Restrict to a the list in $malloc_dirs above + case "$(dirname "$malloc_lib")" in + /usr/lib) ;; + /usr/lib64) ;; + /usr/lib/i386-linux-gnu) ;; + /usr/lib/x86_64-linux-gnu) ;; + *) + log_error "--malloc-lib must be located in one of the directories: $malloc_dirs" + exit 1 + ;; + esac ;; *) log_error "--malloc-lib must be an absolute path or 'tcmalloc'; " \ @@ -569,7 +574,7 @@ then log_notice "Logging to '$err_log'." logging=file - if [ ! -f "$err_log" ]; then # if error log already exists, + if [ ! -f "$err_log" -a ! -h "$err_log" ]; then # if error log already exists, touch "$err_log" # we just append. otherwise, chmod "$fmode" "$err_log" # fix the permissions here! fi @@ -594,7 +599,7 @@ then USER_OPTION="--user=$user" fi # Change the err log to the right user, if it is in use - if [ $want_syslog -eq 0 ]; then + if [ $want_syslog -eq 0 -a ! -h "$err_log" ]; then touch "$err_log" chown $user "$err_log" fi @@ -614,9 +619,11 @@ safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@}} mysql_unix_port_dir=`dirname $safe_mysql_unix_port` if [ ! -d $mysql_unix_port_dir ] then - mkdir $mysql_unix_port_dir - chown $user $mysql_unix_port_dir - chmod 755 $mysql_unix_port_dir + if [ ! -h $mysql_unix_port_dir ]; then + mkdir $mysql_unix_port_dir + chown $user $mysql_unix_port_dir + chmod 755 $mysql_unix_port_dir + fi fi # If the user doesn't specify a binary, we assume name "mysqld" @@ -728,7 +735,9 @@ then exit 1 fi fi - rm -f "$pid_file" + if [ ! -h "$pid_file" ]; then + rm -f "$pid_file" + fi if test -f "$pid_file" then log_error "Fatal error: Can't remove the pid file: @@ -779,13 +788,19 @@ have_sleep=1 while true do - rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety + # Some extra safety + if [ ! -h "$safe_mysql_unix_port" ]; then + rm -f "$safe_mysql_unix_port" + fi + if [ ! -h "$pid_file" ]; then + rm -f "$pid_file" + fi start_time=`date +%M%S` eval_log_error "$cmd" - if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then + if [ $want_syslog -eq 0 -a ! -f "$err_log" -a ! -h "$err_log" ]; then touch "$err_log" # hypothetical: log was renamed but not chown $user "$err_log" # flushed yet. we'd recreate it with chmod "$fmode" "$err_log" # wrong owner next time we log, so set diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 7487d5acc0f..909d33f8770 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -280,7 +280,7 @@ case "$mode" in then # Give extra arguments to mysqld with the my.cnf file. This script # may be overwritten at next upgrade. - $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 & + $bindir/mysqld_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null & wait_for_pid created "$!" "$mysqld_pid_file_path"; return_value=$? # Make lock for RedHat / SuSE From 033b11912121ad2c1dbd4a93202eeac196124801 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Tue, 16 Aug 2016 15:35:19 +0200 Subject: [PATCH 004/124] Bug#24388746: PRIVILEGE ESCALATION AND RACE CONDITION USING CREATE TABLE During REPAIR TABLE of a MyISAM table, a temporary data file (.TMD) is created. When repair finishes, this file is renamed to the original .MYD file. The problem was that during this rename, we copied the stats from the old file to the new file with chmod/chown. If a user managed to replace the temporary file before chmod/chown was executed, it was possible to get an arbitrary file with the privileges of the mysql user. This patch fixes the problem by not copying stats from the old file to the new file. This is not needed as the new file was created with the correct stats. This fix only changes server behavior - external utilities such as myisamchk still does chmod/chown. No test case provided since the problem involves synchronization with file system operations. --- include/my_sys.h | 3 ++- include/myisam.h | 11 +++++----- mysys/my_redel.c | 12 ++++++++--- storage/myisam/ha_myisam.cc | 26 ++++++++++++++++++----- storage/myisam/mi_check.c | 41 ++++++++++++++++++++++++++----------- storage/myisam/myisamchk.c | 16 +++++++++------ 6 files changed, 77 insertions(+), 32 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index b1b8bf15be3..472c2ba5ca0 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -83,6 +83,7 @@ typedef struct my_aio_result { #define MY_RESOLVE_LINK 128 /* my_realpath(); Only resolve links */ #define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ #define MY_REDEL_MAKE_BACKUP 256 +#define MY_REDEL_NO_COPY_STAT 512 /* my_redel() doesn't call my_copystat() */ #define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ #define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ #define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */ diff --git a/include/myisam.h b/include/myisam.h index 85d37a81bc6..a9fcd7e4369 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -426,12 +426,13 @@ int chk_size(MI_CHECK *param, MI_INFO *info); int chk_key(MI_CHECK *param, MI_INFO *info); int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend); int mi_repair(MI_CHECK *param, register MI_INFO *info, - char * name, int rep_quick); -int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name); + char * name, int rep_quick, my_bool no_copy_stat); +int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name, + my_bool no_copy_stat); int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, - const char * name, int rep_quick); + const char * name, int rep_quick, my_bool no_copy_stat); int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, - const char * name, int rep_quick); + const char * name, int rep_quick, my_bool no_copy_stat); int change_to_newfile(const char * filename, const char * old_ext, const char * new_ext, myf myflags); int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type, diff --git a/mysys/my_redel.c b/mysys/my_redel.c index a47df8265c8..25391cd4e8f 100644 --- a/mysys/my_redel.c +++ b/mysys/my_redel.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -35,6 +35,9 @@ struct utimbuf { if MY_REDEL_MAKE_COPY is given, then the orginal file is renamed to org_name-'current_time'.BAK + + if MY_REDEL_NO_COPY_STAT is given, stats are not copied + from org_name to tmp_name. */ #define REDEL_EXT ".BAK" @@ -46,8 +49,11 @@ int my_redel(const char *org_name, const char *tmp_name, myf MyFlags) DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s' MyFlags: %d", org_name,tmp_name,MyFlags)); - if (my_copystat(org_name,tmp_name,MyFlags) < 0) - goto end; + if (!(MyFlags & MY_REDEL_NO_COPY_STAT)) + { + if (my_copystat(org_name,tmp_name,MyFlags) < 0) + goto end; + } if (MyFlags & MY_REDEL_MAKE_BACKUP) { char name_buff[FN_REFLEN+20]; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 602a0ae6cc1..21cbef32188 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -1091,24 +1091,36 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) /* TODO: respect myisam_repair_threads variable */ my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); thd_proc_info(thd, buf); + /* + The new file is created with the right stats, so we can skip + copying file stats from old to new. + */ error = mi_repair_parallel(¶m, file, fixed_name, - param.testflag & T_QUICK); + param.testflag & T_QUICK, TRUE); thd_proc_info(thd, "Repair done"); // to reset proc_info, as // it was pointing to local buffer } else { thd_proc_info(thd, "Repair by sorting"); + /* + The new file is created with the right stats, so we can skip + copying file stats from old to new. + */ error = mi_repair_by_sort(¶m, file, fixed_name, - param.testflag & T_QUICK); + param.testflag & T_QUICK, TRUE); } } else { thd_proc_info(thd, "Repair with keycache"); param.testflag &= ~T_REP_BY_SORT; + /* + The new file is created with the right stats, so we can skip + copying file stats from old to new. + */ error= mi_repair(¶m, file, fixed_name, - param.testflag & T_QUICK); + param.testflag & T_QUICK, TRUE); } #ifdef HAVE_MMAP if (remap) @@ -1124,7 +1136,11 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) { optimize_done=1; thd_proc_info(thd, "Sorting index"); - error=mi_sort_index(¶m,file,fixed_name); + /* + The new file is created with the right stats, so we can skip + copying file stats from old to new. + */ + error=mi_sort_index(¶m,file,fixed_name, TRUE); } if (!statistics_done && (local_testflag & T_STATISTICS)) { diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index ba1f975549a..fe0d4c9c30b 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -1512,7 +1512,7 @@ static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force) /* Save new datafile-name in temp_filename */ int mi_repair(MI_CHECK *param, register MI_INFO *info, - char * name, int rep_quick) + char * name, int rep_quick, my_bool no_copy_stat) { int error,got_error; ha_rows start_records,new_header_length; @@ -1726,6 +1726,11 @@ err: /* Replace the actual file with the temporary file */ if (new_file >= 0) { + myf flags= 0; + if (param->testflag & T_BACKUP_DATA) + flags |= MY_REDEL_MAKE_BACKUP; + if (no_copy_stat) + flags |= MY_REDEL_NO_COPY_STAT; mysql_file_close(new_file, MYF(0)); info->dfile=new_file= -1; /* @@ -1744,8 +1749,7 @@ err: info->s->file_map= NULL; } if (change_to_newfile(share->data_file_name, MI_NAME_DEXT, DATA_TMP_EXT, - (param->testflag & T_BACKUP_DATA ? - MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || + flags) || mi_open_datafile(info,share,name,-1)) got_error=1; @@ -1933,7 +1937,8 @@ int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file) /* Sort index for more efficent reads */ -int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name) +int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name, + my_bool no_copy_stat) { reg2 uint key; reg1 MI_KEYDEF *keyinfo; @@ -2004,7 +2009,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name) share->kfile = -1; (void) mysql_file_close(new_file, MYF(MY_WME)); if (change_to_newfile(share->index_file_name, MI_NAME_IEXT, INDEX_TMP_EXT, - MYF(0)) || + no_copy_stat ? MYF(MY_REDEL_NO_COPY_STAT) : MYF(0)) || mi_open_keyfile(share)) goto err2; info->lock_type= F_UNLCK; /* Force mi_readinfo to lock */ @@ -2209,6 +2214,8 @@ err: info MyISAM handler to repair name Name of table (for warnings) rep_quick set to <> 0 if we should not change data file + no_copy_stat Don't copy file stats from old to new file, + assume that new file was created with correct stats RESULT 0 ok @@ -2216,7 +2223,7 @@ err: */ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, - const char * name, int rep_quick) + const char * name, int rep_quick, my_bool no_copy_stat) { int got_error; uint i; @@ -2543,11 +2550,15 @@ err: /* Replace the actual file with the temporary file */ if (new_file >= 0) { + myf flags= 0; + if (param->testflag & T_BACKUP_DATA) + flags |= MY_REDEL_MAKE_BACKUP; + if (no_copy_stat) + flags |= MY_REDEL_NO_COPY_STAT; mysql_file_close(new_file, MYF(0)); info->dfile=new_file= -1; if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT, - (param->testflag & T_BACKUP_DATA ? - MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || + flags) || mi_open_datafile(info,share,name,-1)) got_error=1; } @@ -2595,6 +2606,8 @@ err: info MyISAM handler to repair name Name of table (for warnings) rep_quick set to <> 0 if we should not change data file + no_copy_stat Don't copy file stats from old to new file, + assume that new file was created with correct stats DESCRIPTION Same as mi_repair_by_sort but do it multithreaded @@ -2629,7 +2642,7 @@ err: */ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, - const char * name, int rep_quick) + const char * name, int rep_quick, my_bool no_copy_stat) { int got_error; uint i,key, total_key_length, istep; @@ -3076,11 +3089,15 @@ err: /* Replace the actual file with the temporary file */ if (new_file >= 0) { + myf flags= 0; + if (param->testflag & T_BACKUP_DATA) + flags |= MY_REDEL_MAKE_BACKUP; + if (no_copy_stat) + flags |= MY_REDEL_NO_COPY_STAT; mysql_file_close(new_file, MYF(0)); info->dfile=new_file= -1; if (change_to_newfile(share->data_file_name, MI_NAME_DEXT, DATA_TMP_EXT, - (param->testflag & T_BACKUP_DATA ? - MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || + flags) || mi_open_datafile(info,share,name,-1)) got_error=1; } diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index 8606bd7c748..9360a054872 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -993,14 +993,18 @@ static int myisamchk(MI_CHECK *param, char * filename) info->s->state.key_map, param->force_sort)) { + /* + The new file might not be created with the right stats depending + on how myisamchk is run, so we must copy file stats from old to new. + */ if (param->testflag & T_REP_BY_SORT) - error=mi_repair_by_sort(param,info,filename,rep_quick); + error= mi_repair_by_sort(param, info, filename, rep_quick, FALSE); else - error=mi_repair_parallel(param,info,filename,rep_quick); + error= mi_repair_parallel(param, info, filename, rep_quick, FALSE); state_updated=1; } else if (param->testflag & T_REP_ANY) - error=mi_repair(param, info,filename,rep_quick); + error= mi_repair(param, info, filename, rep_quick, FALSE); } if (!error && param->testflag & T_SORT_RECORDS) { @@ -1040,12 +1044,12 @@ static int myisamchk(MI_CHECK *param, char * filename) { if (param->verbose) puts("Table had a compressed index; We must now recreate the index"); - error=mi_repair_by_sort(param,info,filename,1); + error= mi_repair_by_sort(param, info, filename, 1, FALSE); } } } if (!error && param->testflag & T_SORT_INDEX) - error=mi_sort_index(param,info,filename); + error= mi_sort_index(param, info, filename, FALSE); if (!error) share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED | STATE_CRASHED_ON_REPAIR); From 8dc642112c83c73969f37dbb12b9fe8f546fd42a Mon Sep 17 00:00:00 2001 From: Sivert Sorumgard Date: Mon, 22 Aug 2016 14:30:02 +0200 Subject: [PATCH 005/124] Bug#24388753: PRIVILEGE ESCALATION USING MYSQLD_SAFE [This is the 5.5/5.6 version of the bugfix]. The problem was that it was possible to write log files ending in .ini/.cnf that later could be parsed as an options file. This made it possible for users to specify startup options without the permissions to do so. This patch fixes the problem by disallowing general query log and slow query log to be written to files ending in .ini and .cnf. --- sql/log.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++++-- sql/log.h | 10 ++++++ sql/mysqld.cc | 18 +++++++++- sql/sys_vars.cc | 25 +++++++++----- 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 50d7762af6d..493aae8f2ff 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2293,6 +2293,77 @@ bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name, } +bool is_valid_log_name(const char *name, size_t len) +{ + if (len > 3) + { + const char *tail= name + len - 4; + if (my_strcasecmp(system_charset_info, tail, ".ini") == 0 || + my_strcasecmp(system_charset_info, tail, ".cnf") == 0) + { + return false; + } + } + return true; +} + + +/** + Get the real log file name, and possibly reopen file. + + Use realpath() to get the path with symbolic links + expanded. Then, close the file, and reopen the real path using the + O_NOFOLLOW flag. This will reject following symbolic links. + + @param file File descriptor. + @param log_file_key Key for P_S instrumentation. + @param open_flags Flags to use for opening the file. + @param opened_file_name Name of the open fd. + + @retval file descriptor to open file with 'real_file_name', or '-1' + in case of errors. +*/ + +#ifndef _WIN32 +static File mysql_file_real_name_reopen(File file, +#ifdef HAVE_PSI_INTERFACE + PSI_file_key log_file_key, +#endif + int open_flags, + const char *opened_file_name) +{ + DBUG_ASSERT(file); + DBUG_ASSERT(opened_file_name); + + /* Buffer for realpath must have capacity for PATH_MAX. */ + char real_file_name[PATH_MAX]; + + /* Get realpath, validate, open realpath with O_NOFOLLOW. */ + if (realpath(opened_file_name, real_file_name) == NULL) + { + (void) mysql_file_close(file, MYF(0)); + return -1; + } + + if (mysql_file_close(file, MYF(0))) + return -1; + + if (strlen(real_file_name) > FN_REFLEN) + return -1; + + if (!is_valid_log_name(real_file_name, strlen(real_file_name))) + { + sql_print_error("Invalid log file name after expanding symlinks: '%s'", + real_file_name); + return -1; + } + + return mysql_file_open(log_file_key, real_file_name, + open_flags | O_NOFOLLOW, + MYF(MY_WME | ME_WAITTANG)); +} +#endif // _WIN32 + /* Open a (new) log file. @@ -2358,8 +2429,22 @@ bool MYSQL_LOG::open( if ((file= mysql_file_open(log_file_key, log_file_name, open_flags, - MYF(MY_WME | ME_WAITTANG))) < 0 || - init_io_cache(&log_file, file, IO_SIZE, io_cache_type, + MYF(MY_WME | ME_WAITTANG))) < 0) + goto err; + +#ifndef _WIN32 + /* Reopen and validate path. */ + if ((log_type_arg == LOG_UNKNOWN || log_type_arg == LOG_NORMAL) && + (file= mysql_file_real_name_reopen(file, +#ifdef HAVE_PSI_INTERFACE + log_file_key, +#endif + open_flags, + log_file_name)) < 0) + goto err; +#endif // _WIN32 + + if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type, mysql_file_tell(file, MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP | ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0)))) diff --git a/sql/log.h b/sql/log.h index b5e751386a6..d3ecba41964 100644 --- a/sql/log.h +++ b/sql/log.h @@ -717,6 +717,16 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, char *make_log_name(char *buff, const char *name, const char* log_ext); +/** + Check given log name against certain blacklisted names/extensions. + + @param name Log name to check + @param len Length of log name + + @returns true if name is valid, false otherwise. +*/ +bool is_valid_log_name(const char *name, size_t len); + extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log; extern LOGGER logger; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a2532ceddd3..e979ea1b731 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify @@ -3512,6 +3512,22 @@ static int init_common_variables() "--log-slow-queries option, log tables are used. " "To enable logging to files use the --log-output=file option."); + if (opt_logname && + !is_valid_log_name(opt_logname, strlen(opt_logname))) + { + sql_print_error("Invalid value for --general_log_file: %s", + opt_logname); + return 1; + } + + if (opt_slow_logname && + !is_valid_log_name(opt_slow_logname, strlen(opt_slow_logname))) + { + sql_print_error("Invalid value for --slow_query_log_file: %s", + opt_slow_logname); + return 1; + } + #define FIX_LOG_VAR(VAR, ALT) \ if (!VAR || !*VAR) \ { \ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b0fa7f9a341..d08cb4f8ca8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -2810,6 +2810,14 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) if (!var->save_result.string_value.str) return true; + if (!is_valid_log_name(var->save_result.string_value.str, + var->save_result.string_value.length)) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), + self->name.str, var->save_result.string_value.str); + return true; + } + if (var->save_result.string_value.length > FN_REFLEN) { // path is too long my_error(ER_PATH_LENGTH, MYF(0), self->name.str); @@ -2856,7 +2864,7 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return false; } static bool fix_log(char** logname, const char* default_logname, - const char*ext, bool enabled, void (*reopen)(char*)) + const char*ext, bool enabled, bool (*reopen)(char*)) { if (!*logname) // SET ... = DEFAULT { @@ -2868,16 +2876,17 @@ static bool fix_log(char** logname, const char* default_logname, } logger.lock_exclusive(); mysql_mutex_unlock(&LOCK_global_system_variables); + bool error= false; if (enabled) - reopen(*logname); + error= reopen(*logname); logger.unlock(); mysql_mutex_lock(&LOCK_global_system_variables); - return false; + return error; } -static void reopen_general_log(char* name) +static bool reopen_general_log(char* name) { logger.get_log_file_handler()->close(0); - logger.get_log_file_handler()->open_query_log(name); + return logger.get_log_file_handler()->open_query_log(name); } static bool fix_general_log_file(sys_var *self, THD *thd, enum_var_type type) { @@ -2890,10 +2899,10 @@ static Sys_var_charptr Sys_general_log_path( IN_FS_CHARSET, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_log_path), ON_UPDATE(fix_general_log_file)); -static void reopen_slow_log(char* name) +static bool reopen_slow_log(char* name) { logger.get_slow_log_file_handler()->close(0); - logger.get_slow_log_file_handler()->open_slow_log(name); + return logger.get_slow_log_file_handler()->open_slow_log(name); } static bool fix_slow_log_file(sys_var *self, THD *thd, enum_var_type type) { From 55a2babcefc9a9f46534f8e6e4b5ca12d94c1105 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Fri, 19 Aug 2016 12:06:16 +0200 Subject: [PATCH 006/124] Bug#24400628: DEBUG ASSETION KICKS IN WHEN LONG SUBPARTITION NAME IS USED IN CREATE TABLE The problem was that using a very long subpartition name could lead to the server exiting abnormally. This patch fixes the problem by reporting ER_TOO_LONG_IDENT if a name with more than 64 characters are used as partition and subpartition name. --- sql/sql_yacc.yy | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b8ddc8bd49f..2ca36e23652 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4655,6 +4655,12 @@ part_name: { partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; + if (check_string_char_length(&$1, "", NAME_CHAR_LEN, + system_charset_info, true)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + MYSQL_YYABORT; + } p_elem->partition_name= $1.str; } ; @@ -4949,7 +4955,15 @@ sub_part_definition: sub_name: ident_or_text - { Lex->part_info->curr_part_elem->partition_name= $1.str; } + { + if (check_string_char_length(&$1, "", NAME_CHAR_LEN, + system_charset_info, true)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + MYSQL_YYABORT; + } + Lex->part_info->curr_part_elem->partition_name= $1.str; + } ; opt_part_options: From 97fad8518bdce19938fdf55cbb5858e31e9ac464 Mon Sep 17 00:00:00 2001 From: Kailasnath Nagarkar Date: Fri, 26 Aug 2016 11:11:27 +0530 Subject: [PATCH 007/124] Bug #23303485 : HANDLE_FATAL_SIGNAL (SIG=11) IN SUBSELECT_UNION_ENGINE::NO_ROWS This patch is specific for mysql-5.5 ISSUE: When max_join_size is used and union query results in evaluation of tuples greater than max_join_size, the join object is not created, and is set to NULL. However, this join object is further dereferenced by union logic to determine if query resulted in any number of rows being returned. Since, the object is NULL, it results in program terminating abnormally. SOLUTION: Added check to verify if join object is created. If join object is created, it will be used to determine if query resulted in any number of rows. Else, when join object is not created, we return 'false' indicating that there were no rows for the query. --- sql/item_subselect.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 43af0b5a3f6..21c897da2be 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -1789,8 +1789,12 @@ bool subselect_union_engine::is_executed() const bool subselect_union_engine::no_rows() { + bool rows_present= false; + /* Check if we got any rows when reading UNION result from temp. table: */ - return test(!unit->fake_select_lex->join->send_records); + if (unit->fake_select_lex->join) + rows_present= test(!unit->fake_select_lex->join->send_records); + return rows_present; } void subselect_uniquesubquery_engine::cleanup() From 7603ac53c86ea1a31a1511b5d630a24faf5de58c Mon Sep 17 00:00:00 2001 From: Terje Rosten Date: Fri, 26 Aug 2016 11:25:40 +0200 Subject: [PATCH 008/124] Bug#24464380 PRIVILEGE ESCALATION USING MYSQLD_SAFE Post push fix: Solaris 10 /bin/sh don't understand $(). --- scripts/mysqld_safe.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 11b692ec928..1b30a3bb15b 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -321,7 +321,7 @@ set_malloc_lib() { if [ "$malloc_lib" = tcmalloc ]; then malloc_lib= - for libdir in $(echo $malloc_dirs); do + for libdir in `echo $malloc_dirs`; do for flavor in _minimal '' _and_profiler _debug; do tmp="$libdir/libtcmalloc$flavor.so" #log_notice "DEBUG: Checking for malloc lib '$tmp'" @@ -348,7 +348,7 @@ set_malloc_lib() { fi # Restrict to a the list in $malloc_dirs above - case "$(dirname "$malloc_lib")" in + case "`dirname "$malloc_lib"`" in /usr/lib) ;; /usr/lib64) ;; /usr/lib/i386-linux-gnu) ;; From aeab9d6b417871a2893df710c690be0de53e0c7a Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Mon, 29 Aug 2016 11:41:50 +0530 Subject: [PATCH 009/124] Bug#23303391: HANDLE_FATAL_SIGNAL (SIG=11) IN ALLOC_QUERY USING CHARACTER-SET-SERVER=UTF16 This is a backport of Bug#15985752 to mysql-5.5 --- sql/mysqld.cc | 21 ++++++++++++++++++--- sql/sql_acl.cc | 10 ++++++++-- sql/sql_connect.cc | 10 +++++++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e979ea1b731..d8edbe4b637 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3482,9 +3482,24 @@ static int init_common_variables() /* Set collactions that depends on the default collation */ global_system_variables.collation_server= default_charset_info; global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; + + if (is_supported_parser_charset(default_charset_info)) + { + global_system_variables.collation_connection= default_charset_info; + global_system_variables.character_set_results= default_charset_info; + global_system_variables.character_set_client= default_charset_info; + } + else + { + sql_print_information("'%s' can not be used as client character set. " + "'%s' will be used as default client character set.", + default_charset_info->csname, + my_charset_latin1.csname); + global_system_variables.collation_connection= &my_charset_latin1; + global_system_variables.character_set_results= &my_charset_latin1; + global_system_variables.character_set_client= &my_charset_latin1; + } + if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, MY_CS_PRIMARY, MYF(MY_WME)))) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5ff6f38d18d..99394878a55 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8789,7 +8789,10 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, { mpvio->client_capabilities= uint4korr(end); mpvio->max_client_packet_length= 0xfffff; - charset_code= default_charset_info->number; + charset_code= global_system_variables.character_set_client->number; + sql_print_warning("Client failed to provide its character set. " + "'%s' will be used as client character set.", + global_system_variables.character_set_client->csname); if (mpvio->charset_adapter->init_client_charset(charset_code)) return packet_error; goto skip_to_ssl; @@ -8826,7 +8829,10 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, Old clients didn't have their own charset. Instead the assumption was that they used what ever the server used. */ - charset_code= default_charset_info->number; + charset_code= global_system_variables.character_set_client->number; + sql_print_warning("Client failed to provide its character set. " + "'%s' will be used as client character set.", + global_system_variables.character_set_client->csname); } DBUG_EXECUTE_IF("host_error_charset", { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index ed0b20a0e34..f1ee34f3d09 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -431,6 +431,14 @@ bool thd_init_client_charset(THD *thd, uint cs_number) global_system_variables.character_set_client->name, cs->name)) { + if (!is_supported_parser_charset( + global_system_variables.character_set_client)) + { + /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */ + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + global_system_variables.character_set_client->csname); + return true; + } thd->variables.character_set_client= global_system_variables.character_set_client; thd->variables.collation_connection= From 91ddaff991d745d6b2308342a2555d302a13a481 Mon Sep 17 00:00:00 2001 From: Kailasnath Nagarkar Date: Fri, 2 Sep 2016 15:13:52 +0530 Subject: [PATCH 010/124] Bug #24489302 : ZEROFILL CAUSE MEMORY-CORRUPTION AND CRASH ISSUE: Heap corruption occurs and hence mysql server terminates abnormally in String variable destructor when ZEROFILL is used for a column. Though the abnormal termination is observed in the String destructor, heap corruption occurs at earlier stage when function Field_num::prepend_zeros() is called. This function, prepends zeros to the actual data and works on entire field length. Since the allocated memory could be less than the field length, heap corruption occurs. Later, when String destructor tries to free heap, the server terminates abnormally since the heap is corrupt. SOLUTION: In Field_num::prepend_zeros() function, if allocated memory is less than the field length, re-allocate memory enough to hold field length size data. --- sql/field.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 3ca072e7771..15571afefb8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1130,12 +1130,15 @@ void Field_num::prepend_zeros(String *value) int diff; if ((diff= (int) (field_length - value->length())) > 0) { - bmove_upp((uchar*) value->ptr()+field_length, - (uchar*) value->ptr()+value->length(), - value->length()); - bfill((uchar*) value->ptr(),diff,'0'); - value->length(field_length); - (void) value->c_ptr_quick(); // Avoid warnings in purify + const bool error= value->realloc(field_length); + if (!error) + { + bmove_upp((uchar*) value->ptr()+field_length, + (uchar*) value->ptr()+value->length(), + value->length()); + bfill((uchar*) value->ptr(),diff,'0'); + value->length(field_length); + } } } From 0d43e570ba66618dbe8078e11844b11e53af22f1 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 1 Sep 2016 13:30:44 +0300 Subject: [PATCH 011/124] Bug #24496214: MISLEADING ERROR EXECUTING MYSQLADMIN SHUTDOWN AGAINST A SERVER RUNNING FIREWALL mysqladmin shutdown will try to extract the server's pid file before executing the actual shutdown command. It will do that by executing a SHOW VARIABLES query and processing the result. However if that query fails it print a (somewhat confusing) error mesasage and will still continue to do the shutdown command. If that passes then the mysqladmin user will get an error but the shutdown will still be successful. This is confusing so the error message text is changed to say that this is a non-fatal error and execution continues. No test case added since it'd require a selective query failure device that's not available in 5.5. --- client/mysqladmin.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index f0ae2c12137..c03b37ab165 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -1438,8 +1438,10 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile) if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'")) { - my_printf_error(0, "query failed; error: '%s'", error_flags, - mysql_error(mysql)); + my_printf_error(mysql_errno(mysql), + "The query to get the server's pid file failed," + " error: '%s'. Continuing.", error_flags, + mysql_error(mysql)); } result = mysql_store_result(mysql); if (result) From d933b881d4509b30899fee4b4eaa4466c38efeca Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 26 Sep 2016 14:42:56 +0200 Subject: [PATCH 012/124] Raise version number after cloning 5.5.53 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d44c8b28006..4f1ecb3a197 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=53 +MYSQL_VERSION_PATCH=54 MYSQL_VERSION_EXTRA= From 99c0fdb5a8af4104efed6ea47df850abf4c59530 Mon Sep 17 00:00:00 2001 From: Robert Golebiowski Date: Tue, 27 Sep 2016 11:17:38 +0200 Subject: [PATCH 013/124] Bug #24740291: YASSL UPDATE TO 2.4.2 --- extra/yassl/README | 18 +++ extra/yassl/certs/dsa-cert.pem | 38 ++--- extra/yassl/include/openssl/ssl.h | 2 +- extra/yassl/src/ssl.cpp | 60 +++++--- extra/yassl/taocrypt/include/aes.hpp | 58 ++++++++ extra/yassl/taocrypt/include/integer.hpp | 3 + extra/yassl/taocrypt/src/aes.cpp | 172 ++++++++++++++--------- extra/yassl/taocrypt/src/asn.cpp | 24 ++-- extra/yassl/taocrypt/src/dsa.cpp | 16 ++- extra/yassl/taocrypt/test/test.cpp | 3 + extra/yassl/testsuite/test.hpp | 2 +- 11 files changed, 274 insertions(+), 122 deletions(-) diff --git a/extra/yassl/README b/extra/yassl/README index b5eb88824fb..a3d4f60f561 100644 --- a/extra/yassl/README +++ b/extra/yassl/README @@ -12,6 +12,24 @@ before calling SSL_new(); *** end Note *** +yaSSL Release notes, version 2.4.2 (9/22/2016) + This release of yaSSL fixes a medium security vulnerability. A fix for + potential AES side channel leaks is included that a local user monitoring + the same CPU core cache could exploit. VM users, hyper-threading users, + and users where potential attackers have access to the CPU cache will need + to update if they utilize AES. + + DSA padding fixes for unusual sizes is included as well. Users with DSA + certficiates should update. + +yaSSL Release notes, version 2.4.0 (5/20/2016) + This release of yaSSL fixes the OpenSSL compatibility function + SSL_CTX_load_verify_locations() when using the path directory to allow + unlimited path sizes. Minor Windows build fixes are included. + No high level security fixes in this version but we always recommend + updating. + + yaSSL Release notes, version 2.3.9b (2/03/2016) This release of yaSSL fixes the OpenSSL compatibility function X509_NAME_get_index_by_NID() to use the actual index of the common name diff --git a/extra/yassl/certs/dsa-cert.pem b/extra/yassl/certs/dsa-cert.pem index 10d533edc88..10794cbee73 100644 --- a/extra/yassl/certs/dsa-cert.pem +++ b/extra/yassl/certs/dsa-cert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDqzCCA2ugAwIBAgIJAMGqrgDU6DyhMAkGByqGSM44BAMwgY4xCzAJBgNVBAYT +MIIDrzCCA2+gAwIBAgIJAK1zRM7YFcNjMAkGByqGSM44BAMwgZAxCzAJBgNVBAYT AlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQK -DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wu -Y29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTEzMDQyMjIw -MDk0NFoXDTE2MDExNzIwMDk0NFowgY4xCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZP -cmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMRAwDgYDVQQKDAd3b2xmU1NMMRAwDgYD -VQQLDAd0ZXN0aW5nMRYwFAYDVQQDDA13d3cueWFzc2wuY29tMR8wHQYJKoZIhvcN -AQkBFhBpbmZvQHdvbGZzc2wuY29tMIIBuDCCASwGByqGSM44BAEwggEfAoGBAL1R -7koy4IrH6sbh6nDEUUPPKgfhxxLCWCVexF2+qzANEr+hC9M002haJXFOfeS9DyoO -WFbL0qMZOuqv+22CaHnoUWl7q3PjJOAI3JH0P54ZyUPuU1909RzgTdIDp5+ikbr7 -KYjnltL73FQVMbjTZQKthIpPn3MjYcF+4jp2W2zFAhUAkcntYND6MGf+eYzIJDN2 -L7SonHUCgYEAklpxErfqznIZjVvqqHFaq+mgAL5J8QrKVmdhYZh/Y8z4jCjoCA8o -TDoFKxf7s2ZzgaPKvglaEKiYqLqic9qY78DYJswzQMLFvjsF4sFZ+pYCBdWPQI4N -PgxCiznK6Ce+JH9ikSBvMvG+tevjr2UpawDIHX3+AWYaZBZwKADAaboDgYUAAoGB -AJ3LY89yHyvQ/TsQ6zlYbovjbk/ogndsMqPdNUvL4RuPTgJP/caaDDa0XJ7ak6A7 -TJ+QheLNwOXoZPYJC4EGFSDAXpYniGhbWIrVTCGe6lmZDfnx40WXS0kk3m/DHaC0 -3ElLAiybxVGxyqoUfbT3Zv1JwftWMuiqHH5uADhdXuXVo1AwTjAdBgNVHQ4EFgQU -IJjk416o4v8qpH9LBtXlR9v8gccwHwYDVR0jBBgwFoAUIJjk416o4v8qpH9LBtXl -R9v8gccwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFCjGKIdOSV12LcTu -k08owGM6YkO1AhQe+K173VuaO/OsDNsxZlKpyH8+1g== +DAd3b2xmU1NMMRAwDgYDVQQLDAd0ZXN0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMTYwOTIy +MjEyMzA0WhcNMjIwMzE1MjEyMzA0WjCBkDELMAkGA1UEBhMCVVMxDzANBgNVBAgM +Bk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB3Rlc3RpbmcxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCAbgwggEsBgcqhkjOOAQBMIIBHwKB +gQC9Ue5KMuCKx+rG4epwxFFDzyoH4ccSwlglXsRdvqswDRK/oQvTNNNoWiVxTn3k +vQ8qDlhWy9KjGTrqr/ttgmh56FFpe6tz4yTgCNyR9D+eGclD7lNfdPUc4E3SA6ef +opG6+ymI55bS+9xUFTG402UCrYSKT59zI2HBfuI6dltsxQIVAJHJ7WDQ+jBn/nmM +yCQzdi+0qJx1AoGBAJJacRK36s5yGY1b6qhxWqvpoAC+SfEKylZnYWGYf2PM+Iwo +6AgPKEw6BSsX+7Nmc4Gjyr4JWhComKi6onPamO/A2CbMM0DCxb47BeLBWfqWAgXV +j0CODT4MQos5yugnviR/YpEgbzLxvrXr469lKWsAyB19/gFmGmQWcCgAwGm6A4GF +AAKBgQCdy2PPch8r0P07EOs5WG6L425P6IJ3bDKj3TVLy+Ebj04CT/3Gmgw2tFye +2pOgO0yfkIXizcDl6GT2CQuBBhUgwF6WJ4hoW1iK1UwhnupZmQ358eNFl0tJJN5v +wx2gtNxJSwIsm8VRscqqFH2092b9ScH7VjLoqhx+bgA4XV7l1aNQME4wHQYDVR0O +BBYEFCCY5ONeqOL/KqR/SwbV5Ufb/IHHMB8GA1UdIwQYMBaAFCCY5ONeqOL/KqR/ +SwbV5Ufb/IHHMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwMvADAsAhQRYSCVN/Ge +agV3mffU3qNZ92fI0QIUPH7Jp+iASI7U1ocaYDc10qXGaGY= -----END CERTIFICATE----- diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h index 83daf3cc81f..0609dfc0592 100644 --- a/extra/yassl/include/openssl/ssl.h +++ b/extra/yassl/include/openssl/ssl.h @@ -35,7 +35,7 @@ #include "rsa.h" -#define YASSL_VERSION "2.3.9b" +#define YASSL_VERSION "2.4.2" #if defined(__cplusplus) diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp index cde32df4f43..1925e2f7592 100644 --- a/extra/yassl/src/ssl.cpp +++ b/extra/yassl/src/ssl.cpp @@ -161,7 +161,7 @@ int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) TaoCrypt::DSA_PrivateKey dsaKey; dsaKey.Initialize(dsaSource); - if (rsaSource.GetError().What()) { + if (dsaSource.GetError().What()) { // neither worked ret = SSL_FAILURE; } @@ -784,40 +784,67 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, WIN32_FIND_DATA FindFileData; HANDLE hFind; - char name[MAX_PATH + 1]; // directory specification - strncpy(name, path, MAX_PATH - 3); - strncat(name, "\\*", 3); + const int DELIMITER_SZ = 2; + const int DELIMITER_STAR_SZ = 3; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_STAR_SZ + 1; // plus 1 for terminator + char* name = NEW_YS char[nameSz]; // directory specification + memset(name, 0, nameSz); + strncpy(name, path, nameSz - DELIMITER_STAR_SZ - 1); + strncat(name, "\\*", DELIMITER_STAR_SZ); hFind = FindFirstFile(name, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) return SSL_BAD_PATH; + if (hFind == INVALID_HANDLE_VALUE) { + ysArrayDelete(name); + return SSL_BAD_PATH; + } do { - if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { - strncpy(name, path, MAX_PATH - 2 - HALF_PATH); - strncat(name, "\\", 2); - strncat(name, FindFileData.cFileName, HALF_PATH); + if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + int curSz = (int)strlen(FindFileData.cFileName); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + // plus 1 for terminator + nameSz = pathSz + curSz + DELIMITER_SZ + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - DELIMITER_SZ - 1); + strncat(name, "\\", DELIMITER_SZ); + strncat(name, FindFileData.cFileName, + nameSz - pathSz - DELIMITER_SZ - 1); ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } } while (ret == SSL_SUCCESS && FindNextFile(hFind, &FindFileData)); + ysArrayDelete(name); FindClose(hFind); #else // _WIN32 - - const int MAX_PATH = 260; - DIR* dir = opendir(path); if (!dir) return SSL_BAD_PATH; struct dirent* entry; struct stat buf; - char name[MAX_PATH + 1]; + const int DELIMITER_SZ = 1; + int pathSz = (int)strlen(path); + int nameSz = pathSz + DELIMITER_SZ + 1; //plus 1 for null terminator + char* name = NEW_YS char[nameSz]; // directory specification while (ret == SSL_SUCCESS && (entry = readdir(dir))) { - strncpy(name, path, MAX_PATH - 1 - HALF_PATH); - strncat(name, "/", 1); - strncat(name, entry->d_name, HALF_PATH); + int curSz = (int)strlen(entry->d_name); + if (pathSz + curSz + DELIMITER_SZ + 1 > nameSz) { + ysArrayDelete(name); + nameSz = pathSz + DELIMITER_SZ + curSz + 1; + name = NEW_YS char[nameSz]; + } + memset(name, 0, nameSz); + strncpy(name, path, nameSz - curSz - 1); + strncat(name, "/", DELIMITER_SZ); + strncat(name, entry->d_name, nameSz - pathSz - DELIMITER_SZ - 1); + if (stat(name, &buf) < 0) { + ysArrayDelete(name); closedir(dir); return SSL_BAD_STAT; } @@ -826,6 +853,7 @@ int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, ret = read_file(ctx, name, SSL_FILETYPE_PEM, CA); } + ysArrayDelete(name); closedir(dir); #endif diff --git a/extra/yassl/taocrypt/include/aes.hpp b/extra/yassl/taocrypt/include/aes.hpp index 01763033156..bccf6e73fc7 100644 --- a/extra/yassl/taocrypt/include/aes.hpp +++ b/extra/yassl/taocrypt/include/aes.hpp @@ -60,6 +60,7 @@ private: static const word32 Te[5][256]; static const word32 Td[5][256]; + static const byte CTd4[256]; static const word32* Te0; static const word32* Te1; @@ -80,11 +81,68 @@ private: void ProcessAndXorBlock(const byte*, const byte*, byte*) const; + word32 PreFetchTe() const; + word32 PreFetchTd() const; + word32 PreFetchCTd4() const; + AES(const AES&); // hide copy AES& operator=(const AES&); // and assign }; +#if defined(__x86_64__) || defined(_M_X64) || \ + (defined(__ILP32__) && (__ILP32__ >= 1)) + #define TC_CACHE_LINE_SZ 64 +#else + /* default cache line size */ + #define TC_CACHE_LINE_SZ 32 +#endif + +inline word32 AES::PreFetchTe() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Te[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchTd() const +{ + word32 x = 0; + + /* 4 tables of 256 entries */ + for (int i = 0; i < 4; i++) { + /* each entry is 4 bytes */ + for (int j = 0; j < 256; j += TC_CACHE_LINE_SZ/4) { + x &= Td[i][j]; + } + } + + return x; +} + + +inline word32 AES::PreFetchCTd4() const +{ + word32 x = 0; + int i; + + for (i = 0; i < 256; i += TC_CACHE_LINE_SZ) { + x &= CTd4[i]; + } + + return x; +} + + typedef BlockCipher AES_ECB_Encryption; typedef BlockCipher AES_ECB_Decryption; diff --git a/extra/yassl/taocrypt/include/integer.hpp b/extra/yassl/taocrypt/include/integer.hpp index 75a3ee3d3df..05fe189fd58 100644 --- a/extra/yassl/taocrypt/include/integer.hpp +++ b/extra/yassl/taocrypt/include/integer.hpp @@ -119,6 +119,9 @@ namespace TaoCrypt { +#ifdef _WIN32 + #undef max // avoid name clash +#endif // general MAX template inline const T& max(const T& a, const T& b) diff --git a/extra/yassl/taocrypt/src/aes.cpp b/extra/yassl/taocrypt/src/aes.cpp index ee4c7a6e8a1..3fcf80ac202 100644 --- a/extra/yassl/taocrypt/src/aes.cpp +++ b/extra/yassl/taocrypt/src/aes.cpp @@ -109,10 +109,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[3]; rk[4] = rk[0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; @@ -128,10 +128,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; @@ -149,10 +149,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ - (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + (Te2[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 3)] & 0x000000ff) ^ rcon_[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; @@ -161,10 +161,10 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) break; temp = rk[11]; rk[12] = rk[ 4] ^ - (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ - (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(temp, 0)] & 0x000000ff); + (Te2[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te3[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(temp, 0)] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; @@ -191,25 +191,25 @@ void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) for (i = 1; i < rounds_; i++) { rk += 4; rk[0] = - Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[0], 0)] & 0xff]; rk[1] = - Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[1], 0)] & 0xff]; rk[2] = - Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[2], 0)] & 0xff]; rk[3] = - Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ - Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ - Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ - Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + Td0[Te1[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te1[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te1[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te1[GETBYTE(rk[3], 0)] & 0xff]; } } } @@ -244,6 +244,7 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, s2 ^= rk[2]; s3 ^= rk[3]; + s0 |= PreFetchTe(); /* * Nr - 1 full rounds: */ @@ -312,28 +313,28 @@ void AES::encrypt(const byte* inBlock, const byte* xorBlock, */ s0 = - (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t3, 0)] & 0x000000ff) ^ rk[0]; s1 = - (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t0, 0)] & 0x000000ff) ^ rk[1]; s2 = - (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t1, 0)] & 0x000000ff) ^ rk[2]; s3 = - (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + (Te2[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te3[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te0[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te1[GETBYTE(t2, 0)] & 0x000000ff) ^ rk[3]; @@ -358,6 +359,8 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, s2 ^= rk[2]; s3 ^= rk[3]; + s0 |= PreFetchTd(); + /* * Nr - 1 full rounds: */ @@ -423,29 +426,32 @@ void AES::decrypt(const byte* inBlock, const byte* xorBlock, * apply last round and * map cipher state to byte array block: */ + + t0 |= PreFetchCTd4(); + s0 = - (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t0, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t3, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t2, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t1, 0)]) ^ rk[0]; s1 = - (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t1, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t0, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t3, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t2, 0)]) ^ rk[1]; s2 = - (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t2, 3)] << 24 ) ^ + ((word32)CTd4[GETBYTE(t1, 2)] << 16 ) ^ + ((word32)CTd4[GETBYTE(t0, 1)] << 8 ) ^ + ((word32)CTd4[GETBYTE(t3, 0)]) ^ rk[2]; s3 = - (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ - (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ - (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ - (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + ((word32)CTd4[GETBYTE(t3, 3)] << 24) ^ + ((word32)CTd4[GETBYTE(t2, 2)] << 16) ^ + ((word32)CTd4[GETBYTE(t1, 1)] << 8) ^ + ((word32)CTd4[GETBYTE(t0, 0)]) ^ rk[3]; gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); @@ -1826,18 +1832,52 @@ const word32 AES::Td[5][256] = { } }; +const byte AES::CTd4[256] = +{ + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; + const word32* AES::Te0 = AES::Te[0]; const word32* AES::Te1 = AES::Te[1]; const word32* AES::Te2 = AES::Te[2]; const word32* AES::Te3 = AES::Te[3]; -const word32* AES::Te4 = AES::Te[4]; const word32* AES::Td0 = AES::Td[0]; const word32* AES::Td1 = AES::Td[1]; const word32* AES::Td2 = AES::Td[2]; const word32* AES::Td3 = AES::Td[3]; -const word32* AES::Td4 = AES::Td[4]; diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp index a210d805452..7ff3c7167d2 100644 --- a/extra/yassl/taocrypt/src/asn.cpp +++ b/extra/yassl/taocrypt/src/asn.cpp @@ -1209,17 +1209,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 rLen = GetLength(source); if (rLen != 20) { - if (rLen == 21) { // zero at front, eat + while (rLen > 20 && source.remaining() > 0) { // zero's at front, eat source.next(); --rLen; } - else if (rLen == 19) { // add zero to front so 20 bytes + if (rLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = rLen; + while (tmpLen < 20) { decoded[0] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded, source.get_buffer() + source.get_index(), rLen); @@ -1232,17 +1232,17 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) } word32 sLen = GetLength(source); if (sLen != 20) { - if (sLen == 21) { - source.next(); // zero at front, eat + while (sLen > 20 && source.remaining() > 0) { + source.next(); // zero's at front, eat --sLen; } - else if (sLen == 19) { - decoded[rLen] = 0; // add zero to front so 20 bytes + if (sLen < 20) { // add zero's to front so 20 bytes + word32 tmpLen = sLen; + while (tmpLen < 20) { + decoded[rLen] = 0; decoded++; + tmpLen++; } - else { - source.SetError(DSA_SZ_E); - return 0; } } memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen); diff --git a/extra/yassl/taocrypt/src/dsa.cpp b/extra/yassl/taocrypt/src/dsa.cpp index bf116d3e48d..b19fed9235b 100644 --- a/extra/yassl/taocrypt/src/dsa.cpp +++ b/extra/yassl/taocrypt/src/dsa.cpp @@ -172,6 +172,7 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, const Integer& q = key_.GetSubGroupOrder(); const Integer& g = key_.GetSubGroupGenerator(); const Integer& x = key_.GetPrivatePart(); + byte* tmpPtr = sig; // initial signature output Integer k(rng, 1, q - 1); @@ -187,22 +188,23 @@ word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, return -1; int rSz = r_.ByteCount(); + int tmpSz = rSz; - if (rSz == 19) { - sig[0] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } r_.Encode(sig, rSz); + sig = tmpPtr + SHA::DIGEST_SIZE; // advance sig output to s int sSz = s_.ByteCount(); + tmpSz = sSz; - if (sSz == 19) { - sig[rSz] = 0; - sig++; + while (tmpSz++ < SHA::DIGEST_SIZE) { + *sig++ = 0; } - s_.Encode(sig + rSz, sSz); + s_.Encode(sig, sSz); return 40; } diff --git a/extra/yassl/taocrypt/test/test.cpp b/extra/yassl/taocrypt/test/test.cpp index a7d5cb3e8af..fc1f0e8762d 100644 --- a/extra/yassl/taocrypt/test/test.cpp +++ b/extra/yassl/taocrypt/test/test.cpp @@ -1277,6 +1277,9 @@ int dsa_test() if (!verifier.Verify(digest, decoded)) return -90; + if (!verifier.Verify(digest, signature)) + return -91; + return 0; } diff --git a/extra/yassl/testsuite/test.hpp b/extra/yassl/testsuite/test.hpp index 5c9dc7ce117..e2e44c24027 100644 --- a/extra/yassl/testsuite/test.hpp +++ b/extra/yassl/testsuite/test.hpp @@ -22,7 +22,6 @@ #define yaSSL_TEST_HPP #include "runtime.hpp" -#include "openssl/ssl.h" /* openssl compatibility test */ #include "error.hpp" #include #include @@ -56,6 +55,7 @@ #endif #define SOCKET_T int #endif /* _WIN32 */ +#include "openssl/ssl.h" /* openssl compatibility test */ #ifdef _MSC_VER From ac143744a90d1069f0b4f8a47516cdcca915fbfa Mon Sep 17 00:00:00 2001 From: Arun Kuruvila Date: Wed, 28 Sep 2016 15:52:05 +0530 Subject: [PATCH 014/124] Bug#24707666: DEFAULT SETTING FOR SECURE-FILE-PRIV SHOULD BE RESTRICTED IN ALL GA RELEASES Back port of WL#6782 to 5.5 and 5.6. This also includes back port of Bug#20771331, Bug#20741572 and Bug#20770671. Bug#24695274 and Bug#24679907 are also handled along with this. --- cmake/install_layout.cmake | 256 +++++++++++++++++- config.h.cmake | 4 + mysql-test/include/mtr_warnings.sql | 7 +- mysql-test/include/mysqld--help.inc | 3 +- mysql-test/mysql-test-run.pl | 4 +- mysql-test/r/mysqld--help-notwin.result | 1 - mysql-test/r/mysqld--help-win.result | 1 - .../auth_sec/r/secure_file_priv_error.result | 7 + .../auth_sec/r/secure_file_priv_null.result | 21 ++ .../r/secure_file_priv_warnings.result | 17 ++ .../secure_file_priv_warnings_not_win.result | 9 + .../r/secure_file_priv_warnings_win.result | 8 + .../auth_sec/t/secure_file_priv_error.test | 39 +++ .../t/secure_file_priv_null-master.opt | 1 + .../auth_sec/t/secure_file_priv_null.test | 42 +++ .../t/secure_file_priv_warnings-master.opt | 1 + .../auth_sec/t/secure_file_priv_warnings.test | 47 ++++ .../t/secure_file_priv_warnings_not_win.test | 24 ++ .../t/secure_file_priv_warnings_win.test | 35 +++ packaging/rpm-oel/mysql-systemd-start | 6 + packaging/rpm-oel/mysql.init | 10 +- packaging/rpm-oel/mysql.spec.in | 5 + packaging/rpm-sles/mysql.spec.in | 5 + packaging/solaris/postinstall-solaris.sh | 8 +- sql/mysqld.cc | 252 +++++++++++++++-- sql/sql_class.cc | 2 + sql/sql_class.h | 1 + sql/sys_vars.cc | 8 +- support-files/mysql.spec.sh | 7 +- 29 files changed, 790 insertions(+), 41 deletions(-) create mode 100644 mysql-test/suite/auth_sec/r/secure_file_priv_error.result create mode 100644 mysql-test/suite/auth_sec/r/secure_file_priv_null.result create mode 100644 mysql-test/suite/auth_sec/r/secure_file_priv_warnings.result create mode 100644 mysql-test/suite/auth_sec/r/secure_file_priv_warnings_not_win.result create mode 100644 mysql-test/suite/auth_sec/r/secure_file_priv_warnings_win.result create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_error.test create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_null-master.opt create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_null.test create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_warnings-master.opt create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_warnings.test create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_warnings_not_win.test create mode 100644 mysql-test/suite/auth_sec/t/secure_file_priv_warnings_win.test diff --git a/cmake/install_layout.cmake b/cmake/install_layout.cmake index 4adda0b6eac..4fd18b049f2 100644 --- a/cmake/install_layout.cmake +++ b/cmake/install_layout.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -22,7 +22,7 @@ # and relative links. Windows zip uses the same tarball layout but without # the build prefix. # -# RPM +# RPM, SLES # Build as per default RPM layout, with prefix=/usr # Note: The layout for ULN RPMs differs, see the "RPM" section. # @@ -32,10 +32,22 @@ # SVR4 # Solaris package layout suitable for pkg* tools, prefix=/opt/mysql/mysql # +# FREEBSD, GLIBC, OSX, TARGZ +# Build with prefix=/usr/local/mysql, create tarball with install prefix="." +# and relative links. +# +# WIN +# Windows zip : same as tarball layout but without the build prefix +# # To force a directory layout, use -DINSTALL_LAYOUT=. # # The default is STANDALONE. # +# Note : At present, RPM and SLES layouts are similar. This is also true +# for layouts like FREEBSD, GLIBC, OSX, TARGZ. However, they provide +# opportunity to fine-tune deployment for each platform without +# affecting all other types of deployment. +# # There is the possibility to further fine-tune installation directories. # Several variables can be overwritten: # @@ -60,6 +72,7 @@ # - INSTALL_SUPPORTFILESDIR (various extra support files) # # - INSTALL_MYSQLDATADIR (data directory) +# - INSTALL_SECURE_FILE_PRIVDIR (--secure-file-priv directory) # # When changing this page, _please_ do not forget to update public Wiki # http://forge.mysql.com/wiki/CMake#Fine-tuning_installation_paths @@ -69,10 +82,11 @@ IF(NOT INSTALL_LAYOUT) ENDIF() SET(INSTALL_LAYOUT "${DEFAULT_INSTALL_LAYOUT}" -CACHE STRING "Installation directory layout. Options are: STANDALONE (as in zip or tar.gz installer), RPM, DEB, SVR4") +CACHE STRING "Installation directory layout. Options are: TARGZ (as in tar.gz installer), WIN (as in zip installer), STANDALONE, RPM, DEB, SVR4, FREEBSD, GLIBC, OSX, SLES") IF(UNIX) - IF(INSTALL_LAYOUT MATCHES "RPM") + IF(INSTALL_LAYOUT MATCHES "RPM" OR + INSTALL_LAYOUT MATCHES "SLES") SET(default_prefix "/usr") ELSEIF(INSTALL_LAYOUT MATCHES "DEB") SET(default_prefix "/opt/mysql/server-${MYSQL_BASE_VERSION}") @@ -87,7 +101,7 @@ IF(UNIX) SET(CMAKE_INSTALL_PREFIX ${default_prefix} CACHE PATH "install prefix" FORCE) ENDIF() - SET(VALID_INSTALL_LAYOUTS "RPM" "STANDALONE" "DEB" "SVR4") + SET(VALID_INSTALL_LAYOUTS "RPM" "DEB" "SVR4" "FREEBSD" "GLIBC" "OSX" "TARGZ" "SLES" "STANDALONE") LIST(FIND VALID_INSTALL_LAYOUTS "${INSTALL_LAYOUT}" ind) IF(ind EQUAL -1) MESSAGE(FATAL_ERROR "Invalid INSTALL_LAYOUT parameter:${INSTALL_LAYOUT}." @@ -99,6 +113,15 @@ IF(UNIX) MARK_AS_ADVANCED(SYSCONFDIR) ENDIF() +IF(WIN32) + SET(VALID_INSTALL_LAYOUTS "TARGZ" "STANDALONE" "WIN") + LIST(FIND VALID_INSTALL_LAYOUTS "${INSTALL_LAYOUT}" ind) + IF(ind EQUAL -1) + MESSAGE(FATAL_ERROR "Invalid INSTALL_LAYOUT parameter:${INSTALL_LAYOUT}." + " Choose between ${VALID_INSTALL_LAYOUTS}" ) + ENDIF() +ENDIF() + # # plugin_tests's value should not be used by imported plugins, # just use if(INSTALL_PLUGINTESTDIR). @@ -109,6 +132,22 @@ FILE(GLOB plugin_tests ${CMAKE_SOURCE_DIR}/internal/plugin/*/tests ) +# +# DEFAULT_SECURE_FILE_PRIV_DIR/DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR +# +IF(INSTALL_LAYOUT MATCHES "STANDALONE" OR + INSTALL_LAYOUT MATCHES "WIN") + SET(secure_file_priv_path "NULL") +ELSEIF(INSTALL_LAYOUT MATCHES "RPM" OR + INSTALL_LAYOUT MATCHES "SLES" OR + INSTALL_LAYOUT MATCHES "SVR4" OR + INSTALL_LAYOUT MATCHES "DEB") + SET(secure_file_priv_path "/var/lib/mysql-files") +ELSE() + SET(secure_file_priv_path "${default_prefix}/mysql-files") +ENDIF() +SET(secure_file_priv_embedded_path "NULL") + # # STANDALONE layout # @@ -134,6 +173,148 @@ SET(INSTALL_SUPPORTFILESDIR_STANDALONE "support-files") # SET(INSTALL_MYSQLDATADIR_STANDALONE "data") SET(INSTALL_PLUGINTESTDIR_STANDALONE ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_STANDALONE ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_STANDALONE ${secure_file_priv_embedded_path}) + +# +# WIN layout +# +SET(INSTALL_BINDIR_WIN "bin") +SET(INSTALL_SBINDIR_WIN "bin") +SET(INSTALL_SCRIPTDIR_WIN "scripts") +# +SET(INSTALL_LIBDIR_WIN "lib") +SET(INSTALL_PLUGINDIR_WIN "lib/plugin") +# +SET(INSTALL_INCLUDEDIR_WIN "include") +# +SET(INSTALL_DOCDIR_WIN "docs") +SET(INSTALL_DOCREADMEDIR_WIN ".") +SET(INSTALL_MANDIR_WIN "man") +SET(INSTALL_INFODIR_WIN "docs") +# +SET(INSTALL_SHAREDIR_WIN "share") +SET(INSTALL_MYSQLSHAREDIR_WIN "share") +SET(INSTALL_MYSQLTESTDIR_WIN "mysql-test") +SET(INSTALL_SQLBENCHDIR_WIN ".") +SET(INSTALL_SUPPORTFILESDIR_WIN "support-files") +# +SET(INSTALL_MYSQLDATADIR_WIN "data") +SET(INSTALL_PLUGINTESTDIR_WIN ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_WIN ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_WIN ${secure_file_priv_embedded_path}) + +# +# FREEBSD layout +# +SET(INSTALL_BINDIR_FREEBSD "bin") +SET(INSTALL_SBINDIR_FREEBSD "bin") +SET(INSTALL_SCRIPTDIR_FREEBSD "scripts") +# +SET(INSTALL_LIBDIR_FREEBSD "lib") +SET(INSTALL_PLUGINDIR_FREEBSD "lib/plugin") +# +SET(INSTALL_INCLUDEDIR_FREEBSD "include") +# +SET(INSTALL_DOCDIR_FREEBSD "docs") +SET(INSTALL_DOCREADMEDIR_FREEBSD ".") +SET(INSTALL_MANDIR_FREEBSD "man") +SET(INSTALL_INFODIR_FREEBSD "docs") +# +SET(INSTALL_SHAREDIR_FREEBSD "share") +SET(INSTALL_MYSQLSHAREDIR_FREEBSD "share") +SET(INSTALL_MYSQLTESTDIR_FREEBSD "mysql-test") +SET(INSTALL_SQLBENCHDIR_FREEBSD ".") +SET(INSTALL_SUPPORTFILESDIR_FREEBSD "support-files") +# +SET(INSTALL_MYSQLDATADIR_FREEBSD "data") +SET(INSTALL_PLUGINTESTDIR_FREEBSD ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_FREEBSD ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_FREEBSD ${secure_file_priv_embedded_path}) + +# +# GLIBC layout +# +SET(INSTALL_BINDIR_GLIBC "bin") +SET(INSTALL_SBINDIR_GLIBC "bin") +SET(INSTALL_SCRIPTDIR_GLIBC "scripts") +# +SET(INSTALL_LIBDIR_GLIBC "lib") +SET(INSTALL_PLUGINDIR_GLIBC "lib/plugin") +# +SET(INSTALL_INCLUDEDIR_GLIBC "include") +# +SET(INSTALL_DOCDIR_GLIBC "docs") +SET(INSTALL_DOCREADMEDIR_GLIBC ".") +SET(INSTALL_MANDIR_GLIBC "man") +SET(INSTALL_INFODIR_GLIBC "docs") +# +SET(INSTALL_SHAREDIR_GLIBC "share") +SET(INSTALL_MYSQLSHAREDIR_GLIBC "share") +SET(INSTALL_MYSQLTESTDIR_GLIBC "mysql-test") +SET(INSTALL_SQLBENCHDIR_GLIBC ".") +SET(INSTALL_SUPPORTFILESDIR_GLIBC "support-files") +# +SET(INSTALL_MYSQLDATADIR_GLIBC "data") +SET(INSTALL_PLUGINTESTDIR_GLIBC ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_GLIBC ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_GLIBC ${secure_file_priv_embedded_path}) + +# +# OSX layout +# +SET(INSTALL_BINDIR_OSX "bin") +SET(INSTALL_SBINDIR_OSX "bin") +SET(INSTALL_SCRIPTDIR_OSX "scripts") +# +SET(INSTALL_LIBDIR_OSX "lib") +SET(INSTALL_PLUGINDIR_OSX "lib/plugin") +# +SET(INSTALL_INCLUDEDIR_OSX "include") +# +SET(INSTALL_DOCDIR_OSX "docs") +SET(INSTALL_DOCREADMEDIR_OSX ".") +SET(INSTALL_MANDIR_OSX "man") +SET(INSTALL_INFODIR_OSX "docs") +# +SET(INSTALL_SHAREDIR_OSX "share") +SET(INSTALL_MYSQLSHAREDIR_OSX "share") +SET(INSTALL_MYSQLTESTDIR_OSX "mysql-test") +SET(INSTALL_SQLBENCHDIR_OSX ".") +SET(INSTALL_SUPPORTFILESDIR_OSX "support-files") +# +SET(INSTALL_MYSQLDATADIR_OSX "data") +SET(INSTALL_PLUGINTESTDIR_OSX ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_OSX ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_OSX ${secure_file_priv_embedded_path}) + +# +# TARGZ layout +# +SET(INSTALL_BINDIR_TARGZ "bin") +SET(INSTALL_SBINDIR_TARGZ "bin") +SET(INSTALL_SCRIPTDIR_TARGZ "scripts") +# +SET(INSTALL_LIBDIR_TARGZ "lib") +SET(INSTALL_PLUGINDIR_TARGZ "lib/plugin") +# +SET(INSTALL_INCLUDEDIR_TARGZ "include") +# +SET(INSTALL_DOCDIR_TARGZ "docs") +SET(INSTALL_DOCREADMEDIR_TARGZ ".") +SET(INSTALL_MANDIR_TARGZ "man") +SET(INSTALL_INFODIR_TARGZ "docs") +# +SET(INSTALL_SHAREDIR_TARGZ "share") +SET(INSTALL_MYSQLSHAREDIR_TARGZ "share") +SET(INSTALL_MYSQLTESTDIR_TARGZ "mysql-test") +SET(INSTALL_SQLBENCHDIR_TARGZ ".") +SET(INSTALL_SUPPORTFILESDIR_TARGZ "support-files") +# +SET(INSTALL_MYSQLDATADIR_TARGZ "data") +SET(INSTALL_PLUGINTESTDIR_TARGZ ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_TARGZ ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_TARGZ ${secure_file_priv_embedded_path}) # # RPM layout @@ -169,6 +350,41 @@ SET(INSTALL_SUPPORTFILESDIR_RPM "share/mysql") # SET(INSTALL_MYSQLDATADIR_RPM "/var/lib/mysql") SET(INSTALL_PLUGINTESTDIR_RPM ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_RPM ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_RPM ${secure_file_priv_embedded_path}) + +# +# SLES layout +# +SET(INSTALL_BINDIR_SLES "bin") +SET(INSTALL_SBINDIR_SLES "sbin") +SET(INSTALL_SCRIPTDIR_SLES "bin") +# +IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + SET(INSTALL_LIBDIR_SLES "lib64") + SET(INSTALL_PLUGINDIR_SLES "lib64/mysql/plugin") +ELSE() + SET(INSTALL_LIBDIR_SLES "lib") + SET(INSTALL_PLUGINDIR_SLES "lib/mysql/plugin") +ENDIF() +# +SET(INSTALL_INCLUDEDIR_SLES "include/mysql") +# +#SET(INSTALL_DOCDIR_SLES unset - installed directly by SLES) +#SET(INSTALL_DOCREADMEDIR_SLES unset - installed directly by SLES) +SET(INSTALL_INFODIR_SLES "share/info") +SET(INSTALL_MANDIR_SLES "share/man") +# +SET(INSTALL_SHAREDIR_SLES "share") +SET(INSTALL_MYSQLSHAREDIR_SLES "share/mysql") +SET(INSTALL_MYSQLTESTDIR_SLES "share/mysql-test") +SET(INSTALL_SQLBENCHDIR_SLES "") +SET(INSTALL_SUPPORTFILESDIR_SLES "share/mysql") +# +SET(INSTALL_MYSQLDATADIR_SLES "/var/lib/mysql") +SET(INSTALL_PLUGINTESTDIR_SLES ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_SLES ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_SLES ${secure_file_priv_embedded_path}) # # DEB layout @@ -193,8 +409,10 @@ SET(INSTALL_MYSQLTESTDIR_DEB "mysql-test") SET(INSTALL_SQLBENCHDIR_DEB ".") SET(INSTALL_SUPPORTFILESDIR_DEB "support-files") # -SET(INSTALL_MYSQLDATADIR_DEB "data") +SET(INSTALL_MYSQLDATADIR_DEB "/var/lib/mysql") SET(INSTALL_PLUGINTESTDIR_DEB ${plugin_tests}) +SET(INSTALL_SECURE_FILE_PRIVDIR_DEB ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_DEB ${secure_file_priv_embedded_path}) # # SVR4 layout @@ -221,7 +439,8 @@ SET(INSTALL_SUPPORTFILESDIR_SVR4 "support-files") # SET(INSTALL_MYSQLDATADIR_SVR4 "/var/lib/mysql") SET(INSTALL_PLUGINTESTDIR_SVR4 ${plugin_tests}) - +SET(INSTALL_SECURE_FILE_PRIVDIR_SVR4 ${secure_file_priv_path}) +SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_SVR4 ${secure_file_priv_embedded_path}) # Clear cached variables if install layout was changed IF(OLD_INSTALL_LAYOUT) @@ -235,8 +454,29 @@ SET(OLD_INSTALL_LAYOUT ${INSTALL_LAYOUT} CACHE INTERNAL "") # will be defined as ${INSTALL_BINDIR_STANDALONE} by default if STANDALONE # layout is chosen) FOREACH(var BIN SBIN LIB MYSQLSHARE SHARE PLUGIN INCLUDE SCRIPT DOC MAN - INFO MYSQLTEST SQLBENCH DOCREADME SUPPORTFILES MYSQLDATA PLUGINTEST) + INFO MYSQLTEST SQLBENCH DOCREADME SUPPORTFILES MYSQLDATA PLUGINTEST + SECURE_FILE_PRIV SECURE_FILE_PRIV_EMBEDDED) SET(INSTALL_${var}DIR ${INSTALL_${var}DIR_${INSTALL_LAYOUT}} CACHE STRING "${var} installation directory" ${FORCE}) MARK_AS_ADVANCED(INSTALL_${var}DIR) ENDFOREACH() + +# +# Set DEFAULT_SECURE_FILE_PRIV_DIR +# This is used as default value for --secure-file-priv +# +IF(INSTALL_SECURE_FILE_PRIVDIR) + SET(DEFAULT_SECURE_FILE_PRIV_DIR "\"${INSTALL_SECURE_FILE_PRIVDIR}\"" + CACHE INTERNAL "default --secure-file-priv directory" FORCE) +ELSE() + SET(DEFAULT_SECURE_FILE_PRIV_DIR \"\" + CACHE INTERNAL "default --secure-file-priv directory" FORCE) +ENDIF() + +IF(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR) + SET(DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR "\"${INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR}\"" + CACHE INTERNAL "default --secure-file-priv directory (for embedded library)" FORCE) +ELSE() + SET(DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR "NULL" + CACHE INTERNAL "default --secure-file-priv directory (for embedded library)" FORCE) +ENDIF() diff --git a/config.h.cmake b/config.h.cmake index 4548d0a221f..c7ed127379a 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -624,4 +624,8 @@ #cmakedefine SIZEOF_TIME_T @SIZEOF_TIME_T@ #cmakedefine TIME_T_UNSIGNED @TIME_T_UNSIGNED@ +/* For --secure-file-priv */ +#cmakedefine DEFAULT_SECURE_FILE_PRIV_DIR @DEFAULT_SECURE_FILE_PRIV_DIR@ +#cmakedefine DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR @DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR@ + #endif diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index 45acbc03b7e..0a3c3bc60b3 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -1,4 +1,4 @@ --- Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +-- Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. -- -- 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 @@ -204,6 +204,11 @@ INSERT INTO global_suppressions VALUES */ ("Found lock of type 6 that is write and read locked"), + /* + Warnings related to --secure-file-priv + */ + ("Insecure configuration for --secure-file-priv:*"), + ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/include/mysqld--help.inc b/mysql-test/include/mysqld--help.inc index 380a7f6c8cf..7fa57abbe1e 100644 --- a/mysql-test/include/mysqld--help.inc +++ b/mysql-test/include/mysqld--help.inc @@ -18,7 +18,8 @@ perl; # their paths may vary: @skipvars=qw/basedir open-files-limit general-log-file log plugin-dir log-slow-queries pid-file slow-query-log-file - datadir slave-load-tmpdir tmpdir socket/; + datadir slave-load-tmpdir tmpdir socket + secure-file-priv/; # Plugins which may or may not be there: @plugins=qw/innodb ndb archive blackhole federated partition ndbcluster debug temp-pool ssl des-key-file diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 684d262f410..3eb70c1bdb9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl # -*- cperl -*- -# Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -1823,6 +1823,7 @@ sub collect_mysqld_features { mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--datadir=%s", mixed_path($tmpdir)); + mtr_add_arg($args, "--secure-file-priv=\"\""); mtr_add_arg($args, "--lc-messages-dir=%s", $path_language); mtr_add_arg($args, "--skip-grant-tables"); mtr_add_arg($args, "--verbose"); @@ -3297,6 +3298,7 @@ sub mysql_install_db { mtr_add_arg($args, "--loose-skip-falcon"); mtr_add_arg($args, "--loose-skip-ndbcluster"); mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/"); + mtr_add_arg($args, "--secure-file-priv=%s", "$opt_vardir"); mtr_add_arg($args, "--core-file"); if ( $opt_debug ) diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index d527d6cb702..78dc9ab4d88 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -923,7 +923,6 @@ report-user (No default value) rpl-recovery-rank 0 safe-user-create FALSE secure-auth FALSE -secure-file-priv (No default value) server-id 0 show-slave-auth-info FALSE skip-grant-tables TRUE diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index 2ce9e763b14..1d56da7aa5e 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -931,7 +931,6 @@ report-user (No default value) rpl-recovery-rank 0 safe-user-create FALSE secure-auth FALSE -secure-file-priv (No default value) server-id 0 shared-memory FALSE shared-memory-base-name MYSQL diff --git a/mysql-test/suite/auth_sec/r/secure_file_priv_error.result b/mysql-test/suite/auth_sec/r/secure_file_priv_error.result new file mode 100644 index 00000000000..4bb4d87c5f0 --- /dev/null +++ b/mysql-test/suite/auth_sec/r/secure_file_priv_error.result @@ -0,0 +1,7 @@ +#----------------------------------------------------------------------- +# Setup +# Try to restart server with invalid value for --secure-file-priv +# Search for : Failed to access directory for --secure-file-priv. +# Restart completed. +# Restart +#----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/r/secure_file_priv_null.result b/mysql-test/suite/auth_sec/r/secure_file_priv_null.result new file mode 100644 index 00000000000..e2a5102c627 --- /dev/null +++ b/mysql-test/suite/auth_sec/r/secure_file_priv_null.result @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------- +# Setup +#----------------------------------------------------------------------- +# Search for : --secure-file-priv is set to NULL. Operations +# related to importing and exporting data are +# disabled +show variables like 'secure_file_priv'; +Variable_name Value +secure_file_priv null +use test; +drop table if exists secure_file_priv_test_null; +create table secure_file_priv_test_null(c1 int); +insert into secure_file_priv_test_null values (1), (2), (3), (4); +select * from secure_file_priv_test_null into outfile 'blah'; +ERROR HY000: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement +select * from secure_file_priv_test_null into outfile 'null/blah'; +ERROR HY000: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement +drop table secure_file_priv_test_null; +#----------------------------------------------------------------------- +# Clean-up +#----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/r/secure_file_priv_warnings.result b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings.result new file mode 100644 index 00000000000..3b80cbe8d6f --- /dev/null +++ b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings.result @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------- +# Setup +#----------------------------------------------------------------------- +# Search for : Insecure configuration for --secure-file-priv: Current +# value does not restrict location of generated files. +# Consider setting it to a valid, non-empty path. +SHOW VARIABLES LIKE 'secure_file_priv'; +Variable_name Value +secure_file_priv +#----------------------------------------------------------------------- +# Restart completed. +# Search for : Insecure configuration for --secure-file-priv: Plugin +# directory is accessible through --secure-file-priv. +# Consider choosing a different directory. +#----------------------------------------------------------------------- +# Clean-up +#----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_not_win.result b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_not_win.result new file mode 100644 index 00000000000..84e2f8ac3c2 --- /dev/null +++ b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_not_win.result @@ -0,0 +1,9 @@ +#----------------------------------------------------------------------- +# Search for : Insecure configuration for --secure-file-priv: Data +# directory is accessible through --secure-file-priv. +# Consider choosing a different directory. +#----------------------------------------------------------------------- +# Search for : Insecure configuration for --secure-file-priv: Location +# is accessible to all OS users. Consider choosing a +# different directory. +#----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_win.result b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_win.result new file mode 100644 index 00000000000..3beff6c4747 --- /dev/null +++ b/mysql-test/suite/auth_sec/r/secure_file_priv_warnings_win.result @@ -0,0 +1,8 @@ +#----------------------------------------------------------------------- +# Test 2 : Restarting mysqld with : +# --secure-file-priv=MYSQLTEST_VARDIR/mysqld.1/Data +# Restart completed. +# Search for : Insecure configuration for --secure-file-priv: Data +# directory is accessible through --secure-file-priv. +# Consider choosing a different directory. +#----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_error.test b/mysql-test/suite/auth_sec/t/secure_file_priv_error.test new file mode 100644 index 00000000000..9f8d185d8f5 --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_error.test @@ -0,0 +1,39 @@ +--source include/no_valgrind_without_big.inc +--source include/not_embedded.inc + +--echo #----------------------------------------------------------------------- +--echo # Setup +let restart_log= $MYSQLTEST_VARDIR/log/my_restart.err; +let SEARCH_FILE= $restart_log; +let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; + +--echo # Try to restart server with invalid value for --secure-file-priv +--exec echo "wait" > $restart_file +--shutdown_server +--source include/wait_until_disconnected.inc + +--error 0,1 +--remove_file $restart_log +# Following should fail +--error 1 +--exec $MYSQLD_CMD --secure-file-priv=blahblahblah --loose-console > $restart_log 2>&1 + +--echo # Search for : Failed to access directory for --secure-file-priv. +let SEARCH_PATTERN= Failed to access directory for --secure-file-priv; +--source include/search_pattern_in_file.inc + +--remove_file $restart_log + +--source include/wait_until_disconnected.inc +# Dummy argument for restart +--exec echo "restart:" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect +--echo # Restart completed. + +--echo # Restart +--disable_warnings +--source include/force_restart.inc +--enable_warnings +--echo #----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_null-master.opt b/mysql-test/suite/auth_sec/t/secure_file_priv_null-master.opt new file mode 100644 index 00000000000..80d7f3cd469 --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_null-master.opt @@ -0,0 +1 @@ +--secure-file-priv=null diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_null.test b/mysql-test/suite/auth_sec/t/secure_file_priv_null.test new file mode 100644 index 00000000000..8d394a13589 --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_null.test @@ -0,0 +1,42 @@ +--source include/no_valgrind_without_big.inc +--source include/not_embedded.inc + +--echo #----------------------------------------------------------------------- +--echo # Setup +let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let SEARCH_FILE= $server_log; +let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +--echo #----------------------------------------------------------------------- + +--echo # Search for : --secure-file-priv is set to NULL. Operations +--echo # related to importing and exporting data are +--echo # disabled +let SEARCH_PATTERN= --secure-file-priv is set to NULL. Operations related to importing and exporting data are disabled; +--source include/search_pattern_in_file.inc + +connect(test4_con,localhost,root,,,,,); +show variables like 'secure_file_priv'; + +use test; +--disable_warnings +drop table if exists secure_file_priv_test_null; +--enable_warnings +create table secure_file_priv_test_null(c1 int); +insert into secure_file_priv_test_null values (1), (2), (3), (4); +--error 1290 +select * from secure_file_priv_test_null into outfile 'blah'; +--error 1290 +select * from secure_file_priv_test_null into outfile 'null/blah'; +drop table secure_file_priv_test_null; + +connection default; +disconnect test4_con; + +--echo #----------------------------------------------------------------------- + +--echo # Clean-up +--disable_warnings +--source include/force_restart.inc +--enable_warnings + +--echo #----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_warnings-master.opt b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings-master.opt new file mode 100644 index 00000000000..22520f0aa99 --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings-master.opt @@ -0,0 +1 @@ +--secure-file-priv="" diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_warnings.test b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings.test new file mode 100644 index 00000000000..cc7a79d5b3c --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings.test @@ -0,0 +1,47 @@ +--source include/no_valgrind_without_big.inc +--source include/not_embedded.inc + +--echo #----------------------------------------------------------------------- +--echo # Setup +let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let SEARCH_FILE= $server_log; +let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +let PLUGIN_DIR= $MYSQLTEST_VARDIR/tmp; +--echo #----------------------------------------------------------------------- + +--echo # Search for : Insecure configuration for --secure-file-priv: Current +--echo # value does not restrict location of generated files. +--echo # Consider setting it to a valid, non-empty path. +let SEARCH_PATTERN= Insecure configuration for --secure-file-priv: Current value does not restrict location of generated files. Consider setting it to a valid, non-empty path.; +--source include/search_pattern_in_file.inc + +# Must show empty string +SHOW VARIABLES LIKE 'secure_file_priv'; + +--echo #----------------------------------------------------------------------- + +let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +--exec echo "wait" > $restart_file +--shutdown_server +--source include/wait_until_disconnected.inc +--remove_file $server_log +--exec echo "restart:--plugin-dir=$PLUGIN_DIR --secure-file-priv=$PLUGIN_DIR" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect +--echo # Restart completed. + +--echo # Search for : Insecure configuration for --secure-file-priv: Plugin +--echo # directory is accessible through --secure-file-priv. +--echo # Consider choosing a different directory. +let SEARCH_PATTERN= Insecure configuration for --secure-file-priv: Plugin directory is accessible through --secure-file-priv. Consider choosing a different directory.; +--source include/search_pattern_in_file.inc + +--echo #----------------------------------------------------------------------- + +--echo # Clean-up +--disable_warnings +--source include/force_restart.inc +--enable_warnings + +--echo #----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_not_win.test b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_not_win.test new file mode 100644 index 00000000000..ec027d4a743 --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_not_win.test @@ -0,0 +1,24 @@ +--source include/no_valgrind_without_big.inc +--source include/not_windows.inc +--source include/not_embedded.inc + +let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let SEARCH_FILE= $server_log; + +--echo #----------------------------------------------------------------------- + +--echo # Search for : Insecure configuration for --secure-file-priv: Data +--echo # directory is accessible through --secure-file-priv. +--echo # Consider choosing a different directory. +let SEARCH_PATTERN= Insecure configuration for --secure-file-priv: Data directory is accessible through --secure-file-priv. Consider choosing a different directory.; +--source include/search_pattern_in_file.inc + +--echo #----------------------------------------------------------------------- + +--echo # Search for : Insecure configuration for --secure-file-priv: Location +--echo # is accessible to all OS users. Consider choosing a +--echo # different directory. +let SEARCH_PATTERN= Insecure configuration for --secure-file-priv: Location is accessible to all OS users. Consider choosing a different directory.; +--source include/search_pattern_in_file.inc + +--echo #----------------------------------------------------------------------- diff --git a/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_win.test b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_win.test new file mode 100644 index 00000000000..bb175fb40ea --- /dev/null +++ b/mysql-test/suite/auth_sec/t/secure_file_priv_warnings_win.test @@ -0,0 +1,35 @@ +--source include/no_valgrind_without_big.inc +--source include/windows.inc +--source include/not_embedded.inc + +let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err; +let SEARCH_FILE= $server_log; + +--echo #----------------------------------------------------------------------- + +--echo # Test 2 : Restarting mysqld with : +--echo # --secure-file-priv=MYSQLTEST_VARDIR/mysqld.1/Data + +let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; +--exec echo "wait" > $restart_file +--shutdown_server +--source include/wait_until_disconnected.inc +--error 0,1 +--remove_file $server_log +--exec echo "restart: --secure-file-priv=$MYSQLTEST_VARDIR/mysqld.1/Data" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect +--echo # Restart completed. + +--echo # Search for : Insecure configuration for --secure-file-priv: Data +--echo # directory is accessible through --secure-file-priv. +--echo # Consider choosing a different directory. +let SEARCH_PATTERN= Insecure configuration for --secure-file-priv: Data directory is accessible through --secure-file-priv. Consider choosing a different directory.; +--source include/search_pattern_in_file.inc + +--disable_warnings +--source include/force_restart.inc +--enable_warnings + +--echo #----------------------------------------------------------------------- diff --git a/packaging/rpm-oel/mysql-systemd-start b/packaging/rpm-oel/mysql-systemd-start index fab7b3627b3..231a76087ac 100644 --- a/packaging/rpm-oel/mysql-systemd-start +++ b/packaging/rpm-oel/mysql-systemd-start @@ -30,6 +30,12 @@ install_db () { if [ -x /usr/sbin/restorecon ]; then /usr/sbin/restorecon "$datadir" /usr/sbin/restorecon $log + for dir in /var/lib/mysql-files ; do + if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then + /usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1 + /sbin/restorecon $dir + fi + done fi # If special mysql dir is in place, skip db install diff --git a/packaging/rpm-oel/mysql.init b/packaging/rpm-oel/mysql.init index aaea498d153..75ae672801b 100644 --- a/packaging/rpm-oel/mysql.init +++ b/packaging/rpm-oel/mysql.init @@ -82,7 +82,15 @@ start(){ fi chown mysql:mysql "$datadir" chmod 0755 "$datadir" - [ -x /sbin/restorecon ] && /sbin/restorecon "$datadir" + if [ -x /sbin/restorecon ]; then + /sbin/restorecon "$datadir" + for dir in /var/lib/mysql-files ; do + if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then + /usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1 + /sbin/restorecon $dir + fi + done + fi # Now create the database action $"Initializing MySQL database: " /usr/bin/mysql_install_db --rpm --datadir="$datadir" --user=mysql ret=$? diff --git a/packaging/rpm-oel/mysql.spec.in b/packaging/rpm-oel/mysql.spec.in index 409c325b675..7ef294ffa84 100644 --- a/packaging/rpm-oel/mysql.spec.in +++ b/packaging/rpm-oel/mysql.spec.in @@ -560,6 +560,7 @@ MBD=$RPM_BUILD_DIR/%{src_dir} install -d -m 0755 %{buildroot}%{_datadir}/mysql/SELinux/RHEL4 install -d -m 0755 %{buildroot}/var/lib/mysql install -d -m 0755 %{buildroot}/var/run/mysqld +install -d -m 0750 %{buildroot}/var/lib/mysql-files # Install all binaries cd $MBD/release @@ -790,6 +791,7 @@ fi %attr(644, root, root) %config(noreplace,missingok) %{_sysconfdir}/logrotate.d/mysql %dir %attr(755, mysql, mysql) /var/lib/mysql %dir %attr(755, mysql, mysql) /var/run/mysqld +%dir %attr(750, mysql, mysql) /var/lib/mysql-files %files common %defattr(-, root, root, -) @@ -916,6 +918,9 @@ fi %endif %changelog +* Mon Sep 26 2016 Balasubramanian Kandasamy - 5.5.53-1 +- Include mysql-files directory + * Tue Jul 05 2016 Balasubramanian Kandasamy - 5.5.51-1 - Remove mysql_config from client subpackage diff --git a/packaging/rpm-sles/mysql.spec.in b/packaging/rpm-sles/mysql.spec.in index a11dfff7b70..6652cdcccb6 100644 --- a/packaging/rpm-sles/mysql.spec.in +++ b/packaging/rpm-sles/mysql.spec.in @@ -425,6 +425,7 @@ MBD=$RPM_BUILD_DIR/%{src_dir} install -d -m 0755 %{buildroot}/var/lib/mysql install -d -m 0755 %{buildroot}/var/run/mysql install -d -m 0750 %{buildroot}/var/log/mysql +install -d -m 0750 %{buildroot}/var/lib/mysql-files # Install all binaries cd $MBD/release @@ -638,6 +639,7 @@ fi %dir %attr(755, mysql, mysql) /var/lib/mysql %dir %attr(755, mysql, mysql) /var/run/mysql %dir %attr(750, mysql, mysql) /var/log/mysql +%dir %attr(750, mysql, mysql) /var/lib/mysql-files %files common %defattr(-, root, root, -) @@ -783,6 +785,9 @@ fi %attr(755, root, root) %{_libdir}/mysql/libmysqld.so %changelog +* Mon Sep 26 2016 Balasubramanian Kandasamy - 5.5.53-1 +- Include mysql-files directory + * Tue Sep 29 2015 Balasubramanian Kandasamy - 5.5.47-1 - Added conflicts to mysql-connector-c-shared dependencies diff --git a/packaging/solaris/postinstall-solaris.sh b/packaging/solaris/postinstall-solaris.sh index b024d94f158..a31e151e1bb 100644 --- a/packaging/solaris/postinstall-solaris.sh +++ b/packaging/solaris/postinstall-solaris.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -26,6 +26,7 @@ mygroup=mysql myuser=mysql mydatadir=/var/lib/mysql basedir=@@basedir@@ +mysecurefiledir=/var/lib/mysql-files if [ -n "$BASEDIR" ] ; then basedir="$BASEDIR" @@ -58,6 +59,11 @@ fi chown -R $myuser:$mygroup $mydatadir +# Create securefile directory +[ -d "$mysecurefiledir" ] || mkdir -p -m 770 "$mysecurefiledir" || exit 1 +chown -R $myuser:$mygroup $mysecurefiledir + + # Solaris patch 119255 (somewhere around revision 42) changes the behaviour # of pkgadd to set TMPDIR internally to a root-owned install directory. This # has the unfortunate side effect of breaking running mysql_install_db with diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d8edbe4b637..c969fd8a62a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -570,6 +570,7 @@ uint mysql_real_data_home_len, mysql_data_home_len= 1; uint reg_ext_length; const key_map key_map_empty(0); key_map key_map_full(0); // Will be initialized later +char secure_file_real_path[FN_REFLEN]; DATE_TIME_FORMAT global_date_format, global_datetime_format, global_time_format; Time_zone *default_tz; @@ -7613,9 +7614,9 @@ bool is_secure_file_path(char *path) char buff1[FN_REFLEN], buff2[FN_REFLEN]; size_t opt_secure_file_priv_len; /* - All paths are secure if opt_secure_file_path is 0 + All paths are secure if opt_secure_file_priv is 0 */ - if (!opt_secure_file_priv) + if (!opt_secure_file_priv[0]) return TRUE; opt_secure_file_priv_len= strlen(opt_secure_file_priv); @@ -7623,6 +7624,9 @@ bool is_secure_file_path(char *path) if (strlen(path) >= FN_REFLEN) return FALSE; + if (!my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + return FALSE; + if (my_realpath(buff1, path, 0)) { /* @@ -7655,9 +7659,184 @@ bool is_secure_file_path(char *path) } +/** + check_secure_file_priv_path : Checks path specified through + --secure-file-priv and raises warning in following cases: + 1. If path is empty string or NULL and mysqld is not running + with --bootstrap mode. + 2. If path can access data directory + 3. If path points to a directory which is accessible by + all OS users (non-Windows build only) + + It throws error in following cases: + + 1. If path normalization fails + 2. If it can not get stats of the directory + + @params NONE + + Assumptions : + 1. Data directory path has been normalized + 2. opt_secure_file_priv has been normalized unless it is set + to "NULL". + + @returns Status of validation + @retval true : Validation is successful with/without warnings + @retval false : Validation failed. Error is raised. +*/ + +bool check_secure_file_priv_path() +{ + char datadir_buffer[FN_REFLEN+1]={0}; + char plugindir_buffer[FN_REFLEN+1]={0}; + char whichdir[20]= {0}; + size_t opt_plugindir_len= 0; + size_t opt_datadir_len= 0; + size_t opt_secure_file_priv_len= 0; + bool warn= false; + bool case_insensitive_fs; +#ifndef _WIN32 + MY_STAT dir_stat; +#endif + + if (!opt_secure_file_priv[0]) + { + if (opt_bootstrap) + { + /* + Do not impose --secure-file-priv restriction + in --bootstrap mode + */ + sql_print_information("Ignoring --secure-file-priv value as server is " + "running with --bootstrap."); + } + else + { + sql_print_warning("Insecure configuration for --secure-file-priv: " + "Current value does not restrict location of generated " + "files. Consider setting it to a valid, " + "non-empty path."); + } + return true; + } + + /* + Setting --secure-file-priv to NULL would disable + reading/writing from/to file + */ + if(!my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + { + sql_print_information("--secure-file-priv is set to NULL. " + "Operations related to importing and exporting " + "data are disabled"); + return true; + } + + /* + Check if --secure-file-priv can access data directory + */ + opt_secure_file_priv_len= strlen(opt_secure_file_priv); + + /* + Adds dir seperator at the end. + This is required in subsequent comparison + */ + convert_dirname(datadir_buffer, mysql_unpacked_real_data_home, NullS); + opt_datadir_len= strlen(datadir_buffer); + + case_insensitive_fs= + (test_if_case_insensitive(datadir_buffer) == 1); + + if (!case_insensitive_fs) + { + if (!strncmp(datadir_buffer, opt_secure_file_priv, + opt_datadir_len < opt_secure_file_priv_len ? + opt_datadir_len : opt_secure_file_priv_len)) + { + warn= true; + strcpy(whichdir, "Data directory"); + } + } + else + { + if (!files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) datadir_buffer, + opt_datadir_len, + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + { + warn= true; + strcpy(whichdir, "Data directory"); + } + } + + /* + Don't bother comparing --secure-file-priv with --plugin-dir + if we already have a match against --datadir or + --plugin-dir is not pointing to a valid directory. + */ + if (!warn && !my_realpath(plugindir_buffer, opt_plugin_dir, 0)) + { + convert_dirname(plugindir_buffer, plugindir_buffer, NullS); + opt_plugindir_len= strlen(plugindir_buffer); + + if (!case_insensitive_fs) + { + if (!strncmp(plugindir_buffer, opt_secure_file_priv, + opt_plugindir_len < opt_secure_file_priv_len ? + opt_plugindir_len : opt_secure_file_priv_len)) + { + warn= true; + strcpy(whichdir, "Plugin directory"); + } + } + else + { + if (!files_charset_info->coll->strnncoll(files_charset_info, + (uchar *) plugindir_buffer, + opt_plugindir_len, + (uchar *) opt_secure_file_priv, + opt_secure_file_priv_len, + TRUE)) + { + warn= true; + strcpy(whichdir, "Plugin directory"); + } + } + } + + + if (warn) + sql_print_warning("Insecure configuration for --secure-file-priv: " + "%s is accessible through " + "--secure-file-priv. Consider choosing a different " + "directory.", whichdir); + +#ifndef _WIN32 + /* + Check for --secure-file-priv directory's permission + */ + if (!(my_stat(opt_secure_file_priv, &dir_stat, MYF(0)))) + { + sql_print_error("Failed to get stat for directory pointed out " + "by --secure-file-priv"); + return false; + } + + if (dir_stat.st_mode & S_IRWXO) + sql_print_warning("Insecure configuration for --secure-file-priv: " + "Location is accessible to all OS users. " + "Consider choosing a different directory."); +#endif + return true; +} + + static int fix_paths(void) { char buff[FN_REFLEN],*pos; + bool secure_file_priv_nonempty= false; convert_dirname(mysql_home,mysql_home,NullS); /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */ my_realpath(mysql_home,mysql_home,MYF(0)); @@ -7715,29 +7894,56 @@ static int fix_paths(void) Convert the secure-file-priv option to system format, allowing a quick strcmp to check if read or write is in an allowed dir */ - if (opt_secure_file_priv) + if (opt_bootstrap) + opt_secure_file_priv= EMPTY_STR.str; + secure_file_priv_nonempty= opt_secure_file_priv[0] ? true : false; + + if (secure_file_priv_nonempty && strlen(opt_secure_file_priv) > FN_REFLEN) { - if (*opt_secure_file_priv == 0) - { - my_free(opt_secure_file_priv); - opt_secure_file_priv= 0; - } - else - { - if (strlen(opt_secure_file_priv) >= FN_REFLEN) - opt_secure_file_priv[FN_REFLEN-1]= '\0'; - if (my_realpath(buff, opt_secure_file_priv, 0)) - { - sql_print_warning("Failed to normalize the argument for --secure-file-priv."); - return 1; - } - char *secure_file_real_path= (char *)my_malloc(FN_REFLEN, MYF(MY_FAE)); - convert_dirname(secure_file_real_path, buff, NullS); - my_free(opt_secure_file_priv); - opt_secure_file_priv= secure_file_real_path; - } + sql_print_warning("Value for --secure-file-priv is longer than maximum " + "limit of %d", FN_REFLEN-1); + return 1; } - + + memset(buff, 0, sizeof(buff)); + if (secure_file_priv_nonempty && + my_strcasecmp(system_charset_info, opt_secure_file_priv, "NULL")) + { + int retval= my_realpath(buff, opt_secure_file_priv, MYF(MY_WME)); + if (!retval) + { + convert_dirname(secure_file_real_path, buff, NullS); +#ifdef WIN32 + MY_DIR *dir= my_dir(secure_file_real_path, MYF(MY_DONT_SORT+MY_WME)); + if (!dir) + { + retval= 1; + } + else + { + my_dirend(dir); + } +#endif + } + + if (retval) + { + char err_buffer[FN_REFLEN]; + my_snprintf(err_buffer, FN_REFLEN-1, + "Failed to access directory for --secure-file-priv." + " Please make sure that directory exists and is " + "accessible by MySQL Server. Supplied value : %s", + opt_secure_file_priv); + err_buffer[FN_REFLEN-1]='\0'; + sql_print_error("%s", err_buffer); + return 1; + } + opt_secure_file_priv= secure_file_real_path; + } + + if (!check_secure_file_priv_path()) + return 1; + return 0; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0696021cfc0..d9fda85d8f6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -68,6 +68,8 @@ char internal_table_name[2]= "*"; char empty_c_string[1]= {0}; /* used for not defined db */ +LEX_STRING EMPTY_STR= { (char *) "", 0 }; + const char * const THD::DEFAULT_WHERE= "field list"; diff --git a/sql/sql_class.h b/sql/sql_class.h index dcc7458ee50..aa6745e4564 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -105,6 +105,7 @@ enum enum_filetype { FILETYPE_CSV, FILETYPE_XML }; extern char internal_table_name[2]; extern char empty_c_string[1]; +extern LEX_STRING EMPTY_STR; extern MYSQL_PLUGIN_IMPORT const char **errmesg; extern bool volatile shutdown_in_progress; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index d08cb4f8ca8..6fd728d638d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1941,8 +1941,12 @@ static Sys_var_charptr Sys_secure_file_priv( "secure_file_priv", "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files " "within specified directory", - PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv), - CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(0)); + READ_ONLY GLOBAL_VAR(opt_secure_file_priv), +#ifndef EMBEDDED_LIBRARY + CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(DEFAULT_SECURE_FILE_PRIV_DIR)); +#else + CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(DEFAULT_SECURE_FILE_PRIV_EMBEDDED_DIR)); +#endif static bool fix_server_id(sys_var *self, THD *thd, enum_var_type type) { diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 5af4783f919..211ed4f3888 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -1,4 +1,4 @@ -# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -562,6 +562,7 @@ install -d $RBR%{_includedir} install -d $RBR%{_libdir} install -d $RBR%{_mandir} install -d $RBR%{_sbindir} +install -d $RBR/var/lib/mysql-files mkdir -p $RBR%{_sysconfdir}/my.cnf.d @@ -1141,6 +1142,7 @@ echo "=====" >> $STATUS_HISTORY %attr(755, root, root) %{_sysconfdir}/init.d/mysql %attr(755, root, root) %{_datadir}/mysql/ +%dir %attr(750, mysql, mysql) /var/lib/mysql-files # ---------------------------------------------------------------------------- %files -n MySQL-client%{product_suffix} @@ -1226,6 +1228,9 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Mon Sep 26 2016 Balasubramanian Kandasamy +- Include mysql-files directory + * Wed Jul 02 2014 Bjorn Munch - Disable dtrace unconditionally, breaks after we install Oracle dtrace From da97aa6885959daff4b87360128cdc9952e4759e Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Thu, 29 Sep 2016 11:02:05 +0530 Subject: [PATCH 015/124] From 65febcce97ebe2da0c9723b76a041e249b053a98 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 27 Sep 2016 14:09:54 +0300 Subject: [PATCH 016/124] Fix Bug#24707869 GCC 5 AND 6 MISCOMPILE MACH_PARSE_COMPRESSED Prevent GCC from moving a mach_read_from_4() before we have checked that we have 4 bytes to read. The pointer may only point to a 1, 2 or 3 bytes in which case the code should not read 4 bytes. This is a workaround to a GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673 Patch submitted by: Laurynas Biveinis RB: 14135 Reviewed by: Pawel Olchawa --- storage/innobase/mach/mach0data.c | 57 ++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/storage/innobase/mach/mach0data.c b/storage/innobase/mach/mach0data.c index 95b135b0954..9669516244d 100644 --- a/storage/innobase/mach/mach0data.c +++ b/storage/innobase/mach/mach0data.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -55,8 +55,22 @@ mach_parse_compressed( if (flag < 0x80UL) { *val = flag; return(ptr + 1); + } - } else if (flag < 0xC0UL) { + /* Workaround GCC bug + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673: + the compiler moves mach_read_from_4 right to the beginning of the + function, causing and out-of-bounds read if we are reading a short + integer close to the end of buffer. */ +#if defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__clang__) +#define DEPLOY_FENCE +#endif + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xC0UL) { if (end_ptr < ptr + 2) { return(NULL); } @@ -64,8 +78,13 @@ mach_parse_compressed( *val = mach_read_from_2(ptr) & 0x7FFFUL; return(ptr + 2); + } - } else if (flag < 0xE0UL) { +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xE0UL) { if (end_ptr < ptr + 3) { return(NULL); } @@ -73,7 +92,13 @@ mach_parse_compressed( *val = mach_read_from_3(ptr) & 0x3FFFFFUL; return(ptr + 3); - } else if (flag < 0xF0UL) { + } + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xF0UL) { if (end_ptr < ptr + 4) { return(NULL); } @@ -81,14 +106,20 @@ mach_parse_compressed( *val = mach_read_from_4(ptr) & 0x1FFFFFFFUL; return(ptr + 4); - } else { - ut_ad(flag == 0xF0UL); - - if (end_ptr < ptr + 5) { - return(NULL); - } - - *val = mach_read_from_4(ptr + 1); - return(ptr + 5); } + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + +#undef DEPLOY_FENCE + + ut_ad(flag == 0xF0UL); + + if (end_ptr < ptr + 5) { + return(NULL); + } + + *val = mach_read_from_4(ptr + 1); + return(ptr + 5); } From 1f93f4381b60e3a8012ba36a4dec920416073759 Mon Sep 17 00:00:00 2001 From: Terje Rosten Date: Thu, 6 Oct 2016 13:26:16 +0200 Subject: [PATCH 017/124] Bug#24483092 UNSAFE USE OF VARIOUS SHELL UTILITIES - Remove use of touch and chmod. - Restrict usage of chown to cases where target directory is /var/log. - Due to limited feature set in /bin/sh on Solaris, /bin/bash will be used on this platform. - Give error if directory for UNIX socket file is missing. - Privileged user should not log to files owned by different user (mysqld will log as before). --- scripts/CMakeLists.txt | 10 +++- scripts/mysqld_safe.sh | 109 +++++++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 27 deletions(-) diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 05bf8530a26..920b6854334 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -105,7 +105,13 @@ ELSE() ENDIF() IF(UNIX) - # FIND_PROC and CHECK_PID are used by mysqld_safe + # SHELL_PATH, FIND_PROC, CHECK_PID are used by mysqld_safe +IF(CMAKE_SYSTEM_NAME MATCHES "SunOS") + SET (SHELL_PATH "/bin/bash") +ELSE() + SET (SHELL_PATH "/bin/sh") +ENDIF() + IF(CMAKE_SYSTEM_NAME MATCHES "Linux") SET (FIND_PROC "ps wwwp $PID | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null") diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 1b30a3bb15b..4b103817ab6 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!@SHELL_PATH@ # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # @@ -125,7 +125,13 @@ log_generic () { echo "$msg" case $logging in init) ;; # Just echo the message, don't save it anywhere - file) echo "$msg" >> "$err_log" ;; + file) + if [ -w / -o "$USER" = "root" ]; then + true + else + echo "$msg" >> "$err_log" + fi + ;; syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; *) echo "Internal program error (non-fatal):" \ @@ -145,7 +151,13 @@ log_notice () { eval_log_error () { cmd="$1" case $logging in - file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;; + file) + if [ -w / -o "$USER" = "root" ]; then + cmd="$cmd > /dev/null 2>&1" + else + cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" + fi + ;; syslog) # mysqld often prefixes its messages with a timestamp, which is # redundant when logging to syslog (which adds its own timestamp) @@ -571,14 +583,7 @@ then fi # Log to err_log file - log_notice "Logging to '$err_log'." logging=file - - if [ ! -f "$err_log" -a ! -h "$err_log" ]; then # if error log already exists, - touch "$err_log" # we just append. otherwise, - chmod "$fmode" "$err_log" # fix the permissions here! - fi - else if [ -n "$syslog_tag" ] then @@ -591,6 +596,48 @@ else logging=syslog fi +logdir=`dirname "$err_log"` +# Change the err log to the right user, if possible and it is in use +if [ $logging = "file" -o $logging = "both" ]; then + if [ ! -f "$err_log" -a ! -h "$err_log" ]; then + if test -w / -o "$USER" = "root"; then + case $logdir in + /var/log) + ( + umask 0137 + set -o noclobber + > "$err_log" && chown $user "$err_log" + ) ;; + *) ;; + esac + else + ( + umask 0137 + set -o noclobber + > "$err_log" + ) + fi + fi + + if [ -f "$err_log" ]; then # Log to err_log file + log_notice "Logging to '$err_log'." + elif [ "x$user" = "xroot" ]; then # running as root, mysqld can create log file; continue + echo "Logging to '$err_log'." >&2 + else + case $logdir in + # We can't create $err_log, however mysqld can; continue + /tmp|/var/tmp|/var/log/mysql|$DATADIR) + echo "Logging to '$err_log'." >&2 + ;; + # We can't create $err_log and don't know if mysqld can; error out + *) + log_error "error: log-error set to '$err_log', however file don't exists. Create writable for user '$user'." + exit 1 + ;; + esac + fi +fi + USER_OPTION="" if test -w / -o "$USER" = "root" then @@ -598,11 +645,6 @@ then then USER_OPTION="--user=$user" fi - # Change the err log to the right user, if it is in use - if [ $want_syslog -eq 0 -a ! -h "$err_log" ]; then - touch "$err_log" - chown $user "$err_log" - fi if test -n "$open_files" then ulimit -n $open_files @@ -615,15 +657,12 @@ then fi safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@}} -# Make sure that directory for $safe_mysql_unix_port exists +# Check that directory for $safe_mysql_unix_port exists mysql_unix_port_dir=`dirname $safe_mysql_unix_port` if [ ! -d $mysql_unix_port_dir ] then - if [ ! -h $mysql_unix_port_dir ]; then - mkdir $mysql_unix_port_dir - chown $user $mysql_unix_port_dir - chmod 755 $mysql_unix_port_dir - fi + log_error "Directory '$mysql_unix_port_dir' for UNIX socket file don't exists." + exit 1 fi # If the user doesn't specify a binary, we assume name "mysqld" @@ -800,11 +839,31 @@ do eval_log_error "$cmd" + # hypothetical: log was renamed but not + # flushed yet. we'd recreate it with + # wrong owner next time we log, so set + # it up correctly while we can! + if [ $want_syslog -eq 0 -a ! -f "$err_log" -a ! -h "$err_log" ]; then - touch "$err_log" # hypothetical: log was renamed but not - chown $user "$err_log" # flushed yet. we'd recreate it with - chmod "$fmode" "$err_log" # wrong owner next time we log, so set - fi # it up correctly while we can! + if test -w / -o "$USER" = "root"; then + logdir=`dirname "$err_log"` + case $logdir in + /var/log) + ( + umask 0137 + set -o noclobber + > "$err_log" && chown $user "$err_log" + ) ;; + *) ;; + esac + else + ( + umask 0137 + set -o noclobber + > "$err_log" + ) + fi + fi end_time=`date +%M%S` From 149212772804e93983f80b63099ba9e1241ddf4f Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Thu, 13 Oct 2016 14:48:45 +0530 Subject: [PATCH 018/124] BUG#23499695: MYSQL SERVER NORMAL SHUTDOWN WITH TIME STAMP 700101 ANALYSIS: ========= To set the time 'start_time' of query in THD, current time is obtained by calling 'gettimeofday()'. On Solaris platform, due to some system level issues, time obtained is invalid i.e. its either greater than 2038 (max signed value to hold microseconds since 1970) or 1970 (0 microseconds since 1970). In these cases, validation checks infer that the 'start_time' is invalid and mysql server initiates the shutdown process. But the reason for shutdown is not logged. FIX: ==== We are now logging appropriate message when shutdown is triggered in the above mentioned scenarios. Now, even if the initial validation checks infer that the 'start_time' is invalid, server shutdown is not initiated immediately. Before initiating the server shutdown, the process of setting 'start_time' and validating it is reiterated (for max 5 times). If correct time is obtained in these 5 iterations then server continues to run. --- sql/sql_parse.cc | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fd3623c6148..ac3901997f3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -889,17 +889,47 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - if (!thd->is_valid_time()) + if (thd->is_valid_time() == false) { /* - If the time has got past 2038 we need to shut this server down - We do this by making sure every command is a shutdown and we - have enough privileges to shut the server down - - TODO: remove this when we have full 64 bit my_time_t support + If the time has gone past 2038 we need to shutdown the server. But + there is possibility of getting invalid time value on some platforms. + For example, gettimeofday() might return incorrect value on solaris + platform. Hence validating the current time with 5 iterations before + initiating the normal server shutdown process because of time getting + past 2038. */ - thd->security_ctx->master_access|= SHUTDOWN_ACL; - command= COM_SHUTDOWN; + const int max_tries= 5; + sql_print_warning("Current time has got past year 2038. Validating current " + "time with %d iterations before initiating the normal " + "server shutdown process.", max_tries); + + int tries= 0; + while (++tries <= max_tries) + { + thd->set_time(); + if (thd->is_valid_time() == true) + { + sql_print_warning("Iteration %d: Obtained valid current time from " + "system", tries); + break; + } + sql_print_warning("Iteration %d: Current time obtained from system is " + "greater than 2038", tries); + } + if (tries > max_tries) + { + /* + If the time has got past 2038 we need to shut this server down. + We do this by making sure every command is a shutdown and we + have enough privileges to shut the server down + + TODO: remove this when we have full 64 bit my_time_t support + */ + sql_print_error("This MySQL server doesn't support dates later than 2038"); + thd->security_ctx->master_access|= SHUTDOWN_ACL; + command= COM_SHUTDOWN; + } } thd->set_query_id(next_query_id()); inc_thread_running(); From 63b2c9765068d82fc1ee3932ce21f9330eef4b55 Mon Sep 17 00:00:00 2001 From: Terje Rosten Date: Mon, 24 Oct 2016 13:11:34 +0200 Subject: [PATCH 019/124] Bug#24925181 INCORRECT ISA DETECTION CODE IN OEL RPM SPEC Wrapper for mysql_config used in multilib installs modified to work as intended, added more archs (aarch64, ppc64le, s390x, s390, sparc and sparc64) to lists in fallback mode and use same script for EL and Fedora. Thanks to Alexey Kopytov for report and fix. --- packaging/rpm-oel/mysql_config.sh | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packaging/rpm-oel/mysql_config.sh b/packaging/rpm-oel/mysql_config.sh index abe46e0ed74..8044ed44164 100644 --- a/packaging/rpm-oel/mysql_config.sh +++ b/packaging/rpm-oel/mysql_config.sh @@ -2,22 +2,30 @@ # # Wrapper script for mysql_config to support multilib # -# Only works on OEL6/RHEL6 and similar # -# This command respects setarch +# This command respects setarch, works on OL6/RHEL6 and later bits=$(rpm --eval %__isa_bits) case $bits in - 32|64) status=known ;; - *) status=unknown ;; + 32|64) ;; + *) bits=unknown ;; esac -if [ "$status" = "unknown" ] ; then - echo "$0: error: command 'rpm --eval %__isa_bits' returned unknown value: $bits" - exit 1 +# Try mapping by uname if rpm command failed +if [ "$bits" = "unknown" ] ; then + arch=$(uname -m) + case $arch in + x86_64|ppc64|ppc64le|aarch64|s390x|sparc64) bits=64 ;; + i386|i486|i586|i686|pentium3|pentium4|athlon|ppc|s390|sparc) bits=32 ;; + *) bits=unknown ;; + esac fi +if [ "$bits" == "unknown" ] ; then + echo "$0: error: failed to determine isa bits on your arch." + exit 1 +fi if [ -x /usr/bin/mysql_config-$bits ] ; then /usr/bin/mysql_config-$bits "$@" @@ -25,4 +33,3 @@ else echo "$0: error: needed binary: /usr/bin/mysql_config-$bits is missing. Please check your MySQL installation." exit 1 fi - From 31d8c9221fb9451c4e269be7b0d4d26a882e730e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 25 Oct 2016 16:58:47 +0200 Subject: [PATCH 020/124] 5.6.34 From ae473368feea7dc75f10624495eb210ae10e1c05 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 25 Oct 2016 16:59:57 +0200 Subject: [PATCH 021/124] 5.6.34 From c3cf7f47f0f4a1ec314001aaf0c3d9c1c1f62097 Mon Sep 17 00:00:00 2001 From: Thayumanavar S Date: Fri, 28 Oct 2016 14:45:03 +0200 Subject: [PATCH 022/124] BUG#24487120 - SLAVE'S SLAVE_SQL_RUNNING IS STOPPED DURING LOAD DATA AT MASTER. Revert "BUG#23080148 - BACKPORT BUG 14653594 AND BUG 20683959 TO" This reverts commit 1d31f5b3090d129382b50b95512f2f79305715a1. The commit causes replication incompatibility between minor revisions and based on discussion with Srinivasarao, the patch is reverted. --- mysql-test/r/loaddata.result | 26 +------ mysql-test/std_data/bug20683959loaddata.txt | 1 - mysql-test/t/loaddata.test | 25 +------ sql/sql_load.cc | 77 ++++++++------------- 4 files changed, 30 insertions(+), 99 deletions(-) delete mode 100644 mysql-test/std_data/bug20683959loaddata.txt diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 2f2a3579eec..2d67d24bedd 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -507,7 +507,7 @@ DROP TABLE t1; # Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U # CREATE TABLE t1(f1 INT); -SELECT 0xE1C330 INTO OUTFILE 't1.dat'; +SELECT 0xE1BB30 INTO OUTFILE 't1.dat'; LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8; DROP TABLE t1; # @@ -532,27 +532,3 @@ FIELDS TERMINATED BY 't' LINES TERMINATED BY ''; Got one of the listed errors SET @@sql_mode= @old_mode; DROP TABLE t1; - -# -# Bug#23080148 - Backport of Bug#20683959. -# Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY -# UNDER DB CHARSET IS UTF8. -# -CREATE DATABASE d1 CHARSET latin1; -USE d1; -CREATE TABLE t1 (val TEXT); -LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1; -SELECT COUNT(*) FROM t1; -COUNT(*) -1 -SELECT HEX(val) FROM t1; -HEX(val) -C38322525420406E696F757A656368756E3A20E98198E2889AF58081AEE7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE78999E880B3E7B8BAEFBDAAE7B9A7E89699E296A1E7B8BAE4BBA3EFBD8CE7B8BAEFBDA9E7B8B2E2889AE38184E7B99DEFBDB3E7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE5B3A8EFBD84E8ABA0EFBDA8E89C89F580948EE599AAE7B8BAEFBDAAE7B8BAE9A198EFBDA9EFBDB1E7B9A7E581B5E289A0E7B8BAEFBDBEE7B9A7E9A194EFBDA9E882B4EFBDA5EFBDB5E980A7F5808B96E28693E99EABE38287E58F99E7B8BAE58AB1E28691E7B8BAF5808B9AE7828AE98095EFBDB1E7B8BAEFBDAFE7B8B2E288ABE6A89FE89EB3E6BA98F58081ADE88EA0EFBDBAE98095E6BA98F58081AEE89D93EFBDBAE8AD9BEFBDACE980A7F5808B96E28693E7B8BAF580918EE288AAE7B8BAE4B88AEFBC9EE7B8BAE4B99DE28691E7B8BAF5808B96EFBCA0E88DB3E6A68AEFBDB9EFBDB3E981B2E5B3A8E296A1E7B8BAE7A4BCE7828AE88DB3E6A68AEFBDB0EFBDBDE7B8BAA0E7B8BAE88B93EFBDBEE5B899EFBC9E -CREATE DATABASE d2 CHARSET utf8; -USE d2; -CREATE TABLE t1 (val TEXT); -LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1; -ERROR HY000: Invalid utf8 character string: '"RT @niouzechun: \9058\221A' -DROP TABLE d1.t1, d2.t1; -DROP DATABASE d1; -DROP DATABASE d2; diff --git a/mysql-test/std_data/bug20683959loaddata.txt b/mysql-test/std_data/bug20683959loaddata.txt deleted file mode 100644 index 1878cc78879..00000000000 --- a/mysql-test/std_data/bug20683959loaddata.txt +++ /dev/null @@ -1 +0,0 @@ -Ã"RT @niouzechun: 遘√繝上ャ繝斐繧ィ繝ウ繝牙耳縺ェ繧薙□縺代l縺ゥ縲√い繝ウ繝上ャ繝斐繧ィ繝ウ繝峨d諠ィ蜉噪縺ェ縺願ゥア繧偵≠縺セ繧顔ゥ肴・オ逧↓鞫ょ叙縺励↑縺炊逕ア縺ッ縲∫樟螳溘莠コ逕溘蝓コ譛ャ逧↓縺∪縺上>縺九↑縺@荳榊ケウ遲峨□縺礼炊荳榊ース縺縺苓セ帙> diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 9a664b84843..aa7be52484e 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -610,7 +610,7 @@ disconnect con1; --echo # CREATE TABLE t1(f1 INT); -EVAL SELECT 0xE1C330 INTO OUTFILE 't1.dat'; +EVAL SELECT 0xE1BB30 INTO OUTFILE 't1.dat'; --disable_warnings LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8; --enable_warnings @@ -656,26 +656,3 @@ SET @@sql_mode= @old_mode; --remove_file $MYSQLTEST_VARDIR/mysql DROP TABLE t1; ---echo ---echo # ---echo # Bug#23080148 - Backport of Bug#20683959. ---echo # Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY ---echo # UNDER DB CHARSET IS UTF8. ---echo # - -CREATE DATABASE d1 CHARSET latin1; -USE d1; -CREATE TABLE t1 (val TEXT); -LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1; -SELECT COUNT(*) FROM t1; -SELECT HEX(val) FROM t1; - -CREATE DATABASE d2 CHARSET utf8; -USE d2; -CREATE TABLE t1 (val TEXT); ---error ER_INVALID_CHARACTER_STRING -LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1; - -DROP TABLE d1.t1, d2.t1; -DROP DATABASE d1; -DROP DATABASE d2; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index a46967a24a8..c084e5e3839 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1363,8 +1363,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, set_if_bigger(length,line_start.length()); stack=stack_pos=(int*) sql_alloc(sizeof(int)*length); - if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME)))) - error= true; /* purecov: inspected */ + if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0)))) + error=1; /* purecov: inspected */ else { end_of_buff=buffer+buff_length; @@ -1556,50 +1556,37 @@ int READ_INFO::read_field() } } #ifdef USE_MB - uint ml= my_mbcharlen(read_charset, chr); - if (ml == 0) - { - *to= '\0'; - my_error(ER_INVALID_CHARACTER_STRING, MYF(0), - read_charset->csname, buffer); - error= true; - return 1; - } + if (my_mbcharlen(read_charset, chr) > 1 && + to + my_mbcharlen(read_charset, chr) <= end_of_buff) + { + uchar* p= to; + int ml, i; + *to++ = chr; - if (ml > 1 && - to + ml <= end_of_buff) - { - uchar* p= to; - *to++ = chr; + ml= my_mbcharlen(read_charset, chr); - for (uint i= 1; i < ml; i++) + for (i= 1; i < ml; i++) + { + chr= GET; + if (chr == my_b_EOF) { - chr= GET; - if (chr == my_b_EOF) - { - /* - Need to back up the bytes already ready from illformed - multi-byte char - */ - to-= i; - goto found_eof; - } - *to++ = chr; + /* + Need to back up the bytes already ready from illformed + multi-byte char + */ + to-= i; + goto found_eof; } - if (my_ismbchar(read_charset, + *to++ = chr; + } + if (my_ismbchar(read_charset, (const char *)p, (const char *)to)) - continue; - for (uint i= 0; i < ml; i++) - PUSH(*--to); - chr= GET; - } - else if (ml > 1) - { - // Buffer is too small, exit while loop, and reallocate. - PUSH(chr); - break; - } + continue; + for (i= 0; i < ml; i++) + PUSH(*--to); + chr= GET; + } #endif *to++ = (uchar) chr; } @@ -1843,15 +1830,7 @@ int READ_INFO::read_value(int delim, String *val) for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) { #ifdef USE_MB - uint ml= my_mbcharlen(read_charset, chr); - if (ml == 0) - { - chr= my_b_EOF; - val->length(0); - return chr; - } - - if (ml > 1) + if (my_mbcharlen(read_charset, chr) > 1) { DBUG_PRINT("read_xml",("multi byte")); int i, ml= my_mbcharlen(read_charset, chr); From 7971360ffa00e6a024182b1d437a50d174eb4b37 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Wed, 2 Nov 2016 21:08:44 -0400 Subject: [PATCH 023/124] Fix a build failure noticed on Yakkety. --- storage/innobase/handler/ha_innodb.h | 4 ++-- storage/xtradb/handler/ha_innodb.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index adaad543dd1..eea1a1f7cff 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -467,8 +467,8 @@ extern "C" void wsrep_thd_set_conflict_state( extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); -extern "C"void wsrep_thd_LOCK(THD *thd); -extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" void wsrep_thd_LOCK(THD *thd); +extern "C" void wsrep_thd_UNLOCK(THD *thd); extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); extern "C" time_t wsrep_thd_query_start(THD *thd); extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index cb7dd6b9cf4..a824f4c680a 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -482,8 +482,8 @@ extern "C" void wsrep_thd_set_conflict_state( extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id); -extern "C"void wsrep_thd_LOCK(THD *thd); -extern "C"void wsrep_thd_UNLOCK(THD *thd); +extern "C" void wsrep_thd_LOCK(THD *thd); +extern "C" void wsrep_thd_UNLOCK(THD *thd); extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd); extern "C" time_t wsrep_thd_query_start(THD *thd); extern "C" my_thread_id wsrep_thd_thread_id(THD *thd); From c7e1c89070e34e13cb4a3e947021b91fb211959a Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Wed, 2 Nov 2016 21:10:39 -0400 Subject: [PATCH 024/124] Disable unstable galera_concurrent_ctas test. --- mysql-test/suite/galera/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 771053778d3..907f7931483 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -29,5 +29,6 @@ galera_transaction_read_only : mysql-wsrep/issues/229 galera_gcs_fragment : Incorrect arguments to SET galera_flush_local : Fails sporadically galera_binlog_stmt_autoinc : TODO: investigate +galera_concurrent_ctas : Test times out, investigate galera_sst_xtrabackup-v2-options : TODO: Fix test case mysql-wsrep#33 : TODO: investigate From 5884aa15d40b4dcc6de5cbcf276200c5fcbac938 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 6 Nov 2016 14:57:27 +0100 Subject: [PATCH 025/124] - Fix MDEV-11234. Escape quoting character. Should be doubled. Now it is also possible to escape it by a backslash. modified: storage/connect/tabfmt.cpp - Prepare making VEC table type support conditional. VEC tables might be unsupported in future versions modified: storage/connect/CMakeLists.txt modified: storage/connect/mycat.cc modified: storage/connect/reldef.cpp modified: storage/connect/xindex.cpp - MDEV-11067 suggested to add configuration support to the Apache wrapper. Was added but commented out until prooved it is really useful. modified: storage/connect/ApacheInterface.java modified: storage/connect/ha_connect.cc modified: storage/connect/jdbccat.h modified: storage/connect/jdbconn.cpp modified: storage/connect/jdbconn.h modified: storage/connect/tabjdbc.cpp modified: storage/connect/tabjdbc.h - Remove useless members. modified: storage/connect/jdbconn.cpp modified: storage/connect/jdbconn.h - New UDF countin. modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h --- storage/connect/ApacheInterface.java | 5 ++- storage/connect/CMakeLists.txt | 2 +- storage/connect/ha_connect.cc | 7 +++- storage/connect/jdbccat.h | 1 + storage/connect/jdbconn.cpp | 60 ++++++++++++++++------------ storage/connect/jdbconn.h | 6 +-- storage/connect/jsonudf.cpp | 47 ++++++++++++++++++++++ storage/connect/jsonudf.h | 3 ++ storage/connect/mycat.cc | 6 ++- storage/connect/reldef.cpp | 13 ++++-- storage/connect/tabfmt.cpp | 34 +++++++++++----- storage/connect/tabjdbc.cpp | 4 ++ storage/connect/tabjdbc.h | 1 + storage/connect/xindex.cpp | 8 +++- 14 files changed, 147 insertions(+), 50 deletions(-) diff --git a/storage/connect/ApacheInterface.java b/storage/connect/ApacheInterface.java index b4c8a4e9885..47b46dc0506 100644 --- a/storage/connect/ApacheInterface.java +++ b/storage/connect/ApacheInterface.java @@ -35,7 +35,10 @@ public class ApacheInterface extends JdbcInterface { ds.setPassword(parms[3]); pool.put(url, ds); } // endif ds - + + // if (parms.length > 4 && parms[4] != null) + // ds.setConnectionProperties(parms[4]); + // Get a connection from the data source conn = ds.getConnection(); diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 95d88538119..2122e56134b 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -38,7 +38,7 @@ user_connect.h valblk.h value.h xindex.h xobject.h xtable.h) # Definitions that are shared for all OSes # add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS -Dconnect_EXPORTS) -add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT ) +add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT -DVCT_SUPPORT ) # diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index cf945a73f46..2222e51b083 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -171,7 +171,7 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.04.0008 August 10, 2016"; + char version[]= "Version 1.04.0008 October 20, 2016"; #if defined(__WIN__) char compver[]= "Version 1.04.0008 " __DATE__ " " __TIME__; char slash= '\\'; @@ -5190,7 +5190,8 @@ static int connect_assisted_discovery(handlerton *, THD* thd, PJPARM sjp= NULL; char *driver= NULL; char *url= NULL; - char *tabtyp = NULL; +//char *prop= NULL; + char *tabtyp= NULL; #endif // JDBC_SUPPORT uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); bool bif, ok= false, dbf= false; @@ -5256,6 +5257,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #if defined(JDBC_SUPPORT) driver= GetListOption(g, "Driver", topt->oplist, NULL); // url= GetListOption(g, "URL", topt->oplist, NULL); +// prop = GetListOption(g, "Properties", topt->oplist, NULL); tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); #endif // JDBC_SUPPORT mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); @@ -5366,6 +5368,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, jdef->SetName(create_info->alias); sjp= (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM)); sjp->Driver= driver; +// sjp->Properties = prop; sjp->Fsize= 0; sjp->Scrollable= false; diff --git a/storage/connect/jdbccat.h b/storage/connect/jdbccat.h index 37f33d7063d..7108aa376ce 100644 --- a/storage/connect/jdbccat.h +++ b/storage/connect/jdbccat.h @@ -8,6 +8,7 @@ typedef struct jdbc_parms { char *Url; // Driver URL char *User; // User connect info char *Pwd; // Password connect info +//char *Properties; // Connection property list //int Cto; // Connect timeout //int Qto; // Query timeout int Fsize; // Fetch size diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp index dca9bd0eac4..b31e77bf1ff 100644 --- a/storage/connect/jdbconn.cpp +++ b/storage/connect/jdbconn.cpp @@ -525,10 +525,10 @@ JDBConn::JDBConn(PGLOBAL g, TDBJDBC *tdbp) m_Wrap = strcat(strcpy(wn, "wrappers/"), m_Wrap); } // endif m_Wrap - m_Driver = NULL; - m_Url = NULL; - m_User = NULL; - m_Pwd = NULL; +//m_Driver = NULL; +//m_Url = NULL; +//m_User = NULL; +//m_Pwd = NULL; m_Ncol = 0; m_Aff = 0; m_Rows = 0; @@ -772,7 +772,7 @@ bool JDBConn::GetJVM(PGLOBAL g) /***********************************************************************/ int JDBConn::Open(PJPARM sop) { - + int irc = RC_FX; bool err = false; jboolean jt = (trace > 0); PGLOBAL& g = m_G; @@ -865,30 +865,37 @@ int JDBConn::Open(PJPARM sop) switch (rc) { case JNI_OK: strcpy(g->Message, "VM successfully created"); + irc = RC_OK; break; case JNI_ERR: strcpy(g->Message, "Initialising JVM failed: unknown error"); - return RC_FX; + break; case JNI_EDETACHED: strcpy(g->Message, "Thread detached from the VM"); - return RC_FX; + break; case JNI_EVERSION: strcpy(g->Message, "JNI version error"); - return RC_FX; + break; case JNI_ENOMEM: strcpy(g->Message, "Not enough memory"); - return RC_FX; + break; case JNI_EEXIST: strcpy(g->Message, "VM already created"); - return RC_FX; + break; case JNI_EINVAL: strcpy(g->Message, "Invalid arguments"); - return RC_FX; + break; default: - sprintf(g->Message, "Unknown return code %d", rc); - return RC_FX; + sprintf(g->Message, "Unknown return code %d", (int)rc); + break; } // endswitch rc + if (trace) + htrc("%s\n", g->Message); + + if (irc != RC_OK) + return irc; + //=============== Display JVM version =============== jint ver = env->GetVersion(); printf("JVM Version %d.%d\n", ((ver>>16)&0x0f), (ver&0x0f)); @@ -978,10 +985,10 @@ int JDBConn::Open(PJPARM sop) jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4 env->FindClass("java/lang/String"), NULL); // Strings - m_Driver = sop->Driver; - m_Url = sop->Url; - m_User = sop->User; - m_Pwd = sop->Pwd; +//m_Driver = sop->Driver; +//m_Url = sop->Url; +//m_User = sop->User; +//m_Pwd = sop->Pwd; m_Scrollable = sop->Scrollable; m_RowsetSize = sop->Fsize; //m_LoginTimeout = sop->Cto; @@ -989,17 +996,20 @@ int JDBConn::Open(PJPARM sop) //m_UseCnc = sop->UseCnc; // change some elements - if (m_Driver) - env->SetObjectArrayElement(parms, 0, env->NewStringUTF(m_Driver)); + if (sop->Driver) + env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Driver)); - if (m_Url) - env->SetObjectArrayElement(parms, 1, env->NewStringUTF(m_Url)); + if (sop->Url) + env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Url)); - if (m_User) - env->SetObjectArrayElement(parms, 2, env->NewStringUTF(m_User)); + if (sop->User) + env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User)); - if (m_Pwd) - env->SetObjectArrayElement(parms, 3, env->NewStringUTF(m_Pwd)); + if (sop->Pwd) + env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd)); + +//if (sop->Properties) +// env->SetObjectArrayElement(parms, 4, env->NewStringUTF(sop->Properties)); // call method rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable); diff --git a/storage/connect/jdbconn.h b/storage/connect/jdbconn.h index 0a1c52d4576..9d428142839 100644 --- a/storage/connect/jdbconn.h +++ b/storage/connect/jdbconn.h @@ -180,9 +180,9 @@ protected: char *Msg; char *m_Wrap; char m_IDQuoteChar[2]; - PSZ m_Driver; - PSZ m_Url; - PSZ m_User; +//PSZ m_Driver; +//PSZ m_Url; +//PSZ m_User; PSZ m_Pwd; int m_Ncol; int m_Aff; diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index 8bddc68e2ae..f9034f25739 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -5264,3 +5264,50 @@ char *envar(UDF_INIT *initid, UDF_ARGS *args, char *result, return str; } // end of envar +/*********************************************************************************/ +/* Returns the distinct number of B occurences in A. */ +/*********************************************************************************/ +my_bool countin_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +{ + if (args->arg_count != 2) { + strcpy(message, "This function must have 2 arguments"); + return true; + } else if (args->arg_type[0] != STRING_RESULT) { + strcpy(message, "First argument must be string"); + return true; + } else if (args->arg_type[1] != STRING_RESULT) { + strcpy(message, "Second argument is not a string"); + return true; + } // endif args + + return false; +} // end of countin_init + +long long countin(UDF_INIT *initid, UDF_ARGS *args, char *result, + unsigned long *res_length, char *is_null, char *) +{ + PSZ str1, str2; + char *s; + long long n = 0; + size_t lg; + + lg = (size_t)args->lengths[0]; + s = str1 = (PSZ)malloc(lg + 1); + memcpy(str1, args->args[0], lg); + str1[lg] = 0; + + lg = (size_t)args->lengths[1]; + str2 = (PSZ)malloc(lg + 1); + memcpy(str2, args->args[1], lg); + str2[lg] = 0; + + while (s = strstr(s, str2)) { + n++; + s += lg; + } // endwhile + + free(str1); + free(str2); + return n; +} // end of countin + diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h index 1406d9f2f2e..d2890421c62 100644 --- a/storage/connect/jsonudf.h +++ b/storage/connect/jsonudf.h @@ -221,6 +221,9 @@ extern "C" { DllExport my_bool envar_init(UDF_INIT*, UDF_ARGS*, char*); DllExport char *envar(UDF_EXEC_ARGS); + + DllExport my_bool countin_init(UDF_INIT*, UDF_ARGS*, char*); + DllExport long long countin(UDF_EXEC_ARGS); } // extern "C" diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index b4b03e6ba4a..19c9f62b5bf 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -64,7 +64,9 @@ #include "filamtxt.h" #include "tabdos.h" #include "tabfmt.h" +#if defined(VCT_SUPPORT) #include "tabvct.h" +#endif // VCT_SUPPORT #include "tabsys.h" #if defined(__WIN__) #include "tabmac.h" @@ -549,7 +551,9 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) #if defined(XML_SUPPORT) case TAB_XML: tdp= new(g) XMLDEF; break; #endif // XML_SUPPORT - case TAB_VEC: tdp= new(g) VCTDEF; break; +#if defined(VCT_SUPPORT) + case TAB_VEC: tdp = new(g)VCTDEF; break; +#endif // VCT_SUPPORT #if defined(ODBC_SUPPORT) case TAB_ODBC: tdp= new(g) ODBCDEF; break; #endif // ODBC_SUPPORT diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index ac2327212e0..a62fcbf9416 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -40,7 +40,9 @@ #include "tabcol.h" #include "filamap.h" #include "filamfix.h" +#if defined(VCT_SUPPORT) #include "filamvct.h" +#endif // VCT_SUPPORT #if defined(ZIP_SUPPORT) #include "filamzip.h" #endif // ZIP_SUPPORT @@ -683,16 +685,19 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode) txfp = new(g) MPXFAM(defp); else txfp = new(g) FIXFAM(defp); - } else if (rfm == RECFM_VCT) { - assert (Pxdef->GetDefType() == TYPE_AM_VCT); +#if defined(VCT_SUPPORT) + assert(Pxdef->GetDefType() == TYPE_AM_VCT); if (map) txfp = new(g) VCMFAM((PVCTDEF)defp); else txfp = new(g) VCTFAM((PVCTDEF)defp); - - } // endif's +#else // !VCT_SUPPORT + strcpy(g->Message, "VCT no more supported"); + return NULL; +#endif // !VCT_SUPPORT + } // endif's ((PTDBDOS)tdbp)->SetTxfp(txfp); } // endif Txfp diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 015f8d93b15..d21a8b977da 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -830,8 +830,9 @@ bool TDBCSV::SkipHeader(PGLOBAL g) /***********************************************************************/ int TDBCSV::ReadBuffer(PGLOBAL g) { - char *p1, *p2, *p = NULL; - int i, n, len, rc = Txfp->ReadBuffer(g); + //char *p1, *p2, *p = NULL; + char *p2, *p = NULL; + int i, n, len, rc = Txfp->ReadBuffer(g); bool bad = false; if (trace > 1) @@ -846,14 +847,23 @@ int TDBCSV::ReadBuffer(PGLOBAL g) for (i = 0; i < Fields; i++) { if (!bad) { if (Qot && *p2 == Qot) { // Quoted field - for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2) - if (*(p + 1) == Qot) - n++; // Doubled internal quotes - else - break; // Final quote + //for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2) + // if (*(p + 1) == Qot) + // n++; // Doubled internal quotes + // else + // break; // Final quote + + for (n = 0, p = ++p2; p; p++) + if (*p == Qot || *p == '\\') { + if (*(++p) == Qot) + n++; // Escaped internal quotes + else if (*(p - 1) == Qot) + break; // Final quote + } // endif *p if (p) { - len = p++ - p2; + //len = p++ - p2; + len = p - p2 - 1;; // if (Sep != ' ') // for (; *p == ' '; p++) ; // Skip blanks @@ -873,10 +883,12 @@ int TDBCSV::ReadBuffer(PGLOBAL g) if (n) { int j, k; - // Suppress the double of internal quotes + // Suppress the escape of internal quotes for (j = k = 0; j < len; j++, k++) { - if (p2[j] == Qot) - j++; // skip first one + if (p2[j] == Qot || (p2[j] == '\\' && p2[j + 1] == Qot)) + j++; // skip escape char + else if (p2[j] == '\\') + p2[k++] = p2[j++]; // avoid \\Qot p2[k] = p2[j]; } // endfor i, j diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp index e398523892f..912e6c7d530 100644 --- a/storage/connect/tabjdbc.cpp +++ b/storage/connect/tabjdbc.cpp @@ -110,6 +110,7 @@ bool JDBCDEF::SetParms(PJPARM sjp) sjp->Url= Url; sjp->User= Username; sjp->Pwd= Password; +//sjp->Properties = Prop; return true; } // end of SetParms @@ -234,6 +235,7 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Read_Only = true; Wrapname = GetStringCatInfo(g, "Wrapper", NULL); +//Prop = GetStringCatInfo(g, "Properties", NULL); Tabcat = GetStringCatInfo(g, "Qualifier", NULL); Tabcat = GetStringCatInfo(g, "Catalog", Tabcat); Tabschema = GetStringCatInfo(g, "Dbname", NULL); @@ -337,6 +339,7 @@ TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBASE(tdp) Schema = tdp->Tabschema; Ops.User = tdp->Username; Ops.Pwd = tdp->Password; +// Ops.Properties = tdp->Prop; Catalog = tdp->Tabcat; Srcdef = tdp->Srcdef; Qrystr = tdp->Qrystr; @@ -356,6 +359,7 @@ TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBASE(tdp) Ops.Url = NULL; Ops.User = NULL; Ops.Pwd = NULL; +// Ops.Properties = NULL; Catalog = NULL; Srcdef = NULL; Qrystr = NULL; diff --git a/storage/connect/tabjdbc.h b/storage/connect/tabjdbc.h index 7244ebd3832..fee8223abaf 100644 --- a/storage/connect/tabjdbc.h +++ b/storage/connect/tabjdbc.h @@ -58,6 +58,7 @@ protected: PSZ Tabschema; /* External table schema */ PSZ Username; /* User connect name */ PSZ Password; /* Password connect info */ +//PSZ Prop; /* Connection Properties */ PSZ Tabcat; /* External table catalog */ PSZ Tabtype; /* External table type */ PSZ Colpat; /* Catalog column pattern */ diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp index 56312630278..a2cf4e77b80 100755 --- a/storage/connect/xindex.cpp +++ b/storage/connect/xindex.cpp @@ -45,7 +45,9 @@ //nclude "array.h" #include "filamtxt.h" #include "tabdos.h" +#if defined(VCT_SUPPORT) #include "tabvct.h" +#endif // VCT_SUPPORT /***********************************************************************/ /* Macro or external routine definition */ @@ -293,9 +295,11 @@ bool XINDEX::AddColumns(void) return false; // Not applying to static index else if (IsMul()) return false; // Not done yet for multiple index - else if (Tbxp->GetAmType() == TYPE_AM_VCT && ((PTDBVCT)Tbxp)->IsSplit()) +#if defined(VCT_SUPPORT) + else if (Tbxp->GetAmType() == TYPE_AM_VCT && ((PTDBVCT)Tbxp)->IsSplit()) return false; // This would require to read additional files - else +#endif // VCT_SUPPORT + else return true; } // end of AddColumns From 41e11a8ac6ae62a9320beff451dbd031540c1f7a Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2016 10:25:03 -0500 Subject: [PATCH 026/124] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a82a4e4d77d..36834bdb92d 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=0 -MYSQL_VERSION_PATCH=28 +MYSQL_VERSION_PATCH=29 From aae67535cc399c92cac24b2b1f44e9a196806c9f Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 14 Nov 2016 19:20:40 +0100 Subject: [PATCH 027/124] - MDEV-11051 place Java classes ApacheInterface and JdbcInterface into single jar file. Try to fix the INSTALL command. modified: storage/connect/CMakeLists.txt - Make some JDBC tests available on Windows modified: storage/connect/mysql-test/connect/t/jdbc.test modified: storage/connect/mysql-test/connect/t/jdbc_new.test added: storage/connect/mysql-test/connect/t/windows.inc --- storage/connect/CMakeLists.txt | 31 +++-- storage/connect/JavaWrappers.jar | Bin 0 -> 19615 bytes storage/connect/JdbcInterface.java | 13 ++ storage/connect/jdbconn.cpp | 116 +++++++++--------- .../connect/mysql-test/connect/disabled.def | 5 +- .../mysql-test/connect/r/jdbc_new.result | 6 +- .../connect/std_data/JdbcMariaDB.jar | Bin 5993273 -> 6021866 bytes .../connect/mysql-test/connect/t/jdbc.test | 1 + .../mysql-test/connect/t/jdbc_new.test | 1 + .../connect/mysql-test/connect/t/windows.inc | 5 + 10 files changed, 108 insertions(+), 70 deletions(-) create mode 100644 storage/connect/JavaWrappers.jar create mode 100644 storage/connect/mysql-test/connect/t/windows.inc diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 2122e56134b..46c4841ff97 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -20,25 +20,25 @@ SET(CONNECT_SOURCES ha_connect.cc connect.cc user_connect.cc mycat.cc fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h array.cpp blkfil.cpp colblk.cpp csort.cpp -filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp +filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamzip.cpp filter.cpp json.cpp jsonudf.cpp maputil.cpp myconn.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp tabmysql.cpp taboccur.cpp tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp -tabvct.cpp tabvir.cpp tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp +tabvir.cpp tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h -engmsg.h filamap.h filamdbf.h filamfix.h filamtxt.h filamvct.h filamzip.h +engmsg.h filamap.h filamdbf.h filamfix.h filamtxt.h filamzip.h filter.h global.h ha_connect.h inihandl.h json.h jsonudf.h maputil.h msgid.h mycat.h myconn.h myutil.h os.h osutil.h plgcnx.h plgdbsem.h preparse.h reldef.h resource.h tabcol.h tabdos.h tabfix.h tabfmt.h tabjson.h tabmul.h tabmysql.h -taboccur.h tabpivot.h tabsys.h tabtbl.h tabutil.h tabvct.h tabvir.h tabxcl.h +taboccur.h tabpivot.h tabsys.h tabtbl.h tabutil.h tabvir.h tabxcl.h user_connect.h valblk.h value.h xindex.h xobject.h xtable.h) # # Definitions that are shared for all OSes # add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS -Dconnect_EXPORTS) -add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT -DVCT_SUPPORT ) +add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT ) # @@ -89,6 +89,18 @@ ELSE(NOT UNIX) ENDIF(UNIX) +# +# VCT: the VEC format might be not supported in future versions +# + +OPTION(CONNECT_WITH_VCT "Compile CONNECT storage engine with VCT support" ON) + +IF(CONNECT_WITH_VCT) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} filamvct.cpp tabvct.cpp filamvct.h tabvct.h) + add_definitions(-DVCT_SUPPORT) +ENDIF(CONNECT_WITH_VCT) + + # # XML # @@ -236,9 +248,9 @@ ENDIF(CONNECT_WITH_ODBC) # JDBC # IF(APPLE) - OPTION(CONNECT_WITH_JDBC "some comment" OFF) + OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine without JDBC support" OFF) ELSE() - OPTION(CONNECT_WITH_JDBC "some comment" ON) + OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine with JDBC support" ON) ENDIF() IF(CONNECT_WITH_JDBC) @@ -252,12 +264,15 @@ IF(CONNECT_WITH_JDBC) SET(CONNECT_SOURCES ${CONNECT_SOURCES} jdbconn.cpp tabjdbc.cpp jdbconn.h tabjdbc.h jdbccat.h JdbcInterface.java ApacheInterface.java MariadbInterface.java - MysqlInterface.java OracleInterface.java PostgresqlInterface.java) + MysqlInterface.java OracleInterface.java PostgresqlInterface.java + JavaWrappers.jar) # TODO: Find how to compile and install the java wrapper classes # Find required libraries and include directories SET (JAVA_SOURCES JdbcInterface.java) add_jar(JdbcInterface ${JAVA_SOURCES}) install_jar(JdbcInterface DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar + DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) add_definitions(-DJDBC_SUPPORT) ELSE() SET(JDBC_LIBRARY "") diff --git a/storage/connect/JavaWrappers.jar b/storage/connect/JavaWrappers.jar new file mode 100644 index 0000000000000000000000000000000000000000..d5353d2cbfd08c449d2c4ddc7a81b1f8c32c1ad1 GIT binary patch literal 19615 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 H7Wn@FuwP?< literal 0 HcmV?d00001 diff --git a/storage/connect/JdbcInterface.java b/storage/connect/JdbcInterface.java index 34af8c4e013..07dcaf985b4 100644 --- a/storage/connect/JdbcInterface.java +++ b/storage/connect/JdbcInterface.java @@ -220,6 +220,19 @@ public class JdbcInterface { } // end of SetTimestampParm + public int SetNullParm(int i, int typ) { + int rc = 0; + + try { + pstmt.setNull(i, typ); + } catch (Exception e) { + SetErrmsg(e); + rc = -1; + } // end try/catch + + return rc; + } // end of SetNullParm + public int ExecutePrep() { int n = -3; diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp index b31e77bf1ff..a69f84a94a1 100644 --- a/storage/connect/jdbconn.cpp +++ b/storage/connect/jdbconn.cpp @@ -55,9 +55,8 @@ #if defined(__WIN__) extern "C" HINSTANCE s_hModule; // Saved module handle -#else // !__WIN__ +#endif // __WIN__ #define nullptr 0 -#endif // !__WIN__ TYPCONV GetTypeConv(); int GetConvSize(); @@ -1442,7 +1441,7 @@ bool JDBConn::SetParam(JDBCCOL *colp) PGLOBAL& g = m_G; bool rc = false; PVAL val = colp->GetValue(); - jint n, i = (jint)colp->GetRank(); + jint n, jrc = 0, i = (jint)colp->GetRank(); jshort s; jlong lg; //jfloat f; @@ -1452,69 +1451,74 @@ bool JDBConn::SetParam(JDBCCOL *colp) jstring jst = nullptr; jmethodID dtc, setid = nullptr; - switch (val->GetType()) { - case TYPE_STRING: - if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V")) + if (val->GetNullable() && val->IsNull()) { + if (gmID(g, setid, "SetNullParm", "(II)I")) return true; - jst = env->NewStringUTF(val->GetCharValue()); - env->CallVoidMethod(job, setid, i, jst); - break; - case TYPE_INT: - if (gmID(g, setid, "SetIntParm", "(II)V")) - return true; + jrc = env->CallIntMethod(job, setid, i, (jint)GetJDBCType(val->GetType())); + } else switch (val->GetType()) { + case TYPE_STRING: + if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V")) + return true; - n = (jint)val->GetIntValue(); - env->CallVoidMethod(job, setid, i, n); - break; - case TYPE_TINY: - case TYPE_SHORT: - if (gmID(g, setid, "SetShortParm", "(IS)V")) - return true; + jst = env->NewStringUTF(val->GetCharValue()); + env->CallVoidMethod(job, setid, i, jst); + break; + case TYPE_INT: + if (gmID(g, setid, "SetIntParm", "(II)V")) + return true; - s = (jshort)val->GetShortValue(); - env->CallVoidMethod(job, setid, i, s); - break; - case TYPE_BIGINT: - if (gmID(g, setid, "SetBigintParm", "(IJ)V")) - return true; + n = (jint)val->GetIntValue(); + env->CallVoidMethod(job, setid, i, n); + break; + case TYPE_TINY: + case TYPE_SHORT: + if (gmID(g, setid, "SetShortParm", "(IS)V")) + return true; - lg = (jlong)val->GetBigintValue(); - env->CallVoidMethod(job, setid, i, lg); - break; - case TYPE_DOUBLE: - case TYPE_DECIM: - if (gmID(g, setid, "SetDoubleParm", "(ID)V")) - return true; + s = (jshort)val->GetShortValue(); + env->CallVoidMethod(job, setid, i, s); + break; + case TYPE_BIGINT: + if (gmID(g, setid, "SetBigintParm", "(IJ)V")) + return true; - d = (jdouble)val->GetFloatValue(); - env->CallVoidMethod(job, setid, i, d); - break; - case TYPE_DATE: - if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) { - strcpy(g->Message, "Cannot find Timestamp class"); - return true; - } else if (!(dtc = env->GetMethodID(dat, "", "(J)V"))) { - strcpy(g->Message, "Cannot find Timestamp class constructor"); - return true; - } // endif's + lg = (jlong)val->GetBigintValue(); + env->CallVoidMethod(job, setid, i, lg); + break; + case TYPE_DOUBLE: + case TYPE_DECIM: + if (gmID(g, setid, "SetDoubleParm", "(ID)V")) + return true; - lg = (jlong)val->GetBigintValue() * 1000; + d = (jdouble)val->GetFloatValue(); + env->CallVoidMethod(job, setid, i, d); + break; + case TYPE_DATE: + if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) { + strcpy(g->Message, "Cannot find Timestamp class"); + return true; + } else if (!(dtc = env->GetMethodID(dat, "", "(J)V"))) { + strcpy(g->Message, "Cannot find Timestamp class constructor"); + return true; + } // endif's - if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) { - strcpy(g->Message, "Cannot make Timestamp object"); - return true; - } else if (gmID(g, setid, "SetTimestampParm", "(ILjava/sql/Timestamp;)V")) + lg = (jlong)val->GetBigintValue() * 1000; + + if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) { + strcpy(g->Message, "Cannot make Timestamp object"); + return true; + } else if (gmID(g, setid, "SetTimestampParm", "(ILjava/sql/Timestamp;)V")) + return true; + + env->CallVoidMethod(job, setid, i, datobj); + break; + default: + sprintf(g->Message, "Parm type %d not supported", val->GetType()); return true; + } // endswitch Type - env->CallVoidMethod(job, setid, i, datobj); - break; - default: - sprintf(g->Message, "Parm type %d not supported", val->GetType()); - return true; - } // endswitch Type - - if (Check()) { + if (Check(jrc)) { sprintf(g->Message, "SetParam: col=%s msg=%s", colp->GetName(), Msg); rc = true; } // endif msg diff --git a/storage/connect/mysql-test/connect/disabled.def b/storage/connect/mysql-test/connect/disabled.def index 9b4570915c7..5e15e0806ba 100644 --- a/storage/connect/mysql-test/connect/disabled.def +++ b/storage/connect/mysql-test/connect/disabled.def @@ -9,8 +9,7 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -#json_udf_bin : broken upstream in --ps (fixed) -jdbc : Variable settings depend on machine configuration -jdbc_new : Variable settings depend on machine configuration +#jdbc : Variable settings depend on machine configuration +#jdbc_new : Variable settings depend on machine configuration jdbc_oracle : Variable settings depend on machine configuration jdbc_postgresql : Variable settings depend on machine configuration diff --git a/storage/connect/mysql-test/connect/r/jdbc_new.result b/storage/connect/mysql-test/connect/r/jdbc_new.result index 14381b0b11f..5cc4826213d 100644 --- a/storage/connect/mysql-test/connect/r/jdbc_new.result +++ b/storage/connect/mysql-test/connect/r/jdbc_new.result @@ -56,7 +56,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root' `TABLE_TYPE`='JDBC' SELECT * FROM t1; a b -0 NULL +NULL NULL 0 test00 1 test01 2 test02 @@ -72,7 +72,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root' `TABLE_TYPE`=JDBC `TABNAME`='t1' SELECT * FROM t1; a b -0 NULL +NULL NULL 0 test00 1 test01 2 test02 @@ -104,7 +104,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root' `TABLE_TYPE`=JDBC SELECT * FROM t1; a b -0 NULL +NULL NULL 0 0 1 0 2 0 diff --git a/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar b/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar index 81f91e4465a4a11c4a1593dd6b44232421ee47d5..9d461ad6223b41e2a18d97773a064aa8f96405cc 100644 GIT binary patch delta 190883 zcmZ6yQ*C1l{ zfN`qg0sbzD8=FyI?x#KLUIKsqo%=i<6T<*szHQAe@??zj0~0JHx8<5l@t!Y?laU13)msaX%Akwa z?7|*{^P(yjxG0C?Z3N}j`k7|eR)YbwTdEIGa{c&DzRwWZE6Gvri$|=xQ9Rrm!>{8= z_^fPXnt6f3%(hniGu9+kXCC3sJ6Q-NQVO@X!4M8>M@M*n(2NK1)ePno`1(ET^)(obmAEY9=xaMFd>lR{ERNl^(7CvhKFp zz$HEP^RQ{@b@_6ilG7m4s7|6aKCCm>`Zt`sSz7zPWu*I{LK1tDcA5X_u`4|^(KF;R z*d`%Su?Mhno9C(_QKBu=syb^HXq3I9*bom-3D@-$jy#_?amROZt`0kvQPbjh$a-hGhS zU@Wfpm5T(ncPt7=z=hHto>CqS{7$K}c0a;HgP{G5R~nKsFxzl#X2@4C$V`zg=R{6M z?0eyEbF7uE^JNcsxH9;z&T~Vg8N8g>#Xc@I;tTKas6CWGFx!&10&Es>wIOtn7o8;` zW!`r(SPZGGfDQlN|E3uRa&KbO86Xqd^1f5cefz_ksi=&7mlpN5oSMm=s0OgQs8map zl5dvHWW)zw^bZbJzwRW#rI+R%7l5T1**T6z!=4>-pg?Bpl{Y;VSnz7+vyNa2+Zurr zk~=r?mhs_M4OLqx>bOS^vWOcRUL#*M1mxcXxdun!H6$9q&>wGsUgnhYdt?;k!jlfH zvxwMk(hlsz(Q?1e0}f|l3%Sh-&a&*L*#1*~{ji_k zBOK}C#FGVK>J_a`ArwW?(Om5+5WI8_dnEw@Ng;hUVgwu25e z)zC5(H+M*mtvQ(jr`xiUM{qxG&@I}2_^_amXCMD2e&@}=bXAILu9CAg%|(+7cX*8u z0%w!8HO*NT8GUrE5Hg}3wZ+I{4fbbZTP$Rvi~#Efh+zcxL_MvqbyfFppWUyL+hQ^O zPM{|?DbU0*tP;f@N@=PDOnR>XW)^yINDSUj9S`qbb@_e4mb_G5aDdZoyyzhsZ zB|ir$u%SPmWHtrb2;Q)RZ_a9+$I3#^jA;!#IQ1zsIIRY-Il@6cSdrlzSl2BzAdfwm z%d$g^AW>K!0JIt-CXAGTxU{^B;xr5{_YR8hu#SlkJM)}lLp(1b3RNgzMhmB`VBfW_ zZZ~!>Oluk7Z5_at^d8DH48Cs=--H579D-p4X0Df)TPCNyC(!E^Zh|K|rxEvcLvSi= zp~Ope9?kbsV!gx+elR+{ps`pyU5kPE+VD>;(Yq`{s?`K}LtHo@OLm$jf|zo2ZJVX>uvLLj0o_znqS|7J22{BA-B&hZ2-k?&laoBlLX%(p82l zTW;){zb-;C7BmWQOdS%NR6pzdM6Zc7P0pYb`9gtapf#0DUnh051*U{vq)NQ9@j$ea z4O0Z)=}?%KFk&LJDdL`?6=EfRaRluZJK$p5q80m(=aD~xb+JWGZ4x)&+SF9zw)>t< zDjZx|0e@R zmokqFt)R>Cwv;?5@eu|61}g(QoTtAUM9STQEXqv`-$5U@(KgUT(tz@1!fOZEM|z7u z^SOA7j-WI8qDFB4g}Vw-;o{tU^1agpvAkx>?z8|Ue;C zKGavnzdoT1ndngN@H^~(XM=2G?Z!)TxwD^mt7l z3WyI7A@V+5XCj`&62;mR<+@{PI{Ac{A>#GbWHw3t$&&R0`tK${M+u@4<{ex(r1Wd5 zgAyD8O+Q{{^Oo9+i(uBfE(SFDH6>c|N`xFyOdWC>!CSz(6ks4KFN3FBA3k9cY~Gj# zEislM@exh}Y88KrB)KufH!uw!^|c}N_wNgoM{paa*?l_XSx-wyevxiJC^8yeT17uh zHo94MZ@lfxqcY~qJQ->)6)61?8K4&FQlB^yK__t|b27%KJR&Vm z2Z#Ltze}Nss|PS^h!unID1~0FYCtpbc?4A}V~K+sNSmnBdb#G1Z|wz)|INF(tA)$n zPhghQy%3RQ=KL3dmNmlq?u>i`QD~KPNFoUjY$phC7;*^A3`(c4kCMw+HK}6?n`EhN zhPOpQO@a43$0kw|#LC)ao6Nb7D8IjBTf+4gsG+Y?cslgv|1-mN5ZkU>oX1#&z;c zsfEqp-sm1UU9>z^suz#hV;Hwq&k!IqNFSAKCByQF+ZC&-`l~8|$V_^j!t4W)NXC^* z+{o?u9%;&m9YyR3Zk|R1-s+Xn#Q^?OwcEwQAvr*unMx|rySTset^4@cnjCv|d~9s8 zY#e@N1GaAmUFNmh50L=2o}Q~rX-Onq57X1Kpp}pQzNN;#WgzC+88hTAI^E+mr z$8i=4OjlHWqJ|0<%~EV72@zBJ=W3Po$aenRfDs3}eIDxemtu9b+YcJUe&!CqH%!#X zg>h<&e6_@TqZA^{01fVifjC#iL^S2zB>OIGdMo|rr~v0qm4{hhPEQmP>sKC#&2B{# z-ggERq8NJCVViy)*aW2{A-xOi&)xl%&9sAciXds}_^uK&YF^*$jX=`hYVFZD511?-QFjmHIKhI35TC_;e#VI;c=Gh8@&()j#cQNOZm z1U4aIe;~#7^k-9lMA1C9(pajMRxcBQX5u7}$@)*Xn!F(@l4QqWUrv-J)t4YN8SR(u z=8_fScUGCwzHo+?)g5-xQ;dQpwTF2Mwn~{V2T8_Pa6dC#(50gRqU@r)H5%keCS+Wg zV56kgcxWx|r^k1Ax$l%s(1Ncd_)&}7Bh>pZJaq%U*Z_4)|Cn-5`z`X)w^#m8L1Z8h zyVJNNAf$J;tiX+orn71rbC|z^*{BqJIdrO_f0dy)Zn9M};b&<#_ik2^pJI|Z3V-`8 z)4fMX3QWTPcv1783$`w)Yk=9U)0%aNGcESWYB=A*;jP zdwwSrAe|Ty-|xS`hcIlaper9e%dh~{?@e4SJVOIfm!dGCLoT7ak#S~|=%dYbKgmJK zBDzuc0V%!D-Yp_W3?+&RwOk$JN+J`-th}>ia#>m_E)2{lZdS-3QI}J00~P_P-Za`p zvQDdv2<^%PFkst{C!3O|#a1f0gWRI?KhHH5my>tkr4Ic@Ps`bSH=@)NIfogZrnm)R zRpm>x?Ok7cv^DW7q?R)SY?W!09dF-5hVD;AoM?zxc81EWKa7DuPfS%-LrnWKQC;GG*RJ+#`>T2|gmXDmJy0AB=7X*m4WtVVy^oXi_l zD=KIkrOHG%gyujOI+v&LLNe?8{7lJyCX|P=#w4d5wc0+vLp6DXW(`Jmx1fOJ0gbHZ zl?}gxQ}T?C&iRo ztG6b9bVml;m4JA4eQ8+XGsoEl%hInR-?7aKqon6&$pO$MXIsH^dj!g^bH6sjUkcvW z5PHhm3zlIHXM7>(=6|zk>NcdDos#UcpO3%+9Z!~i=P;u1(u%1!ib4;Yi_vx8(Miu( zo+ZCa)m=2aNb6t6=!trWPE3bdfFlPkDR%1kIe}qXLhKV7Z=`i^Q*8L z6}1)`aXY?anKGCO`cb84Z4{F^b1rtdu(@Dw zfaCF5zc-tT>b}#Z%*J}Sd2?5BNM02YAq^HHIGPAJssl$l4HZO44iU&kRx_f6w`RG= zcPy@UJ1QT_vsCURtckoZSJSIx4L9y1L8X|BaO+`|=H>kkEEUKI`2(5(g#lY4X9DPq zBaXrP8Hr!nQBA&_Zu182;6(Etp_Uh*+}9x|CCWV(L*`q=1pw~fI3A_HUHMb{z>((- zJaiMbqm3AU)$>-;@!I81CH2@v3q|L4T)KmviY=0MK;N;$Q2!@+4~0m^VrQhaL@}M? zu!|I8EFhADO6+&41-H8BHOVtgLCls@N4R#vB+_>)bI_&uA0JD zRG6!aFJQ_ERUcGwK0re!QD2|E_O^usy?Ujv7jI6{W{Q=V3Q?5v83jT*+Jk)ST+>hH zw1AEU^7X!27lmKJQ@Hdd}1?*~Qx~Xh(#QN1x%B<3B;Ohf`~(`Qnv=?rq!R^lp2b%3{5i z)|LmpYY0k)kwkYN5pCV~j+rDaI4AF4Jiyi5@Us{uTjCMjf81OG}qz>O6=;~ucHSt1LVekBFGES1gbv?gipve^+&F72uNFK8ALSvlXYq>`o;RTG z4vt0HrZxw>GU;FJ_QFv7b&RMtdu&UpH|ILAuZRcYT&c(WamcU5goC4>Nn`yL(0M`* zRaDH-%kp>5n~GWX8#i)C%z!BIsK9l@D^{vMY_5dphL$s?Z-QNLGyB7rJM;Kh)!SIr zXwI41s=^ArUh^bJ=^R9hnG=$Z1{p1s+wm>X#@WioccKwF^7iSJkJ$3Fl#eAdHIO7p zU?-w`5DdCF_uB6ODTY6Tk1xr6_beOF;_slwyxw9APBwpHqmGOoZ|dtlPkpfu;mTl>{G)@e3Q6H3u9%^b*eSLQ-zJvab%#vOtErvwA;-E+g3!>vi1;^82(9HD zIEuM4)qLT_h7}t*@mkSiFWq#rvQ^m^!`I!=GI@hru=}1Qt&fk;ZNmL!y3Opu5oadL zGR{qAglVV!2px7nR<-jooPfD9>;iEyaitliM8Z-GF5|M+#~;=opl#nMnQ!B;oa!S- zql;4#N-K-VdFmYMXL{y7EZT6HT}6&d1+pI=MC0Ji6h%>LJ#({j?|2(V&_hOK@t<&4 zy&mR;a`<}1h}B8T^ZCUrTK7rtZrw;>n8|$MVMW2FE92G{NRD51VL;f|m~^^gYw^8J zc*r}{OsX`Kk#-kS*UR$_U(r~=U>BpGl}Xs44l#yyGy(l8EmyLhf7Tm#&Ua|1aN!NJ z@jcb^e6Q)!j*8|FA?K%X84_!*ns3PPRM<%?M#AsUNqB~%_T&`@m|YqBIq<~H>J>kZQO=RU-H~Ra+C&Ij(K3A zxT-AJ;86Ni>4c#|ENcZ+8T^Bw3y;wd4q=*IHf*{Q&Wqezk)U6ms3JLae@CawaH;E< zAm7#vz+G33?G~$xK81VCN42T5%2w#oQx5*?Qo-%=(?m#d1gOV1HbL?14!F$XsK4GI z&7uEuTZM`~!$CcTcMNHR-ZdktsFrgX5$(E*v6z3$OM|+)+ks0RMDN^<=rI7QuLyqG z?~=@ui!r0atFI6S^W~Zo*inTM%^b2nX+x!4zzY)|c6)V1L%8WfR~@EpFLKv`s<$=O zOhb85hJ19$1k91ub|p8ME}i$FVRVvs^TMAk?0i+|h{w*ewJVTT85HcF<`{}O(=`;6 z_RiqCBqOX~-Ut^g7>v6+Y)0r@;kx_dxk>(xv88cS;4NR%5(uXxHdb%kLfXu%_ovFUutYR&Z zs`~h~U%;wBnj@~{A-xhVih#u<=QXT;C}Zj`>tO3x@w_>4sE9pjK;q^vPL5vMi55H9 zvN2EXNM72>Gk3kbL5$&SB#rT(3!e}Rrgf~)gFss@@YyN6$1zB}FMOEyH#2VNaMc|-c6xZM8WnHPw=#Ui?tMh#aXO9!B2Q*h z;JT$eJ}Ce{76!{@Nw6YgQ}h((s57^?<{1i`h>wlFY@j?Z+~l8Wxs_>$?@+qRQ-t3tm^0-zO;D?q8G7&4lHfJl}uvjDFMxeO~>!HzhbX;`gsO zSI56j^?GLOxo_&1n@6=)n^QZsWH?Gsu?af!kyW$Wx#J5jTkBIIn3&TAL{q4*yE%RC zMc2};#sCJ>me-GflUCCn4MU<`1)Ztx86Y>l+j%%|iS>MuzcYJw6S|5h6sNdOGNXMb zqdj#1{T2D%9g>bF556H3=fo2qza)cX6ABRRJXHBUWNaFlT#`V&P~3WNv9fo8bwR-zqjie79ENUv55#Gq zzQQ@iuC3ZH)R-RKUC4+tiwrvar-!5{|2bOUnwi-dtUlwRYI&k(ZF|oENY>6^Hk&d$ ztxvCQnRe?^liL&U&ljq3EOG?=g;!}r10rpFl4ae)DDGlg)AdH89Z>Rx7>(3Cdvrwh zf{yw@@^5mNNA!kqygOVv@3;-Q0JmnW{Wl0Rm>OP6bLNYe!*Jy)?HtlBoAmGdtkb%f zlI8V;e7YAprU>#&^5EIq4isDRl9z8?K0TO`-Xor#zEQv5$*o_hZ&$VVn1mxNfui!S zoc0#I5?{CUp`W!j%s)uY{rHcp--6q-z&z;J_(zhTD57I-LfYNHt6FG#AkcqJ4%BPi z@LeP`Esng^`%JieHvi_YgMS*}JuZIbh0&}u5TL16Sx(aX)eGmk$XL0smDwP@5c(^ z%JeZ8Bsk-gR3+UjGIzb{g_j2e<_D~Lo?a3=-C3Di)LsnMNYw%c@Rf1{;gln#Z4KqQm10LS9HEi}y?iA+L0*mCaUr0g$1ONGE;0#fTcJ zBS-~!rcCdbENPQ|_-VSk)ESN22^h5d>}JAc^~w#a3*La|1bX=!*0FkucAESSDs}|+ z+#CO2+_Mm`K;uvYUe)Iv6ChWuUfHo$M+u)ZbDLHhHw+i)uk*zw_j0xG&j;E5oh)Wx zfcqc7Km(wuF8a;EFFk}fD`MRAj)fJpfJQIAW-PD!om$QGuto_9^g6;wQX7TH&!h{&!FS z@|+R!BR9y`N6@!aUN7va(;M+zCB?gNL5Gj_>CdIa&nmj~#FYpTdhQ1D9U1g1TjU35 zlDG5ngGvi*J@{PJQgS4W4afoi63#mPagdS&B|EyhlY9D?M<2-{6k{_U>D&(OcMX{v zA2RE|>n6;oicF#*Buc-WN3O5upj6FOs>QD#?VXhrGPdx0?|w#=Zs^8z27`(2!XQa& z9ch7Xl&bo7GSwH0%nkGzILQ}`j4&K<0b2B(H6h^MAc0Bzj1$V{4|S2|Kb#`?9mX>k zr3Fgb1q*7$cN7`qkVlh*0H`8i@P*mnM>mqM_GId6I+g8s$qxNwCgKox%JV_5M#Rc- zr3H1RE<_+KMttBteBLV=O#p8H8(Q!~<d{HCs3rv_n1uJG9fr< zTdV*GOIE7ai&c-~$o~5|vTZVruVr_npP*i~f~e+Mzmaf>Q=sgn|96^lol^IO@WWVk zB_IjtkX+GVNLt(@EA+&;l(+-Tmp$*)C=CdtyBNjL5YDGxs&p6Ja8egm{`v($z?Cew zA@7v=LlpE}P{G=}wpD|9GC;d8)hufexGZ-jw^TJNN{?<6@ja5P=;5BLJ*KI(f_e}{|E2@F#yP>{m00~O>^!hqyWyzPgF~Wa%hr4 z$|>4nZm8*rx2IqMP`2$;-Ont!FCE(|UiW_wCOaV<{1#$SH}pfLB(xa0o5ua2lpfhx zZ#oM*<;Xa^d}Hdp@$0?e-}!zzZ`}bU7}bWugW$Vq(g z1KYIPl>C-uxCk367Y8(hZL)B(ZEe~LO*QC+l!rCC$kSR}@> zR(PDbmmpWliTKA<*QnG*qrp*WEviAnhQY%nnx`p=gBo;PWdp=lKQf(hW|nueZHTMU zZOpWr_&TD4f=$FB{GFPP9Q+PnLOu8Aiy4bum7~Bw4bkBS?u#KMGL`RNaZeHL%J--g%L>0S8Xa0ZK`&NThndISF%4< z@d-wH&Esfj>83RdL6xB>yJA(R#08j84j-%FiJ%R-qOfdEN1~rk)N#3W)GgK_Q*5BA^YT}qov_KNuRtQ3t!#_7 z`<*q5`2Ym#{2A5fn)blV-Dl@oYwM4rhguEsGMTp9SY5jczk)vH#pHv*zX#hic)Fyx zM8t$-7)vyNHLC$U!l8K+_L_Nl6k^oP$-_A&6>t{CtY>NkHBZb)asQi3lG3-m*s`>B z@;>%g!eAvud2(N^uR4#karW?(TyH*XDnD3DpaxpHUYI2k5t;Bec+4s{v)DfEr0@cw ztIlFhn$%d%G5qRX<{+&0-zxKG((gYzxu!eF7joERWbYscH<_*IwZl50uEjn%MOP@K zWQi^A(SN~uIN~~e{w5TL4CjAi-WGW<2$BeHULuHBCu>eLx5jm_6PoX18_BcXE!C=? zivqsFiH*VyurT6-g>FxtZv3882u%ga@3w6YCdu_QLuOt3T+<##lNZ(NQ#%kTV_wQd zigBlSgMStlz2rq|qN0djva4{ta~b)>eS;>eFXyw{n8a?FxKG_*jr*tI;rS z>cWE&6nAs@m=!5wd?aT-A6R{bvaAytA&a4O>s9jXtHPfj@!QA%Q0rxQVY6SGw0y0_ zBXsb-`?5rVw++3_3m^>`lREU^67AC5z2Cu%-ZI)f;!xj)nteiN4XGD_3)R+tngc6F zPSBzsG5eE4)cT&$99d1tdzJUpsMf!Ti2SrD!*5hZ99H&F?L45p*7cNM-H~739s~bn z!}N-!sob^)_xG}9s2eNM>ilM%NE6K_{)Yc=<3q8xm0W@N56<#`8JGWQe3Jh^#s%{~ z2fWgv1_%j&%9d14Y(AkZ5ELjJ_DP{4C>WFw5J`dgu<~GuAXwDNX)G)mu#IB{EzObg ze{8X_n@j-?Aq6CJN_{jf%ce1U)zuzn_nOt!EqayP%SqoS)8--bTyOujjwddk zcT+0~`62YRyT%0}^v^M(8c9cBMx|;(fosuN_R)?3w@*8#w6Pw;HYQRzoti#bgDNY0 z_bP_LbO&ddakT6nAO*#vRI_n^8$IIP#OVs)>m?pef)Uz0mw!?7`QOM>P2217wx zpYIic=KbR9%|Qvx9RL2=OKQDmdQ`V^UA{o#`zHp*sV8S(w%8K!IG03$rE4&^kfLY; zlwHsiU0OcCNc+bMnw!BjVkN=yTX=_Kp{S5r`l-B~xuOviN`?ZG-b<&W(`lq&1()_> zBp7F4r7(&U_0959n64MCL?dQ<`_CWhq19P{ihr03!zJxB65URdgq}Mb=BN8Xw-#Ba zNiY(2X7iP7Y>4{U)qQ4&+s+yyXNd{g&KN9cu`wR&8IYyT98m3U9UK2RFlDC_kq~JZ zXW~Dcg;mJxveByA|itktsb0h_i+Xyt4ygu@BW1+THp4&~rZ?{FF8e(b! z^Boyby;DC5<{9^7V&d#*{Z%>Ywio)Wn+>dRodvSQ6@xn&l$7h#cFMtAs4_@J)q& zO8AT-4E7K&S)BtLTR^l*8t9CEOIisd(Y+$uRHa%Ef6j>H{0Z{BCm0b0H_&jJ^W!+S zySXI^3c-tvP;@^)-O#{A8rc+=_rLNKDi+1a_WQkJPW#zwwf_OsLZ&K{^?i$$5NK|g}n{Hl)n8lI~gCq53T7bh=PqiLNl<>%a>l?s*R> zOW1`?D;XM<($bIIO}Sc6^jCX1JxiTUXH)}jrtJ+bEe0ueP~v8+DuLqJ5s7XP?GdbM zNM=i-N*2aI4xpR83lUHI*r0`(JzQH=p0W%s0P}$EY+&uXIOEwowR=c`ZI=OK!|i}Y zsD14YLsFgDXNPt2Ed9uJYJ!7kIMmf^yk2mO9(OOx1tQs!mw%6GmTVN}D%-2<5kZ2ZoGctAfD)3978^1B>0RGa&gxivO z)a}y6k((~*z=z$my>CV-oR;e%3&AtZnBH&;t=S7`Q)$tI2G%?$0E?lY1 z=U>P7+ovCSkVPB>o~yXmpb9=Am-aE~wsokTge4fZ_V0G^C~=+5*e69pBka#DZz-^9 zSbGIvUUn9+xNcpICFeWjN?u`+dPSzi@I%kgANK?&u?{r>R=Baijkmj3eoG=U=`jc0zN62bR>x zwqz3ZAp)^-)5NiHN~x~PqdOpl&kTv7lnENJ-W^rC(wR!jEqnOXX?K_=E^2MUYfVXE z#KX^RI~Z+CNq2{g1Nm0aJq5;xfc+L>N050}zbokB7RgeUizz|X?*JoDY-Ug(BL==0 z7T%l?D>_WBonYA&aR9TzASz z$q~|4#K(9uQcQjP5`$0R{Us66?)R#xH!^htfs#O@PHH7T#ORlJ=a&L{rCf$IGTYc66lzY4gCi7v9Yt+a(Q@-=HpOHagsEx*>D z>$=G_jce-UY0Y^6)V&7d1?0G%KJqj8 zi%VtbzdopQzxm=FR|Hj<_b6?%SZoEu&euj3?U%l91sGSs``jxJbZ}{4u@~$Wq zcfZmHcBBUGO-pWUb5JkR3({B!SJ^R{DRUS~4C#;A94cii2dOx2Hy#Air52=CE9yh&ASne{Y9#yg#X+}H3ci^u9rqR2EYz<+r zIjm87?NY7B{IwuYlA!*P zPTv+z9yF0{_5RyIS$mf7`!Z?XfX$N@TwP2+QBj5zw_zfC(8ABaMvUq@oKyfHN4%ek zJ%2S>OoQ2g%Vqqs0Q;g|?q5}-2Ou(k66i}HJZ$$(r|)PxhPfC5s)nDZU$yvtXzit; z@qv0eMf>l^TZGXc=|fRIKA*q)#^NNMGxov!+bmIw@$GmJ$`~>7uwZ3_cWcVzJrlrU zyK6|0RYev&oWtz|@j135S1U8;us_e6y!L!O}s3gH6#p_pX`e@QrXQY8-H1XT(=tk z*?It5z@!!oawhN(r7b%#qO^EonjE0b_%^{HuTjkV z45EK@hrVgAGHT~C*%aBk8n3R&Fgzi;1L}B@s!0b4&6L54(u5@p7vnq51Lnwpl@XMy zJF!_iD*;K<+-8NQG+@H z@N;WnTTx((Fike((p|t3AY6Q8Xv;f>yy}#k5RyO;R@NH5}u^V1-i^SO#*PU`cd)XtvLT!AwQ~TPfvDSEou)z zBz7UolM8`EjOJ-FM2#fTpPW62U3=klX$eBW$MA0U%jq$#7#xIL(7|1@kisDi0$MO#YO?EEF z=6sNjEeGUZ0kU)rD`WT3b^de4Xb`TN6c^DF*}r-exoNMO0j0jJCF`|L>X#qk-{H0Y zEs6M}T;5_Z5RhA_|2+ayL-(J_um64V|0AA36eTr88D*8EnE&4av9wkid>Y{92xh=b z?V4+ex(!rGHir%VNmTt|c(u5VM7twZas*`^Nh?&{7!yhK*OOpccTkbJ*SnTt38(Dk zdgIA`_D$9>{9SvmB=cl8+Kop!U#X$M!=Z4B$A^!O6Wu`HAo!cwn*hC-;d8mJZe0V$n>6mqW^XSyYN4uHco#4K zUtVrcdyD}FbL!fYPhZ>j5y-EIu&=gEH5%3Yf`P7%-vf5+57e2kt;veydX)UEeX`IN z0BUpXs0DY-TD0bRQ}+rKt)~?YvnV5MLkuB+4Yy7=?%gla>@sJ0%_!isXqD!;SP$6S z%J0qWSEY13A#3lM6tl{XJsoBnV4ZI#e(1W_1e^*i*7+XEA)o{dkY8`!xyRASo?f!;^rs}gUil4l-3zJb-@4sZcr?*NDG%dNwGevh1$M#YNg&sOf_|UgXIi$wv0=o|92Ig0o@y$lkDoW_ zIcn1~5+-Oj;EDiJU>KJgwEc);X{8PTOAB+hOeC%6q*+}RcJyeci1iZ+XewE7=8)CJ zB&h0az#Yd(2n80fhgiE;x_I3dvOm?0-nurC@)UzzL~N0Z8X^d*{KvI?@@#tKZ!1>C z_1m)lhRk=a=(t4sBy2OYrxCWb(|fJo8b@kEf(28Z=k-$y4=ixP`>DrLtMif3XBEs# zb8%OY`D;|6*Vij0R4Lvgtuk_w`dZmJN;s~syV;puqeJ}%ZJTJo1T<*y) zq&vfqGZqJ453rho)t!CT>*<0f2*_-YDWcyC4;F*XV}RGC2&I@0g#|hqLwWNI-~-@@ zR?M|{5p)1!Vxj=%eK4dvB8$zznL3m_!htO8{p6S)?YakY3U#yRv~f7?iF4?>{SY*3 z6mI@F5a8B97vkqxH${u6iXS;4Uu~gAl{511fJmYdx~=G~u=cv0GuN~rP#(KLJdg~V zsQozb8TciZ&ZEChHr~=4?qU7oh1f^9F ziI!AK%qX(T#Q8F6xqOe5^5oSWvXl=z;L5=$FN!+XCNtg~wSHN#Dl!Jw9qh34QHD%{ z`5IRfTmVq+jZ8ioRCT9sMKREU+Yy9cz#HP9=)7cRvab-PHTl3Dx*lqm!qN4*Z6Z3R z1khrG=)k|QFP$@e-{$__V%czNKf}@xYxM(WvQCCGA#eo*2m3TE)}AKr8Ee%;LTF?L zU}TJSD5X8FVqMx_Y)<;oxxcQ4QBS`E{w>c3N_Gx~%`HMJs;AXJhUp5;UAA(Bg2d^i zp(7?&k@yYkDXb-ANuOwUB*n~zlOZ8$33O<}ciwV!*Eq5nO}$-M9E%V2F6Ss8H4Z(~ z6&Dy#)vukL|BaN?`sW#4ELZW8Muq9$9{l;(H8zx6UP~CN zp!Q_HR;JQ>l*os>ZKa{X+I_`TMRA^n=l~KHp0$d}_CZX=iWUv}z`NY@p!C9qa-n&&?=e6(qe_ z-g9iINc>LVjJ_?Q|3Q@Gzt$rTVN=$`qh!L_6t@8^&pBdt=xsTO?H}+P{XVv3()$g?$(7u z+_`xgLR+JpSL|!F4dX>xBUI4uz(ffx<;ghgP;i%si%Q0_Sqi6$tR2(%8klBBrc};% z;b$?V1UNH3K8rbkmZ&4;w*tut{!5HT9a(G3NPC(&3s6AHM(R-c6IXy)lKjPS37n`| z6~F{$T%YH+4=UHv;?aj8c@w6S$b`}Y*MrcHT@Albr(A^t*OL*$|3^9exXFVa8FoER6~9SC7VZqEfarb<9s81%zkPo}(S$+V|TqMN8k$|eI>twsCn>VS6|)z$-j>5G1T z8P;`}9EV~9Si)XD2ms%z*o%bG<9&+VCjHJP&`|T|xu)nTWy5>kGXHhIOQmXaSy%@= z$&VXG34Rv!!lB+0?6Ch8+J>`0gARCM#1*g4f+coR%;wfZ<*|0CL$p}XcKaW$XgF<+6W#6KfYp^;KNK4tC1H#DTgpFX z*>$)f7%qSGr4-Ro^9%EQS&eop58$g1^n+}|k&hsu2&@5hR)12vBId0|PyKNDAB$bz z^_0mMD61+BVhcD_m{X8-U6MI1=DUQ5)4xb3ZgVW;^(ttYb036WCXq&^mNTD~1vAmGyLK60uEV!1o4hXNh0r3YO45NK5p05^)S zS=?c35AKjHp#Xw){S(X|&l-zB5RPLU-Z(C?NOzi%4!w5A^S#ERybZ|WR6VDQY+0zw zf$f{$rFVmbyE_@v97)WQTH!Nkx5DwmyUK27Gi6;jNGzYVRxfHQFV__in2$bOY)_Y? zKyIBW@sSNm-mH+tjH|-80**@*v&K=GWvrDGcz~ft_{mSl^}_BNa@LD*V-xe06~twg z5SbLJnSIEkHNq$H?C=mYj@hUGiLK8eFrX}n=O;pTO+R|Y@+r^W7-AS`;yUlFFFs!hkLAZ1lx7(tlenKRwt16ezFL1}eZTOhTp*BsqcHctaJ{O@6iRTfhEGUw~pjf$gJUu@f2Kip>PkdU=wEhQDCj zDi{rLhTFS1V&Nhxb*K3EW%T^O@V((2M~Kfs#flddaV=NuNL@L_*X8lw!lt^r(qaTG z?muzZf@?wjQylAq9zm@ ziM^w-8wE>Zk0{E<*f7S}6-AvGqoT1S8Wm%U8Wp>-ViFU(zuDb+4kX{t?~gYxH?uo^ zW@q===kfNnl%@lgR{greGjLM=QJn+Yw z_Ms=IMtsm9B+aMwCmntA?*1<=deKZ@%Xp_Pxxc))`Rc_z+YNih?d-aHSC>t%$GtlB z>i(Nzj<-LdZ=g8n}7yqM%+tknDDzt`j4t+eba{4|Min5dAgII&CPgO_rS4RtC|fS z;nK)8pkev;QB&_9U(jU7&)U1Mmo5Bu%d_|H^-nmu*Z7`<>6DPq3`9 zs*2_PhM1aXsXskaQR+ToYI;+@?Nb*=I+U0LeMStp*e|!os_!GO4IUlmbMw&8C;DE0 zHF<{Z@xT3cn_IO#GI&^k>!Yas#ddopRo)r(^3#d2YL{GV#fb=ez;?J z)1_Ch->phX8rQh|32R>8FEYPzo7q0k{4R~{+vmHlI%uPp?RMAaT;1aLqs^}R-(I*E zvfO{-KK%yZ3>QzTXg#*lqsV*H3gm{cq^hs^L?-PWV(^>Kd7{!Li?G1wVZEm&N05WO$2* zh56riIQ8V|)~fUOc9gd|x-_ntYE|;>8(Ww5*;IaUzB|n61iW%F zj$Zem>dgE^L(j4X?~MMa!JOr-T!)VRtaQpRY;#U!voB-z?ETf|ot{%3uRPx~^uWem ziQeZE+?O10J9OKKv{8O;jbX3n3iGBnzLOI7h5gY!HT2Tg`N6F_6n!13eVOV#KBQYh zi=O*G*;6$5ZokDTXDT*TIprQYv*_f`ZBgd;P3KO|3}4!I;Hkljme;Whc{lTmWA*g! z&pNg9@vX|A+cc@Li7FiA`}4~dvkuK}(573Xg3XzkS(ztxtK06488Y1NT&}w>|H><`=&+Xqji>szDmkOxdZ?9Oi>Yhd%xm&2XZ^Rs zZJq3cn@)MH9vbe^`qq8cqp$1Je(_h=UozXfuUPl!`PTGt(b1by|DE=9Pg3#9cb-0q zR*k%O`r9TYUIxdc$14N&H2vwws8J1P?Y!nvaC`1!%Yv`QefYmTTh9hAF>9XoZyBl! zOV2+s{P&~<=AJiq%<9)CaOSY@axSg;`-sz}LUmf5=p~beCw|vPyX>QlUta$7IqQ*; z=FrUl(e>Ro_wOE9=fpSWY1?kP4BgP!``6yrVl+=*eDJc>xGBrp!iK%SUT@KE-G;tj zecoZ-UPHa;s!30e-@N&6nC0&v2m7vjUOsJBG3L^<1`A5!+T?fsrjcdjt3L0Zif`<5 z{=wsGNCYYdZ@^wS;C*4cRR3qxL#V@c$Q!$bdh)<5~$y@!8y{mbi(4c{+s+ji~q z!TSIGuX|+8BP4tNr4$ww>gU7iH1?~LzkcwNwEKEPBj@C!u8o3U?{0Jb?(084@3o<= zcmIoFo?jln{=w`8%Nj>6TXF9Drhk9mbpOjXKc2gM=lHQ+Q=QM;(Q0P4`lW@j-J-7B zwdM=kn?zC^mu#}if;b=+9Le~Z+P-A{L)>BWU=x^vjl3AjVwi2oDc zagZN!5JHtV_6v~WU2E)DSN`SP#4k$zm2oY@$TFJv=~>B*Kn+`R%HL5UO4|7cvGTEj zYIgnIY$Mz{r4I+FMzPq5U{(B{BvAXK(w74s_=O#F+aow9Ji5}FA@S;%D+ml zbu_ZVPf&azYHZtV6Zj?utW`<0>y%DLxY#)0w5$9bGmf}3L$?4Ob7`0D1GcFFR}B)~ zBTNwv(La&8HdERgp{i#<5ov(T!&zyc08e7EHK0Dc=@W2;Xt?5U=8%%@2k~P9`uNB} zmrN!xN6RrDY*tFP4*r@Kkmn-N=Ij(Bj4uh8FU16;(VToHW|p_lj)t`r0Y6H$An$Cz z9FhkAe2;xU+^mC6=L1yIKG5|-z%nwT&^RMK+l@U;%QmvWaT#hzyByF~CpqVT6`W3)nyt&0nG|5EBG99tHFzAh!iWTX?c1mOw{#AU)d)7X1})!%a|wN$S7{evje0*j7`!J0J|?Ra+;3-O>01Ilpg}=kAw`W6PadpoN0i%Xa^N)@{!yDuBXj78 zQIuC0=u+$ZM-cN_ps%xJ&dmilW)d-v9E3)~-x18zD?km&3j)8h7b8KnC~&KToFrVp z3A41$+1`Al2AsbRjFmK?<*LBXYKa}ZV@+TK%0sRSpekPxON@KLzfW>L~v6;8M85+@Av{*T@te9RlM3Z7Kr&$n@3z_~K;Xa!SrT@6JYc*%8YH zmL6|*IXhbo!_Nh3C?u?N7|wBo%{KzK8>IvyP5B&H`7H3)+AR2R2lhG#UA*r_U?Rz8 ztxd&dla8I}lI_F>cfq>W*48wJY*8H_%e!W4_!tA&sZ7@?NzqT?3^A^(Vb^Rkyk|6d zl1tv2=mpEYOiiTo0R5s>{Ps6$du&S`Js5&blbxg{1z)^xgmuxT)|wic@k$1M4NMD2 zu6<*$M1L^>?Nrb`+ZAp%GL0k)mT#>SE+;ZCsHAcEPI4J2DlIgZEpg5yt11+Wy!8j<)JlC5`NzBu%w;VNUz1pc0}X;v zQA0kDt zXBcr&;G7D3^-HEhS*h1ci7PAhagnTwN}|ksK-nF?0IPNq66@cCAOn{mg8*7SCVBht zUwV8-@}m%-tUS<_Sf1?YDR3<0M5a%Xuenref7~qBR<>`sn?EZ*kr`6f)>1@s3cs=! zFlQE7k?B~Z52i}Bd5sOh$5vzpmVF!?M-yUi>HJyV$xMf$AL`1`E-Ftp7u~IULfV77 zf#ZFO{tBt#YYx&Cy$(HEZ8Zt{H*A*_vtp*1jrldxwd_v#BXUHsB&8{O6S-6jDl3T! zA*+=7nCCaJFMAZ7LjLE`#z|^e#i>lsveEGdvauNH$f8eY>dN*f`pEgk3T-}GUFO)} zp{&+S$ZtB6sb#t zS!K&?n$0CH!eMO0*-T^E=y!gW1*$0D$y`+0QpJ8bo9R)O->$hFURItwPHMyo*SX4x z1?MsY$|k4&PH>TfNU&^rhZY3-Xc7i22UWfQH?fUgi!L{v&(!{3;t2$+_zgLC>l{m* z=Y0@Lb9spIAzo!wA6f{;r4iH0T4qr$%WA+?t89N%!btrn+cC4;i$gAgt>#L=GxCZZ@-tzh^pP*_BUl zd66r^D#OZu&omZI`RIv^MQ$Pva$)|LGM&n{eEc~PXxb~PdPGq{vAS$-FRjFtE$_XI zWD!P3Bul@XX($`fcL%|FX7NdE`Q=P)S-1Y92+lK0!0%tq3@$RvbSerPcuVpTH3O#< z6%5v~?pHEh$}$Ey(lk-txC{k@`%6$!d7zoSxsqA8EMe%d>R9I>L)rOZR8V-J3)urc zaie(^GlQ7nYNo!Z&xpN}v8Wte*4(R^7L>_SR5)^tL@DZ(^%zCgFIwI^h#9Y8rdr0l zOJOFGBllXSPucQujU*c@zKTWAChoLyy!vx@wd>-;Ra?G zH`V%H+9KT~sw-9tcfWxa_Mc28s)!d%uFU!ynT}->r%(b5?oV!H>dWjtQ!1uHp{(iW zl$2J9c1>$wHCJ$v&x}3N93r2%i(b!=GU5a1-{l%yR$4e%PAN0bZz0PGCs$Tb{2q}q z&kriP&n^m5Vm-Y7Pw*Cn9V5z%J4n;9DR7JgI z0|ob0Z03EGYw@ZdtE0%muH46B_~n}I!D3F?`^Rb)c%0=?bh6?n$xxIB4kudxOL?Z|JUf$>tl(hsA5ta zk21r}e`!S#)<$qy^Sc&F0HeZERB+Z%w($OGUul~6j|H=tk27_!Ok=ZFu4vdC2rI#0 zXPX(sf-m9Ra!^NSbHA6IT8U2Ppy=T?QM4=UG1|r``$(*J7FPLZrV5r#wAo5svkYRK zGOEaCmYjmsQo1B`kqvEMu^L&R+aep2EZ&0BsJ}B^*=D_qEVxj<(q;!~S$W6K!V31- z)NYvo>)jJMoQc(=;;xMooY-P>o{TA$4-RAqbY#u{$;3VOHXAd^RUYWi#FS>=+XN6V zWNQKBb(18sjw$@vrcBP0&5oEj8zhFaKT&%BR zuo3(&+eA}Dh#m?l7-8ZKn>Ye;vVg$h^jp!>$o!w9HnSev1XGj3Qw%Epwuzxr2sBP8 zYx*M79h$3c_mh*~$Mgb|gYEVfGR&sWPK&Ir8CX7|w*4BZ2@GR2} z&a}7fPFT*1BcM;ZZ6v`Ib)3YE@K-49`3&1SgjMu#0#hejIt?f?&-Z7BUbY7I>O(wC z6z57S!i^FJjWTVI(`26de4raN&as_C`d1eDNFZ~5lNkwhyW6&t!vUjhBE|i@5Bvcq zuB<5qC$z9#mM6UIWBZhBkl#`gb6vPDt1h(fZ##l!Ecf;FhsuGrv~4Ovf>PuR+bnxF z(g;L`=2qOj2ab z*7-xp=eA4fw{RKf14Cxm?xRyHK`G;BTcw-eqDxAFM{UDtX0?6C9Xku@{SxVGujpt}Z)v6&2J}+AbyQE^lI27Z9kT+!Ya57;WdkM>>GrE!*)m zvqoT29kWbu_`dBsG)Kg>z-)HRssm|{Z4cIP1QQq+CzLh&iLEb*#j6(^-Bme9lox^6p+j|T>)8z^jzV-#7ZiOUcY`9edOD)ZB@kEY+cLPVF$e}` zM@5T?8YjZ<$`U&lmg|X?Wz8Zx7m{D(ix3FW{t}3L!&pJF2%8{QP-^E0IVE;Qbn1hB zw552Hoju#_h1L#TW2Y=<9I<1Q5^sDi;N0oNNQjQVo!Bn#EO%(L&8`m-EZt>SUn(G4 zG2V2!_+&YNO_Q*th?BDO3MSZ8 z)X8#V`E@Y)a{jPOso^*U>kZfL+6B;}P7M^pSt=IgpXC8bRd&-T8k8nTVyF3Mx$OAI zu07?Z(x8f&7yQu|pFg#mM{)M{%$R^I7sz;Fw~{PwwIrVl0e1F{r8;~yQKVEcg!{vC zjr}5`$;+a^mIh`SSdT!|FyG1kgv9cGks-npX6o!ysk!G7A!Tx|64MSa4T9pMhzoBv!{l>7GmIZ`#*@Wbw*{O zy^0+P#^{?p%U)@{3}4!Zv%I=l8kjuCz5xX*7BNy4=hzY*t6>o44*o^NBUh4QG2H!un&3cj#Y%~lQ+vGG$BH*!-PVl-$dsvb>;Yf{JP+V05=8Co5x+q?S#H#vtm{SY@Kn;ENpb)57YeDj=_m z^+!Rl*chxTU$;<|D>0!sLeNC48kW4HIzu#TFm#1=tyR&rcAEc-j zl45Vk70_Ab@qa1PBMy}ro~fGP_(V00dcewG9W1PS0#@qEv8o*&)#1k}zz=g( z#d6^h`7K~$7OUexm*=PR=tv`vA~rTs%7#wO!`KpG=tc)@!_7#uRi+O zv_|DZ&lT}hH;7fPP#IWkV6++rg36dI1B`ocdx<(fPzr_yg(Q>uM~Ww|DgM+zM7X-G zR?gsU12R#=qWWrmO(hKuK1Q!@LUOjiMv=%B8$=Y|tN0x2sYQ7B;Ru=uM;ili{C<5b=@b zU80Ah5?DzK6lp^r%?k1)2g1}*nnBc-h(Q@GaZvOm&9fRaq5Cw=FExG_C*hcWb2RS| zH$kYfShJ04qaaku2mQKCvx|zZ7<6E@CP4aLY#(DsIC!ug@8Gs8cAMrbl`+v5att)v zsaZlm(Mt-T%O1_Yvm2TqZA7hD))s5U#tjay<&r4+6;W*vp@+(S4z$a+77Ui&4i}9% zKRSFN`9t7ghb81du~9A^;^@R)x5M3}eTBnsO6dRUaGRDbo})|*+L4U5bG+uzgL);t zOmYMi{o&A@EX_}tCGf>PhxHAmajHpdNTQC=}-@Nnbm9vBe#5<9BAJRzvHkY{x80X3rB5?$RgWjbsS=a`JaV?&hsD|?I91~|rx5@SU zYe!Gkqa(I5jaoZ7dr6E4#kqT(9AS7Dr&}Z{-zKo615Pf?sS{?=yj-W>y3650T^wFW zBLzqN?aC?w&1&d+z$u#wn5dGRFw=F$rQ*>kCp<_I&#^=wi^Rcn-swJ7C55A!z3z0LVDtu_4OOQ&pFp=4KD>8xg(RnFdQ_Xik^Gwht-kXc3f zNJ2CqTDf2)yJQZ`cXr<2jZDVN$+%(8-jLtl`3#9E?Z`)tALgtaWk_K-O9X0}%QRG= z=_uzj9|}SuHt%Gj7^%mcPst!>oFkwZKgmoG;U#*4=s%o4A=6?_wlMtd2In6*4}MQd zRq{QCg{Tr~*;$R?n*?n$s&68h6pS;g$VMr=8f#xrjNu`1^zp6~gj5X;m;UU0avN@Lo+SASeWM!{oAkU+YO|-VwcxRzrtQ z+J+J>)*UN*fDg3AG*7r*!QjDYmUcd2YKgqt9*-W%yCc`pU9=l1nraCZ(gV?X-Lw&s z1T62NT^TI>CYB0?k2Aa3Bg+@&Ox0c`=kce)EOw#Rp;n73*F}WGk(pX0#PN(v3=U-W zAK_8R)OlJu{bFJXyqlZl%POvFHSpm=?PS@A%Htl+faUzA)q-xlc7jY8xg;wHR&qYm zi5N`i`DgjF(tlL`;^O>Ng;0zGnLr14Oa{sT8WYPVz)U|?wq3uIhZoe!S zR^Bhm0;#=q6z8m@p%)hJnv+A}_rAJ%=K!!jE_Hr=xDt|84 z6-hL|C#rhhaO`PzZ`Ey;D)R&b9K41m3or7?tmUw*XqdNCr_>3dmxA$vZF_af zBO4)~z!-<)p?Zh?y3IsQ;ph#`4(M)@fyA06hMPXYCr24abS{)Q^0b&UM~pA5Jgu8S z*^Fm!(XyK1s*eZ2PhC`O?}#i1n0-s!9XHnX|}*6y~}oDTCm#7!tl2z9QSYuA|M)(fKh%f zO-xd7^s)u!G<9jDc)h;?A3BZB(!7~*;bypf*=01Pq@aP?sA1+!mn15$R+dn8+eLX2gr!f4&9vijyAX5F zMX4ZyrBHR~csw>;_rT>m6%Ta3g{^(;LdOHhEEq05c5#+y#kIHtf8x@Crr<#@9`-+V zIYYli(~ZB~n9l?Z4EEB+L_u2cp&^*%O~hxMLnff6PhPnkA^G{7?UnipX>d^;k%B8+ zbJow6=gIu03U`q+eAPze}yWGDX7% zX@f*UQ@x+PxSrB^GXUU6F;8Uz%Rxv57352cHN0POa0K*G|ldx1TTBk22wR!$Q#%8?_ zSx@K`yF-t!2~5GYdgT`Vpc3VuuYtVX zdVCBZ9;0K_MBv9)^>|}lKKI1r;8YjhY(b~(f1}s zSU+fz_w=j~SZ8M#NJbIl3Z~;}ayJJzg3AumP8rJ=Xaq#o5+dqu)U#s4PV3f zP6iukO~BOsSLq3E=p$Hpu0ahOx*2X#2wGJI#Qa@D5Uvmln2USizxx=xX|$ogfu5Y< zPCA%vnqj~j<3kJ@+=Ur*atvU*vXh3dcpv@G2LTT1Ma`oKwA`BpCstU958d`0L4iU? z8+uSl$LR^Mdxk+-tKS-~Wk=^>qLj`u{3_Q7k(HbnZ2ZbFo!DkvHH5LWB5ZMnEXDiv zG6_VKX6!?@8&{#g-B%d=DHhRHYpMGcGrujuezyNUgYue^sD6AVe0Riv&(}mwS%Iv_ z0+h&j-0-}n(gt@|M`(G{FooPGhI1f8pa!1*YB19k4=ZMMYNbJr1{C9wBK9iOWkNCP zGUlcskM50%m`AO>*-Va!c6aSxy~u>JmVT~k_{qmLm6+ohSuoq{gUm10an-XFhAl{* zpQ{pL3N>tK{9N(H3WiJ6pLJXtlE2VAk|fKi>$*j1f3>bxFgx)jZm7~jT=PhAT($(z z44QD)(KH+TuVD5n(X|dsUxdxbkvLanN#f@!+;cnXyDEJTw%x&?YwCKrW@d>{X_?~c z%=|_hP}z4}ZxL;g8^ZaBekQ#scEc5CT@AHcJCTr;&)oE|u7m4eWM~Xf`A`(rsaFpJ83Oh2_Z8R0HBHKaEcqM!&%jX_(+}>u{w$Rg?Jdgc2@f8)<`Eq( zYw;@V7{2|-RXO3smNbE71iE>_<)^N_ND9mn0v5h-ZAx|%O7M{^_ghShK)u^@QhLFLqAmA0>=4n1!N<|Lt1usW0pI+yUgvB zFce^e^BvVX5$%N!-2Gttw{FTy2pEb9P`SoUIWHDk;%@^iTJLt6YOcrz1nQw|r`rIT zYkHQ^)PR#70Nv{{vd)RAXbf6k$g*V~yLy z$oH9>Jq&1Nd_ekFTfFUVJg{Hg$*8<0Q|;~M{f$o0`vc?0q?Je?5eEXJ%QF5=)I<(( z3?Sx9DhilGjo5=d*w)q?uTWRK@5jpbVm96U)c95iRP4h8(L;ODlk@V8zlPTc-17aX zXlyx}dHq^rCpwA{CP0i4k`EYrlawMP1n}7*<9%u*@mwr{31I96<9jqx6nOzG|J@i* zJ+sWve~o%*e#5w$rYq6nx7zftk!C9cH7w~z6nNM({A!gH7&l6ogFm9;@4Pa$p&};I zt7M&r6a3`pp*(pNcH_VuS`Wp_SYVqMYd!2)#Q{v0lTc;=^Z7p(5BrIRwCf zkU)k&2gnHZpx5Swr7N91f|&jgT5VsHhgv?pWHNA&4$C`~`eo zwTBYW!u5jpvo;=ylwwxtVMvb0-xQXj(GfI!enQ8<0FMF+Xhl>5OdRB))GKAU0m6oQ zG$+DhIYAl*cDdL?3*SxlP#*t_19jBO#BzVerQpubDCWG+Jk%6&!uNb4;KWh_;=Wv% zNK#`%6TH3P=^Bq=B$g<@3Q0ATuJd?Bs)%(*h_T@)=BC{)59NhMMHMF&d(J}xmw&K& zPtk`k)AxGxr4pi0a{`<*xjF<}!}IeVoheGJcIJe2u;i9UYZ68@1%`7TQLMvp6sGw< z9xX@#D`6oFD?g6Wc=BJ5L6QYvlvDf0-lC2t5}uxTrB>saQHw<=AVzs3(K-imy*=r& zH(-oTp?neML%Bkrzr}MuJ>7guBsDvF5+$D0*s~64EtU;5c_3VB>Un^AGtm+!ox=9^ zN^4JgB+q0ce8kg-nNH(M>fY8<>3T#q6zoS0N|QZlcLrE9%gK_WPvLlmcr^<@ouy~j zdwBjTQdA^I1t(j@$v(~XRMt9C7ljmsJw1P?j6oYTkRvyb@tj0Th?-!f!4TsF6UKW^ zr?#T-FjgGFzx*to{P&vSnNAMbG0RiAjb1He;Yv?EOFxI1I%U3R1(j8i2SP_gFC=%1 zrcMwx{f4K$pRV$xhgeL+o`P|Me^z^HsXG$IhhvJ*<9d>^$@41ZhSiD;IjCT8x##c1 zMs6R_M0gX|^UYg(iX)zWu;(YMkI?81im!TVpz4U#J0d}H-||>ryD6Me;Oke_N zd)4y=1)VT>Ri>8_8b9`&Pt4Kajo6#tv6YPa9hbGhzpR8sJ6iI@Q%$cb3k!0Zd^leD zaPj(#oFhC5*w}g1l7Z1!S?grY8$Jc}1}9moazlhIwt3t21Cd`J4s`v&UY+ z^QH++yf%CJOh`H7eEW+d-&OP+aI zAnaeSOfrYiBKB66AKQEjwK(z2OIedpi$*NAzBk@ZxQzn7uk%)#f3e!MFzoiv z=;}a&w*$FONU2P8V^zhtnoco$FH;hQ@5#6r?9FXVAzVa0qgWO0<#eGzeeb`NQi^Le zAaETG5=$liRP?Pp~iWenbP6V+Bu^JKtN!^!Kp^Ycbio6IoRh1CD_+ zQ@uNrqc{){s63>QnLXdzjdgf{)#}j#?*~*IM8k?BwGg=2dpfyP<|hZrwEXP2%Qg7;XA*tMZ5s4_)f3d5_LCtC95J8E*ePP*A?*QpA zz-{hBVkbOrP~i^?jC65fCw0KEcO{>Ha~3&S>sKr`LeC*`c^s94l<{F|o>j z@X&95E1wK1mBOldgweA;|Kc&iyO};pkBLrc&gbY?AIbJ1n~PK}eTrKrpO1aAXxYau zTMTr8@-aT1#CG#92rS&>;|QklK4g6+E`cD&aJKpx=Hb-|K4v-r5UE}9fZA|kgK6MWp6>1UsNqHF_Z_!0^&)c6yb zJ)+OxhJ~INeDbL_h-~K0TByo)gZg)Uni5&j7UAeXD81)%p=NzAiT4dySdp!PiobmB z%h7;q4UkQQ|8Pt_w%is!)N|yi&quW96p|*X@JmbrGtu6+Gi^LYSFB*XSYDj3Jv4In zbs<@Ve+AmlF53wf8-10=3;DKXGwtwWH6MEUwje%2Cq5jmSbXaf3z2sM*dxwYd3?w{ z4=C$Gl3nb~a8M`|)%Wd6Ge!T1Kp$w?+V>Qd5>Xoj@Z%4ByONxuup-cbm1O(kO)@na z$tlxUStvyL;b=f~unZL86mC&IMa2p<_#GgZp1vcfaa2?h6jkidP~WR^VXkJC>cGFJ zmFN2b=}^sO+9$q=wYda1W;=swg74t}FqrI!jyX8P_mpIS51oRce5UVIDi7jF76tW! zPv`k6TSl=q$NuiCXQfW4*1jU&ZX|`Q864y7ob3X`i+$_U^%)^Kp92pz`PQYR7l~%j zWt-STXC(CTkG@I~7S_k%`10W)UnRQ~zIecR!j}?@$)@OcUwUO<1WlnXI{+qK@_i{i zB+iVv62&gaW%m`|w6}UmJe+4uZ~88i77&jz`EylP<&yoM7l_2u5kz=G#x38|WF%a5 zg866zbba7U*KP6pD!2pZB$&@*UzwoH;ZNUi$weFuH#20{fgykT_Myf|ytY(m=ci#W zpZL-mDlXx07)1Z$t31pTxAzd}%%WV;v1gw9wv!~l{MwhE`#_+LpVI#Dstq{)w9IQtzYuOg)|R;ck)gN=)yvd`r}NC@u56z9WMrogMHr>cL1`KJ*^vD$YbWHxv z`9GrivK6E7{j${V$>i0X?#a!i72cWQXN1k&ldqDH4{xW|V}-Ml9og~j$$B=uBF6}K zM(d@o>G$s6*(?Yc{urd3cqDXlUqyeC7)lCU;oEsow&(Dn9ncCevo@Cc^2s}dH#|d z1kFw-YY52oVyIUjjJuFbZy~bH1GsX(BpcYcQ#roid?k4X$$eFepT660Jvm0ofM1F; zvMVeFTd!Y|omlhJIbKljM)Gf@wfJ0Ik1tX@A@+9iJ_6#GB8}j9H#vv`CiX${A~I@V zf3(uSPm{f54QAp)drM!VElS){G=Ab!mH+#n!~gzQ`>mt8Y=vz~Sgm+wif&@MGyH6u za*G&Ykec!3s+2%Mv--YD&j6A#@~*xu|Y}@^*;jm>7^VG2yc^;Osm1>^(aW? zrJQ>|moB3oH#?;?lG6c!Gi%w?la*h=qG8)DWf@_( z<#`|oj6K}RP3bBbLA%~5%Hi$F)A;qfNBvSFMSucE6g?pYlx7t*Wj{|&Nq||yQ|?g` zV6L~4bijPZmA)HL6%zoT7oF6H}f`nE)yEp_Ur|Y{d55K)V#oN>R$c zsH2zx$_@7F8dOr8;>8MYVs^(CrL-q<`Nb*ih#gNYz|;yhiNNPT1onV>L@3W;$w%&f$hCmxj97*NM1%4xDH23j0LU;xZGm!f>Ta=9-C7N5?>J;(`z+{-CvqyqSMM9N*NMPiK*gL*$i zM#Ju<{6;iOTH>b~9S)|1uwxH%OtAVvN+9WfX_z0F8 z*xr#1sKTiK>izb+NH>gNfpK6xdbY1|H8ZIdehYGU_x4}g{>Rw^c{L2+!$1?WBjAUH?UgmR8kqKFdk>{1t;Zz>`DD;*Hq|TybH5kul?STI;u9)a zU~^<!!Z+0&<~ye9DN?vM z8G6%`S<$Tgd5#5~wW$F#rdrgu#yG%Om;c`wxMD~>N%du$G4-|-2%iC@R+4PiWm+;f zyu!5n#gw{@3cg57Y_o)HA#gf2wS*)R7Di#b;roQtVN{G`8l}=#Z5c*XJxcw8Cr2gl|y;4^^q2RsL4kTc8*dS2Dp1r|Z6xcrXWzD)F1mtMQ=$NW}DW_U9 zfeGrI`o>?nv(mAHku@2fT37y5mJLsqF+5e}@$tw$eR>bC{SR01_C(;>Ih!u-@W=4f znWU3dYKd-W+ocZdAD8+k*-7-083m~>tZG6kwXxNr3B(&){D*GaPE5T>RWzg^^(oE9 zN{wuBHsnl6?M?|G%8{5^-@c0*s6R`k2S)6rXPTK+s=K(b65B40uxVQAaGHaivy|Vh z*GEHZD_0#|+ybn_Z2V7}s!IUCj8u9y3)nO$%M*UP*$4%5Qg0G%YtVDnKCp6b>O6{v zMhjARktQM@1o>{7F5b|BrQ&UH-pfJySE<1?h*M@r*^f1I=wgJOOH%97iFmdBmpY*R zgLkG{8y9P9FBE^}(8UYd|B$M*NlN{a-erh3K+)dRt`t9L>lk*-v5N;ZJe0bV{Nu_$ zz+3qQ#fWk0qJ!9zsmiWdntphyn$2|T;tRHyQ(sV=D&4UstEx)XvnDsl*?R&{gYXYcANBWIhh zC)!(C2f_I0H032dq(n1cHA-`W&l{xCw^7)0kMt1M!O%qun#O7Vlw_jo=8Pbtd)f+; zW)Gx=G5l?SsE^Wy(HF18^z`m&YB*k!Hcom3QrD;5AdlgnVbFDJT6bx9Kq7+(Rn6qX zJ!yk$tyMaqCpPuyJ==3tjOWYvOJK+r2A=42=f*T1FV0PHa19BA*D2um>KTr^toX`gX|+mE2T;Y zm0sxwDO#(6M=a@kXyiw8(~VFPoKDX)Au>LF0!8Y^hUrZt&wCBi<)H#JZ~;dce_cChIlF-a&O>bPto#px#>&UWZNV zW%7oAk4?#B;L<_$>i_~9k{t@ZYFLNmjWwy+@t%0(^QgBe?>`uyUWh5|Yg$B@=n*aC z9O%&Blu5uzPG$?+)C)fqetm%HECrl0QUjI46p`87FM`B$SBUw<^b5%q7lOi~9KNi) zH-4GB%_x%-^{QLWHo$AVV@>C1WbQlfd9ljLkt#miz$$m*8RvvgP2ZZO{lZQ)5QGfu zM4xPYCw`g9nnxQr?uR)QU8ay;+`qC-mvsbTiFjrd< zKlRW*+ml_Kl30)FoyPJ=B{NaiNLgF=Z19W!`XRDc){;<&d1I#bZdOTtz)%HOOkmfT*jH_#kIBj33fE#1zB4#Kb1 zhnmfrn%uZ%?8^h$dUn&%9K=2kG7pkc3R#5S-ofV9GzIm3A<;Y{DFP$SI<|R1BNf{- z7@fK()J&glW|hrR9l_wZG6r12&0kT72uTq$hKN7jEF%nq8i&K!7;|IN;cW~v4Mn#- zjx{Tfp>pTfn5c!N@n$8ttPX_^iDr76pYdE}`F;&mklx5#pIA(5Yz~*2@z{cj#%4dl zlsX32Vfb4GhNfl;d_dKdW`;+)z%#__*~Vdb9Bg^VyoR)T8x61DHGe}G;TcYtPjrDZ zZOqE1qF{j8%ytgPkL(-M%u1_q{7bZ^81C~)b|jcG%*+470_W%%vcP}bp_6&afA}C8 zpM-sY@3u%)(VaxH=?Hv)@Nc%+hvsk$#CA3Rq!{5kx*LCMS;6U>uo1kSA^Me|M;nG&K@?1<<*FQfy1oF38vu+D( z>%~rNH&a;`xiTR?Tgy)5qe&BYm@}z~nY+hKdvB~u8N>pMJzgf9lx64x#27<12^->MU5eCSlOt`_rtW6YKJ;;X!~H<)uuq z?qdo5lC;Kx69gwbEy?sC5RHhRPKvW=nBNqP!>mwCQ;Ih9AYn#M!H0(z!YzeF1Kr`z zGWz12iYfTuXH$gbXTk`%keU|OMOm5=AsL+67Hr@`EowGrYPL5-##-jk988BGz&XlS z9hF5x3-=N%kLeuW3S>#CsP&T1FmgOwS-znyAJxmPRlB93K#QrCXGC4(mE5Mz+O~J^UP>zj|a?22#oh-vsoxXjzA8$a`P5 z=)7ziD)szhOMPWI773Ycac6eZ(Lp2oS|-<27YQkM!-NA|W@J0Fz0;9!lYtiH4IdG; zg<~!F+UN{iH6DFp*+tP)F$P`3=fLlyEenV+_q+hIiW#WY*0GiYgfXWl1i{kr79CB; z>K(*}%tUuzpJ*9Q3i61APp4aslGg-xG=&2Uon=v8(HYho4S8gaP|b?D z7W&{7!#oVahY=QM7BCy5=ZpE4dQ_G~1R^G$S~jJ<(y}A7@gKNpyUbFLL=bZN&OtfX zl~^_qP{=u9rG-B1#;kI(y>oE+dh@O24;m?!h}_etfnlBHOHxyKSO6=^EL&)#70AB- z0*lq29o8fe+)O(y_iBg)@jqB9=(mWh@Vyorx@#h&;pCZ1AxhJ)!g7m7ii|g1M$Cj$ zmLEl36LH8vF!Z$LDLF^9SV+MWmi}hBOm-Fy7bDkQuqdw?V`T^e1n#ftR?~bmm)|vu zazrZ>$hdDgKw>BYIzsbDmRJIEw=x`rCAkPgXU$`aave&sj3Z3>%hImK+FSh6f^SIu zYk7|(6Lgav21*T0LCU_s8k2C`9CRu|E~R`X{FD~-kb+K3y3{#nBH2#p zSvfMuiH%_x$X{j!c~DUn1{0VQ3`@ejodhVp`B5h&@||Pg(u*KEH5R5vm&~M%ImCtC@d#ckqu3f@taL5vwbwKF8O^Bn7h)XPvu|*@`qL-) zYieOcAxI7}u=G`^Rh>`kI>E&T!NFmYtb&D@9>INs-iEQ4d`9H@P-nP2IrwD2+gSXN zN$^(s?u9~yt@{@Hr{nvBKS`)Hc-TL|$K|&nnKBrLde$}8Ca`%m5-4v_H`H8_o)faGwys0hBh}@bLdMkAwQWVn3)#wA zjm7*o;Nbk%As@cY(*P=S==56h!tSKdowXhOZU4}VB!LhsZzE>HzL}vBwSagNc713I z30#fIMaNSzD@|ceFzZ6-<=UYKg_lC-(4nd55%tbtYDjq!nn|@lG;acU+$L-pt#1lY z17E4b(h11JgT*2v7FLRdp{{dS4_Z5v;c7Oy6c^tgUBcQ^TWXyHjXcAeDyt{&RU^0H zO1IuOj6Q$BP@xcLVhS5VO{G;WR&OgB_)1vVeOV@Dza!*84Bp*{2%{!J6qo$1*uMlt zg|)7(LLuxoPGVWZuqz}1Ctlnx%)nyGux9OQ7FJiTb%H`nYM3J!+J(`VN%`Sf5EH;5 zDPhXBUG6DB;29FiS_L2?JuIB;BD#v$?Rc;<>3v0fz~$rVFd5&XLKYqjqq8pTU&CSk zp)gyji-K`sdN_WzZ3nhe=T3wjBD0DmNMIK4KoeX(7q*`;ytEf*hhwf^3G2~DumQen zraQHQ#kgkSg|%2XLDM$j(PVnzwDK!qSk2SJ+mRisfx7JQzQhf!5Y9|Hv)$RY-0-7P zDb9k!R4jidu3!5;3cns)oz8fTBFu%I+lhVd)z8DjlorD=I0$0rhl6B>-;fS(LpBsf zKoow+za*SKgDhQ=u?xG6(lz0;>5`a`uT`b;sUC6uVxUUE;=@3HwN+_*TdJ5O+=QJ zbKuc?;kRkHFiQEoaC=r~4`Tj)5U%VEmB7)l*w^7I=vEcJo_2g9tGJV){_Ak%!!z9C zu-vAe@(EVClwA)l+m)X!wh-N8Z=h zYkOQeOmyO$4qig2x00GVjHYmieNZn(Ruz#lA`}DmW2=T|pZM>k+DA;Lno}LAh&Hkw zbs|b6ZR~l&8NzVG=O3|BIvY^CZd68vPzCl89t;mj9pqOgC%+q^d<|3>wD3pF_0bTom^d>r{Rm3(Vo0(nCt z>0&M5P9wDX*eteqY@{=s9ToYH3}8Tasg*XJC%EA!Y@=rUjIr#U9~nia78XRB8u(;V zWXBqn5%A%`5&A8%Z^98QTQ{dhDh;d%lc=L;;aM{x=@S}E0s6w;S&>JT>HLUDj65(W zQrR71SQGH~xsi4xjfjS{U+`EWV18uACTTReAn{JQ@WUt-i*6mIffY$nACb|7a2x}O z@u*f9|1nt(9GVg}pX89S#(`0(Q6~r}s_*w^*e$7H|0hthXW#ROoO5v*v=EUJWT&MYA?+Z zN^%Sg?H9FNF&sUL(6YW2Xy^y zxJJyGJtB$@mE^*VY+cyllNgJ=M@1>;FN&y+%=cGJ*}h|N$t_oZ`t*))1(ka|$8>;qBB#74pRfXAVzOZ96M4o(PsUq&6E=&SZbi9@sow06-{EoFXG zp2baMl{$I`5f)|>!ZbUFQ2`Fow7tZ)v@o)kIz_vY>BWh_S(oUq6rb`lkVd~@Vy<_M zPEn2>dAiN{4S6&Oj6PUT$caV>W-ZU7sxc|i%BfVfm@Uqusvc?41A9rWxcy=EmT2XC zhi~)Qz4KW4Pj8P_UgQwD;Rn$>6|FhnxfhVH$DU}BjPgvtoEaa&s{CVAp!SO?S2B@{l=oqbJv{c0`6EJd<0HX7 zCFTwd;^gp|PKJP0^g2|Nu=VTjI;-bi80!cY7qrDX!T9ZJZeCyN7`(NnM86` z14}o@D1~13bX{VcSf5JtnQ?neRm~HE+&(dQuW^4&Fabp?7O_9Zk%bP#bKQ3PV+^qB zc+694?;OI$T*dzX{Dm0hD?{94_?5vJCO1MDIialHHS~zBbL=VEw{h4GbL>m`cH)l2 zSULfyKJI`P4PrwFRJ(X?Nvx4x0v54#q%8J!%@{7Yfq5N!1FPlz9kHb{+M#4uY%el8 z{u#~2ZV$p&_;q2r-gAHq}zaig1PkX042200yt41p`BV^`MLHNo1eu@mXHh>Z>p zW5a`_V}#zzUE|6qoJCfaqov_f@3^@%sTx?nZk(D#5Dy&|-Oe__AWqo>iNY#I54np~(xW(Tw^D?#pJ#jT;xka+ zFXLJ(1)V=^6gHT?G)`%)gy9;lh+9V+c%`e-vb>S;_$F0(+%h>GFe^GzgyWx)5PvLA zOXjIHY2cZ-C$zt*g_(0D?kv3pTMJY8XIyuBAXE$EXBV%Web>SysN=^88A;W{(I6UF z_+I?_{{*YR49SS!Ed32A!ct{tbuca*?tL8Jj<}=g!XdYJd>aZ499j=f4~#ccoe)K> zstQ-EdynzBDtc(VAC0WWwD=P-lSjrkBaN*XxIZ?2y5eolXhnX!`+w9Hj=ef5{vcgi z5(Ya}93MyIsx_|o3k}p{as16%!l@v2dA#z^jEO~|0^+qS|8HDVl2*m{Cl`w?glSd0 z8~hIOD+nlx7#|L$N8(Eeh$4itIZrU;r(KHQBQ@YD&kFy+@;>r@CjjuFIXNrt3y&JECBie+?G8-YoCqa1|p}PJ& z{1@xbnmP%G6E%m#Uw;ixZ<;|5O~}&AyTd$fWH&TW$5f+n9w;PiF_br`t(`0 zH^YX(0qipqCP`^g*I?L~m2j4XM|%Xb$miL3BVuKcGaSrGP;UJS4NA6PdoEuZse5`Z;gzyC*2sfK!7bxd~6mh=PV`VS+Q8_yVJEPZw5{}kz22|xGtfJY%5BS@W-FlgAV0b$31XqS9>>#uV6oF29 zg)7k65efasgcpBqUWcJTelYg4g!2@@)xbHk5xCU^o(NwhHGiO;1$5;E!gk#^Apck&&o;TmktD zj1%kDF>$U{rD~WX3+$A*fEe(tNX48)BV6m0Sf!X*0kZq*9B0sGCMxe{D75t~Nt1*B zN=7t5EQcLS)gN%Gs6up{=@4I_~OpB+{8Gt zskp7fsmU?r4rub8A1A&~%-%xdrJUZ0vj`)vrYRHQ=e~(`iLGKVLDEUy0gM`$n5*+tP> zJyR2vPudH10y9CEqX)~3#499-5?XqQot3COp5^HW7!EyYkcfJm?#Q~%OdWu*`F}p~d7pdkJ?GqW&pr3t zb#AB_db81N!bnL_MJ`H&%2Fq+A~u^H_?rl8iQA+`B>cHVVK4^>!i)OQQT9M%ni|KMROdW8Nv4&%s2crLgV$#uVT!w zjDpKgFfqT4onxxJnZJ1hCc>?a6jBW`$4@vCl*yoKGd0Y-fIDa=ni~?AWx-siN13mq zO$`D)*vNIeNSi`cWSJbC-dw)eybG74RDwdsSz#WH2}4OkB(ug`i0(&7ZLN7I&QDd` zVY4{{9m_Y5$BCp0BS>8J57PJB&C{?5xReBmhYBFfs=ekbhEFq5+))sI!demR=&S~F z?xB=nodP}u(eFlc?qle%7l8{tPy|hX)oiYgy=|`O-~`_|xK23vqIoiw{4gYognYhY z&V4VAI(b5oFuY;TUH@vlXV2W?Yr#h>yJwDtNwxqa$r5kxoAVJ(_ssDL)zbMar7eCI zGGzK|TB}F}qOuk;VGvSyXl{p9mfXDM0u)gBBU01{$Xgt+4hv_n$)5zwsz%U>P=c=H z@XY*;A`OL%Cd5glP?@7?7O#2fG*ZNX6;5IES?Dt8G*Z*ZGy>9u(V(hDgE-C{pz{a7 zOI%b2p}#P)5XHo)-Q@#T7Scq43P7wUS}-w$+?gS`5Cyc`%wiCeCu@rU0=i07fHce$ zI})}QaL$uT!$J}!s#aUTCB=K@{3ylVLd2PZA~@oxBuM{+b$mFtN|oVO0VU^KG|AFw z;1^Y>+h{SFZ!C#*PU_eGf{i8GD_NFqBm7C#1%y?|Rn0xi*C#mmz) zM*?8;!-fSb`4ls-x<{Azq7M={XwQ0zQIQ6QLe=2JT2JTYCZQx}RtVkZ1h+EiwI^2; zNYaZ1lXD6^{8T5l8A3Ozn$F^O1UMx>BIkgIZUjX>pI#Iri+bgrxk zNLNIk5?EfCbF!OK3<6+0Do9~L*m;sB96)Bl6+((U^dyLn7SB>7t{4Lk6^mJ`FyxOC zljKmuG8XJ&P(?`BgNs%M<*i^rtQrb1lAa7vm;qILj@2|IZF^{;c|tbEZnN0I2~C9Ng~Mt#_zqAEC@jKFBHA5VnIMk5`Y}4 zS(~t6M`92`ytQ2Qquc~8Ga|%87U*?!9ZM3U?iy|FN4&8F4mn#f-O)WuT?sB6`;5u5usznk93u-9@B^rAX3Neph^}3xD4TEX)THN znpwfMCyE+0xgVi2IaHKb?->gFfPPljX_ja{0b&Vv!K^0O(R?aZSRDwbe?r^B%}q)p zpt93O)-FZVT9&5tM$UR6rUYu_M|k>#8l&eEt$$(rM79F5wzRIoh9Wk^dKPl`vSx_U znBiLs>ssLqYb*ToO0=~MZhXk#N4)iim>LoB))M^xTLqlS9MTj=MD3K&vFKBZb(R!O zVP%GOu_dlXqqVOe^^<@`^@AfA){1mBUWwXF#E{E7Y-SS%Q$tnIo^Ttug+U1b5_Qz+ zl7P>T@C$~CdG9e!XC1tv79?z#sLZZDp4W}9jN?M?^xs#6K z@qR4Bb_t;rLKZ5Y^mQ>^2ogiQ=t2~uGebii(63nA7YZ~S`r>4)=9JXM!{Dq!Z5VX2 zhAi7;EJP4J4<-UvA>cY&neE7ERFrm*BQOHMcRW;6a|8I6C&0~wdp}jSBG}%LMw~<; zk9ewWr_+3pD@8P3LTpCpIAT|m?Jb(?rOmcx^e<{|T-su*L<}_BZlTjkC)hz`oi1Bx z)ZAh#j_u%ZqGYQr+)1GL`;$n#jtCV*w&!hO+mLDzSSQkyq{B@BH8rHs zWjmnq2Z=RlD*2HATiaNynAE+Irg%GLqEOP34}Je&%XMF<%UfIsFM9LYb|&@$fE#O+ zFKBlcQyb2y6bIx8r9lD+{@gM~3PNSmTBbo#P5)hP# zs>?8kb+cet88Wtm7&?DJBx3-=F}Hh$AyoZI?5Nz@t{1ZjPP{eT7_k;69>&0Uaox@i z&fimrz!#t(La5!*?k(<;kR6Val5hm@r`Yo%xj}$=$w*2dX>sCWEI2ePlkM6tQfl#n zf=rkLi+OA2+g0J#gllpZG~zi6>~wJ=RZUViiQENtLWEr$DAL`9cE4y2Db0NoZ7)!? z*bZADau_Bc36A8(f$8*EY_~L;&P@7P6a>A!V|SG{-}L<{Dmx^KqHizlKI8sMX)g&u z%0KOlaetyFmsDapkG%suSW>4hDa1vIp}fSt1Q7ZcWBZS|&4wK9VdaGqD7BzM5u2JA z3a>;u+kc?}!!uxjN)r1M!GAjKVm}8PeQL=KAkrwr&;AwWk5VEkF)hj-PT5lwNTv}a zKE);f@Ov!9ehVH`|D+YA*u%RyY4#2{^RVbnB!TGM*4V>F+h2?u9kUlgd0F-|a6|tQ zDgh8FLO0ibA6B`&}9|7}Q9KcpGgmN`VpYLHl1=#GvCe1d+6G ztNw?KC?PZtMy%yc_Iqe#e~OUEL{WINeHb2fV0N!Z=b_f@1n%1hVKPyV?R9AgC69;S z?1hM&`QWNtcx=BDkNu=ONB{)p+b`|mz&S1AKZz?|+rwpKI+0vsOL=QgU>Q?Odr(pu zS%0;MeF!QO*^CGh-RQB0yz@(;7e;s*L9 zabOX+*Y6D+c(6?90a_%Fe9Ihej-ZL0_c~-@eWQ4K zy59l&&g4M?2D)~{0pgBPVwZgEz(g02!#1oeF(jvD?Z-mHZ3cf1|p zPW5o6d;X5?BkOS~(2;*+J>Ji9d^Umz@p}~@88g?B2UCJ@3i5<%k|S1AxG^tJ_#`>v z`A!P_!qj?Ao!}UGt0UaPNOF`y=jJ)8;&%HFM1**h0UE5l*wGK$OmK9Y4}_1Zyo%h^}{(CB$`ylpIUgJk{F4~*#Sub({YAa-W=HsVC+dhotU0SqlqC7kmA$|;Y^rJdmV^SDaMC%)=r|o8$&%_dQ2SSUPVn$3m6PI=O6)Uox`Y$CR)vq~G<6cE zG9oY&u-#3Sp|n0{6Rdh}w{+Tsr}d;ZB6laJgIKL$l$9soTb8id4EvyVY$tsT;bMoA z%xDA%pB#ceZy(vyQG#G|1Wg=(`_-vK|PGxui;wlm^@ioM$kIqQ; zJ@hryX%Kfi>YFFp3GN0`bg1v(7$Wp_Prg0YKJ1L|5c}{7#QY2k8KHX_4 zE>79k#^p}?>C&(QDo@C7h3f5C;S@;=>R7(hDS9kLP36yklYMdJJH)#$Km;*d` zqL;^=l*iFXDN*!o15wyrcgnz4j}pM7?I3`UH=NA5A_nq^eak5Xb4#`hI`POU4p$!J z$CO+!B0>*YWvC*=On&aIb9wY8iVV$9U{F(c=r_!~Sai25_zS?q7? z28zibR?K#WSFuU}WskMhBCMB~cAYc|ed|gfNV97DlSU&QGyar~yL- z60veq0~%12Kmjq%+%;9outVZYELtvgX;c*FT#9LM6Ge#!r7%b)ra0&0=7i2cF-t*Y zk<}7sZcik=CZb`L^H`#AHgM#n{^=6VZccmjNsin48EGT6z*!(laAXmbbjt-US&`pVnbsbc z8roV?pX>WvBCziVTrR^5LEn%kzE5I{5wB`Mu6y{|Vi+Z?#>f*6!fbsaq81!W9znJS zE<-{PK=3vm0b4NgMCnC$UgGy8wkY8z%w`aVbucSY7i9H z{^${zD24O`*%`Qts^+oBqdTGOYWz*PdcF&R{Ju!`Oga&box>L3_5l(zh(?kCxB&8u zV`t;a443?wz?PtCBFTAdP0SVVk-vqMonxReb~gH!B59mf-%_0Z>+aoAgMCTJ8* z!fz*=7ujaAA7XZ(Bs^e47a~1Vl3jvz2sCx(PWC4(C(~IHhyOMjAMy4y8{Q*n zV!xpP$C}w4c&0%rIeKw}{c?n$(coQnJFY%8QcCi=@}k?1*frSL|4Ag;kHS2@et`WE z7w0m8THmoVa78E*(O=ly#fsvcZj7TUu3JWQhb=0u{KV^HP}jcEuH0=^k_rOSvE%95 zkmZPU1ewb8TxExKm4UhqTx*A=!a$|QuD|d%msLJ=+SGN)S{f6GjzK^sVKnok>r(8c zP~Gxtn=5xqjQaMy;L5?XiD68GcU+ToX-t$gTE^>ELw{0Lb>wq1#?(ocQK5j_X0zcc zAm>SLg;h#9^}A6KozSb+!w2OUENVW#n$hy1}t$N;AoE8kNj?g}EgF}nYEYHq z#!t6DI+*VkhZ_o*RYo=iZu9A)2)=J)wank)hNtles!U+3Oo@5mG`LlB4!OB9hiieZ zbhsH~v65mY;9H2uJp%`V413)WHlCy|9sAmLS1sf-bd6#hrtzNXiAN7`RWx zU5wjMyu{un(9UvW_fWby5Xg5cZaB)8Dww)U5#G&!?)r51g}5$&?w20LD`|>}!5Vkr zzkM3YCw|-EE)F&TFj%*MbvT>nJ`2zIsX6h>8h3f(K%To0QBvYAK*a5I|3(XdYk{f4 zim0;09b)NGZ3By7^2C43A;D7jTnwhh{r$V$zu~?{4Y=?vPbi%OQ}Vjn{V|;rU9WLJ ziZzg$Jp)d4qVybC`SyM84S2{bLR?Usc*oo4Fr$LBf6(XMrv1-Foe6C|Ri$Z*d88(hc$n`;V#(WWf z6~xZ-fg^0fxQqbIRiD#u{8WgQ1wIfaxX>pW_iu<# ziW6MAlA*uM;R}RS@+BWHtOvs^oayv|TgMb%5RH{4iEM88jHUTPpeHXd z4XP1=C4SJUTFhTVGfe+U;<<@$t)>iWcb17H#VGPvml_Ghgkvv=-~WZOmM_r#CH&j@=ra8PVF#$!b{wD z4_(1Oxk-RDGL-NQ!+5w=gZp68zVMKmq%WMhr-bsS3<3x~Y(PL{X52VkB%p<-Tp$eEhdG+Pu|wC+-XoQJ*e|Ld$&_ zm>8&|7SUw@D!;GFm#gwWYq`StPemct-ces66jkSY7#ot|uB2)d#z$N>1QiWD>iZKT zrz8)o!ZYg)zH-FI6TV%P%+c%y-^*B?xIz|0;f=m*ExJu8O(F}TE4{vO-HFl)Zp9(8 z#8cn9SQ?~dB&8upNSlB;RDa>ioq|&qih{(MK;Uop0pAsv1 z{DQD1bEPDVb}jbfu1bSa4ANyjmO_6zxWbQD3?49{U(um(QLP5)d_=GX=)Trczd5*m z5Xm2&$6Mhyh*g9Nod0==pCpmX0)yYZ){lGiiR}MKa=jl9*VoazfjDA-(%<@D?0o{{>wB{Iq3IiHcQf4Z$$>b zKjc?I_jd#eW{K_hjvIdTA_xMra}vvnvV3oE_>DzP5B%~lZ$QkH<^`k%dr>wJ5&h6( zzf%|yrOA+}fNEa&Nz#c3hLpqD4#7`-wEMH)+2PSf4{iGC2XWA;3Q|^&L`vw|!Z23P z>wg;~f#&4y()=WmUT1LaXriE*m_ z+!g|NMuqro7bY$`vhmR=ZU17f$$#Z8LrgydhA_g(UzE6L4|cLr*FON)hSDwyV&o7u zmasJPZ>Os@+`G6?5oBxZ|9sde*q~Vx{YyuFJDd5R9r?|+@Q1q|q?8b-BR)K6K!|(SH{f;g!NFr_aExu z_oxuYFQ&ljw!Z$f+8_}>|5=y?P*=?&HgtnM0scu??I{^S5k6!a;Xenf8mNsXx-!RK zaHJq5UBSExC;6|$Y*QRTqA+pM6`Hs+#XlPJN)LH%VPb@y8$gyW^yeO$COJSm7W;G0 zpHtrtmiU*@(=!BwA*K(ddX&csjKS)mJ79XW(Z7+FcIhU6Vax(G-jaFHjV=D&8gxNQ zmsWa!*?MroKNVLU3TdPCQ~qo5!6hmah27W_-XyTN@6TNUrR)@ibNyrgtiPH_3fcAf zb6p_ndAKjn{Nb&p;m$(ggp$HYd%$1Em4;A4emfbobG^xw9f@=z#Zo}Ylol*x>f63z zO7|oh4zkc9RDGb^dGt=fr(h7g>H&d*C~{m?lOUSB0dryhl;v1I{{w+W@PQ`xe=&u7 zx}0(;flo=4HZa8|X_yZ-mIvgFkSqdU1|pA9eF+TsCtN|A z&x`;`WSt#QV)#cYn#WMU5?mY<=m!m;)DddMS2P9OiGvLRiF6hOE}$lt1F#ne>;?CL zFt@GAGU7<9B_Kz0mDJE?mj)~XP`T| zf!%ljp_Ih(P)Kgxo?42J z)q)eILNwi;Du?zDO}&p@Co0oft!XKEaG<^u*wgIr5-CMVY&KAOv1D2;E<|C1dds5A z`=+&HyD^;Dd2QM?oJi}oa}fW39YTWCxFWG2I3fFa+Ba-JNX?+ql=y-UsXWkfG1hx0vO0i zIY<^OF=;Tk03npE62$e#Nz^17LDa1p1W|V=(kj|P@D2+_ipw+cG9Cr2CkApmOKG@bX^T1oXU;!3$?(QJ&l#ufAxnOuovnr?tPuaMTvB(Pr zaZhznrUSu0Z?FH*s%BSSn8Qeq;WTg+=%Ffh~% zBa}k251HB6uAGn@K}s4ue9m;m?KzAnWPo`CD+bIUhY|4+u}zD+2ywuwniYiUm?o>#qD~k5A9RVG zHW1z_%JL6y)KhbXsSF5$fLlxTa*TxAhU18&aRA|&#?ZxkUhoE`4B=C+B0*4u!xI?{+{ef= z2->}hMvSZ%F-kDH2py&&k(|SjMoLQ=#dwS&B|yAoLX+`iG9Y#^Sz`pVDDKJ_)k8=k z#3L05ubrR-;d}UU8B&<FKEgA5e-=wVy`L#hWz!6^E4FRzk_F}W0`O- zT^WR1QovC8ci+Z~7(Imn8wX_hq|LyFm+RFjw3S zMz#iBF-oRgB@9s#B1|MCGDMNX7Y00s#O?RG#2+w9|IRpoA=I0NU@>sBPXEPd$B#8ZYyFNGdSwOop3$apkOkhygv1CU)2nTarqa3b~I z=3Ogp8IlZ=6lZ?JJ&aNwNR&ptl1x$Bb3>4L5KCuR*pk{1Pl~P2lpeOmRCW1?huYB0 zdrX*P=xHh1Z_k9-@RUpdlP-1B1|bB=OLIjJuS@Cf<>SX#=wy%X~PK z-&UqD8oh(bUG}6nfZ}lDq=d?T(-ORcfwkFVr z*fq?_SXh6WksvvOEWAXC3D|%e`2 zIvRNRxEi^7c(DW70fB}t0gk3~qJFit?Y;Tz>ZhH=hMjSa((h9Q5L<-bc#WuHy-Y699=5#VI zwP;^{`Z&His+9L}iqPbK`HE+KRaHf^o>j^ZRQC7p>95f4-&65YtG|DoFhg*4;5?Dk zEfw0aPy70x?g<*_IW9YccUvak>VQpBxsxYKzn5u|zW#nnuISTqOT@%PMf3ASz4N@p zM9Z3{OIs3l>*qw>8-32&xYLx!>YZ19K1Y-@kim$VoN1OZn11DI`unF}Sr7vwMW6aJwTcb74g@cZh4lcJ}0mMCpcJ$1Fgv0L+ZKxoUSSKCHUCNA&# zy}B~g;YH!^!7aCb&$ZY7dDi;J*LvA@m#-l!Se%o~0tbyZ#bu{#zU@+;T)FF3-1r%{ zmj32=%h|^EF-<0ThZ~7??f3V?%Mf>9#iusbjKDgyNA?Moch;2 z`z}#l(h#~3SRpXzh1ulQmiq7 zD2V9Vw=sNTc+aC}Pi2=d3Oo((r6+$oyl&6s(PfU?9C!M7`|O%nv1sSPo>NA(iwA19 z<$U9lw|EfN!5MoY_U4EF=d~J(XY1Dprqz8T+_7jufkdvCk~h@JU7lU_WAH|-jSo{E~I~tKQMmxT8pptzZS3Y zIA>ZE?YlxhcVOVG&shEIhVI_cq0{1SAHQ2VPr$fVVb*o6O2@+-MbG_fw5+G`%h?tV zcq>gYY7}kQC42T=RL$ZyskizT&sCY2qj_KGZR*k{{SEc!Kl;xPKkdA}XrvX@`BbQk16Lx** z8UK6rm-{6?oyNSi%eJQbKD7IM?~TnvE7VVLPJfegu$k?Y9c?zsJiA_U(uF|vtRdAS zlKnXo)|jYG`y@~(rnctl1TQD~3^iuenuVoO+VfjDhj=dJrd@yByGm7Dc-IR_Wf{Fl zrqtQUp)ZAL^MXYMc+xD_XwN$LHrw*0f28fS%=1HQ6iQ?g+|Iq-oHn#TvXgfxQL>Zo z?Xpou?$uZJR#nYf8)&*m@!L+@yISriH3P?s+Q#ZOm{-htUvoz7%jd!J*fAWBw=XVL zOi(K>_N&_RiBne=dncf1?~83=S{JIUtG367ddFMk?iR6IGP(U&uI$n;-vk=IYkrZw z_$v_cCfB4pIJLTZ->SPJRb(D9&fNN3xKQ-w*clscEI4XpZ&kKEFplDJIyY8r5oCGTV1u=KYNe+!R0$PUcYu~-H8ZuA#F~f|314N-r=bWOzdXF zEV$u1HScMnT=fKz#E%O`yPptAwcP)7kvZ;xAR$#*>~Nq4(pX;L_%HFj_?+= zy{rx^t{cx%k8IUSJJxr;?NtRotLm`N31h<;!OFbGZPOOdar%BoD)X+3s3Oa8!@*+; z2gdK1YU;VDcH2eYnueRpjraM4=r0$_57XFGb6at&xw3~|LsIaDvF2s{hdCi*pU+mj zRqovKZQrLUvqC?(=BTu@mGXmKU2Z!+Lw*Tr1`f^ z6TPU=G(++JZM7#BA9&wx%pF~Oj@$K8{v$yQk zof@lhAl_&CoxY^-qx#)rh{X~Sp^c4x!S9#9bew!|lY(7|Re0TP?6mcP|S4&QrCLipN{}o(#Z;8mhlf8Z7GuesaQ+~t-?#hU@ ze6=&<&B@>&`akx(%0~0+);|1|@-;G+tl!`lK4I#)6e^ESEiyjybZJ=t@d)ntb~Ozy7mC zIrF|9YvrzR6m1^%6fdwipkKPzu=Ipe%f;)}1`0{%#yyk2ojWRQfzY6CPUE%wMiFGQ z;Y_cgzo?DKiBIXi$GuofSS<4uD=q4~%nG!Wi`~A+MKm_Eaw|=%7j_R+XTCW%_P~N4 zEy-FTy4e$*6ygG-L?>@hTRCst?)nmK!5DkKi^hEoV)dIi#$}teJ#?1^w_SS0-sK&$ zNAHG@u+ExL&o`q_f9yJawsL;S1G|nfNs$I&I(6R^zbqf`@+`Ki_x_FN^M8yA5;{3= z)r^RQdwcD^sSFiff1_1=$FKG3Q(dd7CEMqy%;Ydz;+fA*uD$Ri^5sv#OdGESzPB5r z7KL1@D|melWi5Y@purjML);oQ#lon0c30&4^0V4g+p?70oZ5fO@0R`T{oG3V!z7_o z=USF4)~0L@PtBYAdmP`=o#tQo1D54=&7STQHr;8!Q?PQnlkVqhkJesP`=GgeP4U&> zAJU_>lY+v2q_25cFSh!%?5ogcS5;TZyX;O3ysykwl01+o>P5xUi@2K zHO_43Tp96{NSAtn#Y11FYL1_%|1$HToq*rk>w%8*Ug}RPV)gZF?UP<$vvgOw$gdYV z6+(&+BDaRrSzp|3vP9hb?Bh7`pif7;U1!&SGqc>^<809Fc{y4nzgBa%Z}I?7#OK$U z_MyJfJA*A(^agDY5;?q3?v_k?V+QBo%IjWjilMPR{i#19erp}w)<5-^Y;#HU*cIMa zPWQ(4PI4W}sJ*XUl+fbCzuV?Wk+JvU_xm4>FBVHP8q_$dI=B`NAawZf_%Tj@5>@Yg zW_sM3X`8Wd&#TQc$vYS8UQJK@@%e;xRJr$W5puw8l`yIN%0Ft9wirEN%Wy^s3JQ)Q zUG|X!>xBPrV0Dd*UXVP02|d2%2i*0M_Lm92ez$9)!`}J2*>WzW@`^^PIzcD+)MYh< z_eyAA?+xbPV|rzQ=Ua^*;t^?GF4t9azG>#D#BlDVzL4>ZPTOjm`Y9xR-@;FJ@B80; zRvG1@?<(1-6k!|6Gjb*^|QCAEvne;J@NKU zuK_WE$bxMf8zTEsY`N67DXyCX|$ThS3UQa`uYO8Bn?OUTm zo1!Q6O3t06w|3QUABQH<*?gBHXEd#DHD0!5)ds)&pQrs=c~N`qgQb10V;bU!7d}VB zkEbrUUVTOE{o>nkzlbRuUZbgkcK3N#uvbqDx#i_?^-^bWd3&hh{mjDVb>Gy^s{Wkg z-(~z_mATzI$8S|a0k5iVO8xjW!)z)aVV!9dl=+*%6QR@ZEYZ5iX_T~}s&nF|=apL? z-B4X`w^X7`g*E+j!J1=l174UO*{QxYH?!sur|PtNp`Bx{#2Lws*&SW!oOSMo;p~L& z2bYQ+-bSPRPvbTqT$BO7^z@Ko?7>)e6PB@7E3jq{+m6;b{{z^lx=KzW8MOxJr^Gzx|nDYJouwwD0)HT2cx&g zI&>~y$oo{YbEshcvW~%qp2EuuCR(M>??^9snEK#z%-4R-L;K%6g=ZJZc<8&nohD-& z%xqG4uzu!V6;}E4R-5_rtX7Bli_Y}_l@`?TZhml1sp_uU`Ns`DcRzi#o;i4_cLwhp zc8dM#vegwy(=sdX-YHQ#R$J8dDfj51**aS%D9>>V?dZDfIXL6iRxQ5etc3xHkX>`l z)JC`^^Ui5MNu!rloZw{TL7{}O692*!@mF(-2Im~ljXYVyl9{gCUFW$!a#G{G!dl^S z!#dX_cEa<%Yw>Dl4&0m@xk09eHJ9(!wb4Og$0~PhsqB!A)B3Q@vgqD=?SWXG1|ip)L62u=rPdzRcrdr_E+^#9O9O_};j}et zzCYf2>r7#ZP}*%N3qH5wVbwPaSjuwoRR+pE>(kOJ1{NGt(+D%k`EWu~D8FdT*dg)! z=hODZZE4+Zm^*Q);m2DsN7l{r(s8#vpbx-T-G_x<-P9Z=h_$DV7FRZ1Ws@JK5K=Wi~UoEd!^48=%9vy)!Wh0H&@$YkWeFx;@Grvy1FzM_g z#ifg-m+#5`Vf)>tW&Cr_>Qx_KndTKouFQMhFukKhwdl&_oen<_@)eh{M_y=p&LFk)Dv%q zH*|5Fw7(wU(+QZf%iZz&)I}FoWq3DCRJLeqXs^}%F+JA)_(3I!qQtcyrHh_>&B~Zy zVdb6o`28r27p75mPo_3LGf{r~ZDM@m&fS-iE)_>rYeJ_1zg&mgx(Ei{d{7<^Af^zX)Dh=-y%%&YCAk=J)z{4^6k&8!xdxG{wGN zdWCr4#DSoR?dxZxOt9+ve1)<8@s8h=F)?c}diV=w%kqMM8NBwlp_Z>f`8eG#l`S_ZQ zr{YGV6Km(rO{ncw+}Rfs<6UiqGr3M zwnves+aaf@4RssqHaztZ*0jiRKIHRGEr*d6#oI7vvDWSEChf$lAIi0lyY}wWKJN3L z5&6YZbk~|*?Tj}6_G6xV6mOjW_Dpe2+s>Fxj*~APy0R_b>CS@wyamcZcc%EXUFc-& zXTQG`RedB%R+00eg2^Iuo*j0s&5<=dlhn|@1k|=wZMeW#WM~qmKA@>od)n`^ z|KV^){n_U-P&P& z^J8JA>FLIq$3J~~C)bg-L+IARd#^3Dy@wLD&fiteaIUxOnOkt#nvv92d?fqH*^_Zf zrQ3BroUPX>UK!>O5x+b*c3LN#=Mzt7$W-an_yz8+cJj|G6K3zxt(g*7S?%e+rECH_ zK<1`SjelTywX1)AnW@Z8-I{>FJ=H$`N`ofPWqi$#ZMd@ii|`kH;m^H}3U&o8@+l_5 z5iQP*43i%Nxh;IhFFcxK(5aU(ct6h6wRyUa)rsO4ORe_ZwR$j-vq_)x&MoYl&L_|A zzLny)HtQb9_lRF!lJVvD-AUpLYj5*}v~Q~%YVl6YdU;~^AZxc}N3PAOHJ&E<4_0ov_gSLh% z8zbkRpS0B*7mZ4gY78QXsjqJazhIX~Dl{j)++Md}XX`7;8E1!nMaKx{%oV7A&YR5m ze642g*_+2A75e7JeUK||%bJx^6?JgULb0^Dt{ED;Cz@r;jo&SF{bJOG$#tP-oFIek zwQ^V9TAXz$X?qV%v&2eUyhxat6+?*-Zk(!~a ztM9F@AD!M*b|ErO4q4@x_a|hrhgNB+AKTfcZazwXosqt8j-07r?rEc78I|C&vYT3y zt|X2ke~V}Hzn^nZa#T^AuD$>}m?QUjC40-+YwAhwCv@xI6wQ4(W^(Oqi+uLBQ3tC} zADmDEQP0Okdx3H%2a8ygl`?#hJG4$?;k2&#U^D)W1f-AHqikFNg@9A!%^hEqKLkdHn_n zeWP{L>>tOi5FV8~IHrAaS##%{x06Q&zvYyyYvxiz8nrHpM$PKX}Z+&kxP zt&ZjE-Sdn*6{F6GnEh;c(x2-4vHv|stHk`f3hAizw!iB7$~$V5Dy$=ttC9bEX?Y792#&_5JWn72GGGirWn!l{(byUxG zTI2ARvwW3^sN(GBmuFULdtbX_;k~2c%`|CgbCXSL=bCw}HL-XW9(LWxdu~wBt(Ts6 zZc5Az`o8z_5Wa`UnoauS!;M-;Zo$GlhL*eEYj75MCVQRC16ap-MK z+y_1JWwH^QmY+^?JM-g*m<@l-Pj8#7Sw9VIvSOCsSbwmtpl6<6cflQ#2?OU}9S`e1 z|9Z}*k55d8czrHBo+amV@!LiHNm{nWMXlElWnX%%7&0m0d@7IW05W4GJ$%?b$>gx`xdTN%7ltJ)_S|X9vu($+(GeA{O^;_>Rhzj_nCtvhS3s3v@jNQN99XxYj{=sDq?MJNbo z5v}*L&L>b-v|^m_-g2?FwC+9gj@+#XH@WcJ^%qNI*44CqX8Oi9`F1v6-6aQ=Ur6h0 zjY@p)96pyHY zMyTrJfS*DEo4>StY#!@#GBT{Gr#9~Fud8=@BMrLl)?@{qy;-$)zv!_SW%g1-U)xdb zSw@WTy3&=lb#bGGXKDKksujxLnEKH{Yne!(@4!TF=JhW}zL-DT=%?5?IJ4`(-c=r) zXW`d(Jk+{ry2!N9>VEmyD|L6Ct+_M1=A&q}+Tr+xLgq*Gq-tzUqSby zO(!>*E|i$CiC^Z%Be}B5s?61|Z#OU8_#j8AQ_qr)y@Euck_#Ut-wTl>P9)BiZQ(pQH=VXl3vH zw4Fz6xiJ5ufE4-LYAZ`u7pPUJt{%&$a$b#ZS5qY4gof8?;mwS+fab8Y9WyIig&#D3 z-gYe}Cg$2bj#kJI2RZxAtuY~udIz7DqgNh|p1c`5EQ35bvmES=wkk|RC7O$N-LnY& zR&_V_cB*Syg-xQuwt=KXuak_~HEoGRm5J$8jT3z_?A1?JrrwJ)kZ%~+U%qRvQHy)j zr0L-yKSL`z4rDDkex+oVuly9X@oY_JNsCWOuCs$K30B#1MsMUjtUcFrQsmOrtFm8; ztU+;RFT7&&eDu$1?CsyXH`-uH*{rN1yB|3k7HuqO@{X5jSR5X!kU3~3ZPS}@ec>64 z>7NsR9*L;m9<)z%#+*7G2dx^_gGKv9?_K`XAoTiUVsca4th?*^ZkzR{o6rB+A-1}2 z-?x}edw3Fd#EL#He!!_Lim5V8JU_e0vuw;uzs{w0$4Z<1_E!cvU3nKA!FDBD@5-(1 zOI)|1G-*~+nMRTZ;{)0^=jr0O{TGdIIi@`aaO^$vZX1wPv^pS8GO zu`J9o$ObW041 zu_unQdJI0Ni1zF>99Z>I=UCN>57u*K>J0t@9z{`PwaYl{^$3|=@pf?s(;E!WT6vAXU?9vo+eKWi4@JB5&wLy?9XFe8~JjF zm`VLRyxZ)of>dUXzhi0IlU5MY?fEz}O?q*uvu{d?iL0mRwbjLatDSsS_T}y2`0*Q_ zY0z2RDRjFoRzG%Qd3b5(V8Pzs$`AKE59Qn0Q zZd#EXo4oB{htpk;XVJU88+N`l3uAqotbOnM*8B+X3kzbeZMdHDw6MQyL*A3K4J~HH zFD~vfh<#Jc%Ca)CEN~opyD%wMCi(%(nDa*GXL`i>Np|yOT;{E7`I?ntx64w_Wk@nJ zGwWcXFO%)hEbEF93}5y*Sb;5(nJe0>4q4smGg?}+QcQMP7P-`yv{YuL=)zBSeO}8B z(O&Omk9Bg?-HsK#*Udk>e6DoQ+9mp&cHOT^vmbxF4@0#vE5p z-;|#WjSq`I{T49d|Lvmi`|*q4$&*(8el+%n{P`jKNtqHu>iaKE<}=I@{o!(3+iO79 zc46t6*QOS$^lo>`bj-ZBB*(bwBkPrc^t@f;7o+JLD<8ZM-mogV+Ti25_iux{UYrV! z4oO%T8ouY??I#OE^(?CeD&1*{B&^3v;*v! zV@!FY_+PcGnq(p^vWAD)nkls*fBuGy9c;t++xz7YU)6tB%C@|!_AK&%PM2Gd$DJts z>qNG!;b6Dzx3Z1(N-9HkA6`!OIGtax^_E`rx$`}DFEw0JsQ(;ww6bmL0^!_AGj45H zxMUs9-o(k8-P^UoHbzxzYx63Z`Ks&`L3x40lJ8s9WpbnRW78{xS9{h6uKm=tyJg|S zq|#|x{*)f!o6<@m+e=JCyO@}RVQROtgjyME)}ojl)iJC%YXDGe|bYr^-Y(3YA+33 zPHm|^3cuo&{K+hPO5fc{=0Ez1-#=O7<+L&jsiQg7ceC$!-Eb`%RE^ISx{)G0fm6KI z(V!smW`60QW<10HZq8Bxf1B((9yb=1EgHL!5W10}Tm3^QhJWEy(b{C*g+~6L$1b$@ zmyn#Q6%^0%|15o!sNODgf&79Ki zGhi%fo8){w>#boy`*-j5)$Z9!*?d97)IiO3w@>aB+J8;KYV_y`J}I7at0f+lOKv*S zGc^7FHK?8xpG<}+{ot-)sXoLN!Zngy4H8Rs<^ ztZ3c2a_#AWf}^58!?RjSL}MB|3l9YP3VjPQ7qWhO$?t~YU9sK1X&UYqFFk42y*2UT zNw$U^G4|}b+9PjVntOcOt>l|CyEX)rZ}1NKdb&$sl9buS5A5laGdJtq+*R=*p?Sx7 z^(oC$C7xGbm73wDI`Hu5ctcLq-j)mJg!>jQ+-o~eN7}aU@{N5JtMXUew(vZdm=|^V zTur`tovHrMn(dL6daFDi9ueR8tV(BZaf2#{XUX0A*ulg1c3*SkOXj?Y-FkVE_0t)3 zAHf`H2w=liAu(Qb9OWIN9 z{KEy`*#-|+3zkju^E8;ds!ZJ_V_9X@6b;!7?d@|ziuS!W+;-pT!{aOEETb8XX%m%Q zBoy+M8|Qd6ro4OHno-i2KJoO&`x_ljs;b=bBbcb}L`b%XL*Ve7(o2LLcyruSv?TsaKV2-`L;TeW!o@ zF4Kvtnx;Q{xpTqnMT@?TTQzvZweR?h={|Cg^`^{|^?rQ3q(7`K1=B@Z*bXPk8kaUKav>KxB`rX=y*Z(CO;{r2KUlkr8yDaQA9 z8D=L$HR{yNU-qDM-GnFFV(UsOqh@TM=6zr4?knxl1(EzhM=}@ZUXEI`(Qt>&UCU2B z?(yo|raS&0Uta-L)$%<|w{&+aos!bsC0rV5>2B}}(k*pqq#Hp2Q9>G&?(Ptj6jTs| z?_9vAy!ZS5XRQNw?Vg!Ed-}{rvi{D-ijjoJFEZr48uauKWGUXxoHdSkR*&AnL75X+ zct!M6gG-{+J5C&2u7VcWyQpmmDyer|yz55i-Oe|s?fFYfvx*h;a_O~&>LDtVucFap znai6X9>NwHO%LIwSRN}Ll~UO^4)ku3cS(kbDnaMWW>HaHH@>r2M`jFGG2{4;e(-CUE}j$u;DPO=mC775FdK0=@?QE zjdOHO_(KVh0)!K=r1gl1NoTL`fTR&yQY zhkS3kjRkBbyd$ksF5~p9Cn~Vol}GkrjM@l|g5w;MpRu>gfjpyuzg}RfEn0tfEb{!Q zgAoz;=)GEa_c;3znbR#ww_)IKw)0B{i`=NMBO(i66a?zoTE!f8n8{N*7ztQ=0sZS0&E6*W!<=dh z*Wdj;c|HL8*9)QmbH~m>d7}DL!@!41^XNZ8eEk zzS4K8Va{D^s(w;c`jQ|sUf=-!L?c|!S|M+`B=QxH@X=xh*8aYj7#Q~8pd=EPvcY>R zZ#z$>q)96mthj`yxcdvQUGc6^ap ziQwSz&DJ-&l)=SG&9~~C#k(mtHzRPlYJ*`l`fMJ?<<)%Ou(l+8_qMhkgw!0#%^W;g zr^Hw>g!~yxcJ$M?oqijIil)WlSebmpFe-Sk%o7rJgR1u8jAp!5D)lE9@W)vc$owZ2 z7HuB$>tHtzG;xAA)3{5Q&rK}6)+1sNX$QjX8XO{=W`shemQqsZNZkC=>y+0f8c4>r zkv{9J!CxxLbb0YaZ1M^wQnQ#gA^Bm>so3k)@TbWJPA^J|`EafFQ?MM4I&zC?xtWp; z+LH-4_!%AEy<}>M^3$t1BYCn9?72cl+3?>h8U_P#`{-tO*Z-bR;rO5PDOw(8Ztgbj z9`2Uc!Tk1uv8IFFm^!h@8Q{?|U8m1~gxR zr5$liFBN4-m`~u(HCEjcXUDZABpvtM1cpBN7(Y2b|4H#Q#F2pI@%D5@-cub!p?Vz` zf+^;PSO*Gz_xW*`sNBu4Di(_zD)gQxv(QkUjs1q?&TJ>9POE$SzJWyhT=;XFG|#>Z zWTJ$=TSLstA&(38ACwcNQMpU*b{Vgv2JYffkBVyw&;1fST1R_1&|K<4fBr^Nc9N4s zriSQljk6}+nLl~h*We3X7nw{`4B_4W=R@#Qq}`+FhI5AMecnk0h!2BZYox7pGtf7a z`Q|oVD<@1-duyhDB>flw3pACFVh{`TIEzBO=^4Z{gpkT~CtT)QG559}lW~ria)K`# z5qU$K!rLA*cdvWVseye%jm}t2*N2vNg&=nDzPQt&Q@o4hROsf>KTOFq*y{p9Q z-g+AxlU9=4Ev^u;skwpg->_W5>*X$JX>^JR^&p=|$A!y)13CPk4n+Px9Z1{V#vbSa zfPwvc4w^1pW2}t@rw0E-iuKst-GZL$Y`sSL!3+Jhi5IT#&u)>}1HB z-3@`y!t%IBD!{F7CNJs{01`0|CyE;+2IF!B#Xiz?YH0DkPgx&ge^@UkUxXttFT6H7 zaYmA=9^lnky?|mdMCr5expfbn1K-u+y;c>-TsN5(qoB-ficIPAJpwZLi|2EcKm0tk z6sGnk*r_X9Fhp(k()sYHVtw^}a-Rh|r)wKx{C{zw|^$AKA z1Ri2Y=6=!C>kI+_3Ss%Pm#!AOk@^eW5#PY0vC>i&KRzC(l|{OLC#RzGmGrO7&L;O?%L#e?P40FoIp=xqzg9DO6Ilbo zh3sUJs+P}3^VT1}>Cb#9i)5-6-e6$ns_;akkg^v=76~<&@1c(@5^ONTg@Rt`2L}6S zjA#sH4C>b2_TJY1RyZ@RYB&YP#P?Xp;E%9NJduEjwZMD3dkg^ndH$7%>$SjJQPm-) z4YN%gJM^;DmI;>@SB=_mr)xl)9(Q#(V@|(ZUnRpHa$t)|*(w#`@Lbjm^GK~F?ewze z2<(a6I_x^)JVHMXUkWm$D5S**?F-KljPk+dG%4pqEy}kngG=c;Q|Mgu(h8#EFfHPd z++XSm9iCSh=vuLx=c0KX)Vl!jdE%=nIoP3#`!0$<+bvhigW^+B@Dq|>jdyGNroZte zND3nag*4e`s0TVANfM~$?#bB+@ioAwsCN_|JU|l2yoKt_lV*OE#>6wqvojK_}J3b#{J=AS4&f10BLRtjV(ZE$)kO=?X|omcexA7 z>M*5zhxX?%`q)-x_B%ADQo@?P;A+~QitKqd;Qtgu8vBT29;)95fw$XvGE1UwhTkxm zO+`-Sz5k#mMUp~jbn{n9Q`@8OH4*4X` zx)6p3rGv}J3%LtgAph6cmE$9B%|@ut<9Hr5367BdT70nyMjyu=sHggv{Y!Rh!}xNJ z#=EE-y?2FF%B3m`^8xcRQVK~nyLSaK^JO}ixUzSrUglE;uoRD~w{;h>h+rhOSS*T_ zE@MUrUYMrmse(Bl9Apa-Z4BYn)Q6(FM;}MKOu|`Z>UG8BLRDJYPSnMuY{7oG-$tYv zm|=8mnq&&>9{LK?R;nA0RlJa=)95^&Wf_sYk&&K@-y(sIi zVv*QciA!adz;?%DdKbP8o6(n^KDh2-tFp?zL_cW#E^(o)li~aGyT^dHX#q<{x9c4Q zIE;JCiGYw{W@>Jy@~>?@Sr3=g=(LGN#;B6&;n~FM(HqQUOwmIsmuai1Kfa2hM$~Cr zup|OwSk_};j0t6}nvI{>@`{qED3714KjTQfN1w1IS`%^T#GNgyRb06Hxtq7S`6ysX zWJz#IWDG2J@$(x$Ooum1@KGx2vMmZ_KLSpNJMZ;mt$ZY6}NiVzaq1A2h~)jr`Odxlzr3@f@rv- z{@Tt=Qz1C^gLrAq8XKz(h~~L#N_He!J)W#ZaLNPcl(fvur!dnbOk#MvZFp0fZuhZh zP`*51xya0R^)3Ff-kiRKq?*TjclO3o3r|SZz@R;okJ9~_-V6?XTz1A$;g2l|qXcvr z`gO_!y{eP42zdKdzSOgm^l7t1%w(=VCleAN!<*yyY$|F4EFlg^A)HbHL#jQ4++w|# z9Z&MW-{;5IsxugUw|@SLPJdIIDe-HuLeVC`qu|?AKGn2m`t$tKy^Ze*8-~rV$%Dl5 z%Oja`(hEO4}L z<@u_Y>@}6?KNvHhC?8XK#7}_WNm6%TgF*5!CfJghnf5-jRQcPyG>uQZE+I9f#YVW_ zxU*Xk(|5T{;7PK!@?!cjiQJ6_n14p6vF(+HZW!}1jinq$n-L4Lw3K$oTFae2qAblxr3X)zUyG~i9Nbg!O7kZTLsELZ5xqf!8>NF$PX=4{1~njT*~=#J z4z6DY{-UWt7o)&(Ya>D;ds~BuES8$*v^n_row>WK0zaho4&N&2p3#MGFk)Z97`Y+O zcAY@(B=?8ZfPB3m+v7z{8n5jYkqpEBK&I#DV=-n{nqB>Q-}~vGWEb<3gJWlhoHxzh zI0?H~E`4NK#z{W`KXbXSny(4yL6rAd^EQqc%5suob3SiP_!UEZa4@W z$0F_imX`KDEp1h}i~b@`jZwPk&JG5dV24{>_gV109NbSlwQEO_Ra|fE8j9>1#wSJs zLK+oX>|^(+F1tM2Evq)R+Njy4Y1xvUYLR0M-#>cB;gex9LTi%P&Cfgerr>~r$^R1N zOT?S=OWl12gZ4f!JTxwr*LpjAK!Cx6aRu7oe+91#k0!U4nwZlR8Aa;e@KsBFB}9GP85MHhu+0ob z&E^EHrEJxX^xd-J_m^P@wV_VS8O$w(E0iB*BAv>;WxHOJey1gBcXRbOmcnYmYe#oI z%nOA$Yj@p$dul|$VRr(iY-A>7e?LB(R1Bh7ZP{9b zo^9%f7pjdpuI*!GT5@?oM?Q^eE2>PTRCJ#x&QNPBu%;>>%Y0&y2%RCS z&1{i1Y07C*s>X{4xi8#g`$=W`Sf~mx)C>>tj|;fpcFGjTS7+|jK2KA#V9i(OcwrhFekg=T z4x-;ApQ^?SX-X4du$BUG)9$Cms>D0T5D`nggE$*$2U7IC9keXvCh;6#o$U@%Fh{ce z#ZR@6x&KA0=!dy?%WK&q*bjM+{0QE?@5)zspg7vXoWNqmU;u6(Qh7uCXit}{ubo`bld4rB<|n1AcL?5V9@-)9Mmx;>G?hZrdsywK;-6?>K&0 z-ts_tc)oqT1ic%6ByMedxF(u_zBa`((oq&8WAq~H8woKaed~l=bxQ#4>*D*g z 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�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 QA~Y*M>(|E+WyD|q0pOP5cK`qY delta 163865 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

n}_f>6EWC?SHbxzirbYUn8xCFh)z&zJ~C$dD{zm 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

  • ^A^bh`soFTN->Ho1a=Ko-(Ax}$AHV_P>o+BhX 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 vn@&e9%CbwovoLDNe%s Date: Wed, 16 Nov 2016 13:41:27 +0100 Subject: [PATCH 028/124] Bug#25088048 ADDITIONAL ISSUES IN MYSQLD_SAFE Don't read --ledir option from config file. Ignore current working for finding location of mysqld Remove use of chown/chmod in scripts. Be helpful only when basedir is /var/log or /var/lib. Removed unused systemd files for SLES. Set explicit basedir in scripts. --- packaging/rpm-oel/mysql-systemd-start | 4 +- packaging/rpm-oel/mysql.init | 24 +++++----- packaging/rpm-oel/mysqld.service | 2 +- packaging/rpm-sles/CMakeLists.txt | 3 +- packaging/rpm-sles/mysql-systemd-start | 66 -------------------------- packaging/rpm-sles/mysql.conf | 1 - packaging/rpm-sles/mysql.init | 13 ++--- packaging/rpm-sles/mysqld.service | 48 ------------------- scripts/mysqld_safe.sh | 18 ++++++- 9 files changed, 41 insertions(+), 138 deletions(-) delete mode 100644 packaging/rpm-sles/mysql-systemd-start delete mode 100644 packaging/rpm-sles/mysql.conf delete mode 100644 packaging/rpm-sles/mysqld.service diff --git a/packaging/rpm-oel/mysql-systemd-start b/packaging/rpm-oel/mysql-systemd-start index 231a76087ac..af6e906efe1 100644 --- a/packaging/rpm-oel/mysql-systemd-start +++ b/packaging/rpm-oel/mysql-systemd-start @@ -22,7 +22,9 @@ install_db () { datadir=$(get_option mysqld datadir "/var/lib/mysql") # Restore log, dir, perms and SELinux contexts - [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 + fi log=/var/log/mysqld.log [ -e $log ] || touch $log chmod 0640 $log diff --git a/packaging/rpm-oel/mysql.init b/packaging/rpm-oel/mysql.init index 75ae672801b..50d1bba017d 100644 --- a/packaging/rpm-oel/mysql.init +++ b/packaging/rpm-oel/mysql.init @@ -70,18 +70,19 @@ start(){ ret=0 else # prepare for start - touch "$errlogfile" - chown mysql:mysql "$errlogfile" - chmod 0640 "$errlogfile" + if [ ! -e "$errlogfile" -a ! -h "$errlogfile" -a "x$(dirname "$errlogfile")" = "x/var/log" ]; then + install /dev/null -m0640 -omysql -gmysql "$errlogfile" + fi [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile" if [ ! -d "$datadir/mysql" ] ; then # First, make sure $datadir is there with correct permissions - if [ ! -e "$datadir" -a ! -h "$datadir" ] - then - mkdir -p "$datadir" || exit 1 + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + install -d -m0755 -omysql -gmysql "$datadir" || exit 1 + fi + if [ ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + chown mysql:mysql "$datadir" + chmod 0755 "$datadir" fi - chown mysql:mysql "$datadir" - chmod 0755 "$datadir" if [ -x /sbin/restorecon ]; then /sbin/restorecon "$datadir" for dir in /var/lib/mysql-files ; do @@ -94,13 +95,14 @@ start(){ # Now create the database action $"Initializing MySQL database: " /usr/bin/mysql_install_db --rpm --datadir="$datadir" --user=mysql ret=$? - chown -R mysql:mysql "$datadir" if [ $ret -ne 0 ] ; then return $ret fi fi - chown mysql:mysql "$datadir" - chmod 0755 "$datadir" + if [ ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + chown mysql:mysql "$datadir" + chmod 0755 "$datadir" + fi # Pass all the options determined above, to ensure consistent behavior. # In many cases mysqld_safe would arrive at the same conclusions anyway # but we need to be sure. (An exception is that we don't force the diff --git a/packaging/rpm-oel/mysqld.service b/packaging/rpm-oel/mysqld.service index 78ef3bffe60..871f191c017 100644 --- a/packaging/rpm-oel/mysqld.service +++ b/packaging/rpm-oel/mysqld.service @@ -34,7 +34,7 @@ PermissionsStartOnly=true ExecStartPre=/usr/bin/mysql-systemd-start pre # Start main service -ExecStart=/usr/bin/mysqld_safe +ExecStart=/usr/bin/mysqld_safe --basedir=/usr # Don't signal startup success before a ping works ExecStartPost=/usr/bin/mysql-systemd-start post diff --git a/packaging/rpm-sles/CMakeLists.txt b/packaging/rpm-sles/CMakeLists.txt index b5ffaa15565..98aa4f4d222 100644 --- a/packaging/rpm-sles/CMakeLists.txt +++ b/packaging/rpm-sles/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -20,7 +20,6 @@ IF(UNIX) # Left in current directory, to be taken during build CONFIGURE_FILE(mysql.spec.in ${CMAKE_CURRENT_BINARY_DIR}/${SPECFILENAME} @ONLY) FOREACH(fedfile my.cnf my_config.h mysql.init - mysqld.service mysql-systemd-start mysql.conf filter-requires.sh filter-provides.sh) CONFIGURE_FILE(${fedfile} ${CMAKE_CURRENT_BINARY_DIR}/${fedfile} COPYONLY) ENDFOREACH() diff --git a/packaging/rpm-sles/mysql-systemd-start b/packaging/rpm-sles/mysql-systemd-start deleted file mode 100644 index 28472249eda..00000000000 --- a/packaging/rpm-sles/mysql-systemd-start +++ /dev/null @@ -1,66 +0,0 @@ -#! /bin/bash -# -# Scripts to run by MySQL systemd service -# -# Needed argument: pre | post -# -# pre mode : try to run mysql_install_db and fix perms and SELinux contexts -# post mode : ping server until answer is received -# - -install_db () { - # Note: something different than datadir=/var/lib/mysql requires SELinux policy changes (in enforcing mode) - datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p' | tail -n 1) - - # Restore log, dir, perms and SELinux contexts - [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 - log=/var/log/mysqld.log - [ -e $log ] || touch $log - chmod 0640 $log - chown mysql:mysql $log || exit 1 - if [ -x /usr/sbin/restorecon ]; then - /usr/sbin/restorecon "$datadir" - /usr/sbin/restorecon $log - fi - - # If special mysql dir is in place, skip db install - [ -d "$datadir/mysql" ] && exit 0 - - # Create initial db - /usr/bin/mysql_install_db --rpm --datadir="$datadir" --user=mysql - - # Create a file to trigger execution of mysql_secure_installation - # after server has started - touch "$datadir"/.phase_two_required - - exit 0 -} - -pinger () { - # Wait for ping to answer to signal startup completed, - # might take a while in case of e.g. crash recovery - # MySQL systemd service will timeout script if no answer - ret=1 - while /bin/true ; do - sleep 1 - mysqladmin ping >/dev/null 2>&1 && ret=0 && break - done - - # If server has been started successfully and file created in - # install_db step is present we run mysql_secure_installation - if [ $ret -eq 0 -a -e "$datadir"/.phase_two_required -a -x /usr/bin/mysql_secure_installation ] ; then - /usr/bin/mysql_secure_installation --use-default --defaults-file=/etc/my.cnf - rm -f "$datadir"/.phase_two_required - fi - - exit 0 -} - -# main -case $1 in - "pre") install_db ;; - "post") pinger ;; -esac - -exit 0 - diff --git a/packaging/rpm-sles/mysql.conf b/packaging/rpm-sles/mysql.conf deleted file mode 100644 index 74cd5f836e7..00000000000 --- a/packaging/rpm-sles/mysql.conf +++ /dev/null @@ -1 +0,0 @@ -d /var/run/mysqld 0755 mysql mysql - diff --git a/packaging/rpm-sles/mysql.init b/packaging/rpm-sles/mysql.init index dda0bebba56..25762d9bee2 100644 --- a/packaging/rpm-sles/mysql.init +++ b/packaging/rpm-sles/mysql.init @@ -49,7 +49,6 @@ get_option () { datadir=$(get_option mysqld datadir "/var/lib/mysql") socket=$(get_option mysqld socket "$datadir/mysql.sock") pidfile=$(get_option mysqld_safe pid-file "/var/run/mysql/mysqld.pid") -logfile=$(get_option mysqld_safe log-error "/var/log/mysql/mysqld.log") install_db () { # Note: something different than datadir=/var/lib/mysql requires @@ -58,14 +57,16 @@ install_db () { logfile=$(get_option mysqld_safe log-error "/var/log/mysql/mysqld.log") # Restore log, dir, perms and SELinux contexts - [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || return 1 + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + install -d -m 0755 -omysql -gmysql "$datadir" || return 1 + fi - [ -e $logfile ] || touch $logfile || return 1 - chmod 0640 $logfile - chown mysql:mysql $logfile || return 1 + if [ ! -e "$logfile" -a ! -h "$logfile" -a "x$(dirname "$logfile")" = "x/var/log/mysql" ]; then + install /dev/null -omysql -gmysql "$logfile" || return 1 + fi if [ -x /usr/sbin/restorecon ]; then /usr/sbin/restorecon "$datadir" - /usr/sbin/restorecon $logfile + /usr/sbin/restorecon "$logfile" fi # If special mysql dir is in place, skip db install diff --git a/packaging/rpm-sles/mysqld.service b/packaging/rpm-sles/mysqld.service deleted file mode 100644 index 78ef3bffe60..00000000000 --- a/packaging/rpm-sles/mysqld.service +++ /dev/null @@ -1,48 +0,0 @@ -# -# Simple MySQL systemd service file -# -# systemd supports lots of fancy features, look here (and linked docs) for a full list: -# http://www.freedesktop.org/software/systemd/man/systemd.exec.html -# -# Note: this file ( /usr/lib/systemd/system/mysql.service ) -# will be overwritten on package upgrade, please copy the file to -# -# /etc/systemd/system/mysql.service -# -# to make needed changes. -# -# systemd-delta can be used to check differences between the two mysql.service files. -# - -[Unit] -Description=MySQL Community Server -After=network.target -After=syslog.target - -[Install] -WantedBy=multi-user.target -Alias=mysql.service - -[Service] -User=mysql -Group=mysql - -# Execute pre and post scripts as root -PermissionsStartOnly=true - -# Needed to create system tables etc. -ExecStartPre=/usr/bin/mysql-systemd-start pre - -# Start main service -ExecStart=/usr/bin/mysqld_safe - -# Don't signal startup success before a ping works -ExecStartPost=/usr/bin/mysql-systemd-start post - -# Give up if ping don't get an answer -TimeoutSec=600 - -Restart=always -PrivateTmp=false - - diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 4b103817ab6..a5c87a44e65 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -218,7 +218,13 @@ parse_arguments() { # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; - --ledir=*) ledir="$val" ;; + --ledir=*) + if [ -z "$pick_args" ]; then + log_error "--ledir option can only be used as command line option, found in config file" + exit 1 + fi + ledir="$val" + ;; --malloc-lib=*) set_malloc_lib "$val" ;; --mysqld=*) if [ -z "$pick_args" ]; then @@ -394,7 +400,15 @@ else relpkgdata='@pkgdatadir@' fi -MY_PWD=`pwd` +case "$0" in + /*) + MY_PWD='@prefix@' + ;; + *) + MY_PWD=`dirname $0` + MY_PWD=`dirname $MY_PWD` + ;; +esac # Check for the directories we would expect from a binary release install if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" then From 42732cc195fd237c9b17490e96f1bb29db433b0b Mon Sep 17 00:00:00 2001 From: Dyre Tjeldvoll Date: Thu, 24 Nov 2016 09:57:54 +0100 Subject: [PATCH 029/124] Bug#25092566: CREATE TABLE WITH DATA DIRECTORY CLAUSE DOES NOT REQUIRE SPECIAL PRIVILEGES Require FILE privilege when creating tables using external data directory or index directory. --- mysql-test/r/partition_symlink.result | 2 ++ mysql-test/t/partition_symlink.test | 2 ++ sql/partition_info.cc | 26 +++++++++++++++++++++++++- sql/partition_info.h | 13 ++++++++++++- sql/sql_parse.cc | 19 ++++++++++++++++++- 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/partition_symlink.result b/mysql-test/r/partition_symlink.result index f26a1642a52..91cc78f1361 100644 --- a/mysql-test/r/partition_symlink.result +++ b/mysql-test/r/partition_symlink.result @@ -4,6 +4,8 @@ DROP DATABASE IF EXISTS mysqltest2; # test.t1 have partitions in mysqltest2-directory! # user root: CREATE USER mysqltest_1@localhost; +# Need FILE permission to use external datadir or indexdir. +GRANT FILE ON *.* TO mysqltest_1@localhost; CREATE DATABASE mysqltest2; USE mysqltest2; CREATE TABLE t1 (a INT) ENGINE = MyISAM; diff --git a/mysql-test/t/partition_symlink.test b/mysql-test/t/partition_symlink.test index 5fdde8e0abc..9e57d616213 100644 --- a/mysql-test/t/partition_symlink.test +++ b/mysql-test/t/partition_symlink.test @@ -32,6 +32,8 @@ DROP DATABASE IF EXISTS mysqltest2; -- echo # test.t1 have partitions in mysqltest2-directory! -- echo # user root: CREATE USER mysqltest_1@localhost; +-- echo # Need FILE permission to use external datadir or indexdir. + GRANT FILE ON *.* TO mysqltest_1@localhost; CREATE DATABASE mysqltest2; USE mysqltest2; CREATE TABLE t1 (a INT) ENGINE = MyISAM; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index a0d09557b81..cd17e3366cf 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -2550,6 +2550,30 @@ void partition_info::print_debug(const char *str, uint *value) DBUG_PRINT("info", ("parser: %s", str)); DBUG_VOID_RETURN; } + +bool has_external_data_or_index_dir(partition_info &pi) +{ + List_iterator part_it(pi.partitions); + for (partition_element *part= part_it++; part; part= part_it++) + { + if (part->data_file_name != NULL || part->index_file_name != NULL) + { + return true; + } + List_iterator subpart_it(part->subpartitions); + for (const partition_element *subpart= subpart_it++; + subpart; + subpart= subpart_it++) + { + if (subpart->data_file_name != NULL || subpart->index_file_name != NULL) + { + return true; + } + } + } + return false; +} + #else /* WITH_PARTITION_STORAGE_ENGINE */ /* For builds without partitioning we need to define these functions diff --git a/sql/partition_info.h b/sql/partition_info.h index 7bfbf8a1b1a..7ff6abeebd2 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -1,7 +1,7 @@ #ifndef PARTITION_INFO_INCLUDED #define PARTITION_INFO_INCLUDED -/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -349,4 +349,15 @@ void init_all_partitions_iterator(partition_info *part_info, part_iter->get_next= get_next_partition_id_range; } +/** + Predicate which returns true if any partition or subpartition uses + an external data directory or external index directory. + + @param pi partitioning information + @retval true if any partition or subpartition has an external + data directory or external index directory. + @retval false otherwise + */ +bool has_external_data_or_index_dir(partition_info &pi); + #endif /* PARTITION_INFO_INCLUDED */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ac3901997f3..18cb758c9b5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -35,6 +35,9 @@ #include "sql_insert.h" // mysql_insert #include "sql_update.h" // mysql_update, mysql_multi_update #include "sql_partition.h" // struct partition_info +#ifdef WITH_PARTITION_STORAGE_ENGINE +#include "partition_info.h" // has_external_data_or_index_dir +#endif /* WITH_PARTITION_STORAGE_ENGINE */ #include "sql_db.h" // mysql_change_db, mysql_create_db, // mysql_rm_db, mysql_upgrade_db, // mysql_alter_db, @@ -2413,7 +2416,6 @@ case SQLCOM_PREPARE: copy. */ Alter_info alter_info(lex->alter_info, thd->mem_root); - if (thd->is_fatal_error) { /* If out of memory when creating a copy of alter_info. */ @@ -2421,6 +2423,15 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + if (((lex->create_info.used_fields & HA_CREATE_USED_DATADIR) != 0 || + (lex->create_info.used_fields & HA_CREATE_USED_INDEXDIR) != 0) && + check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE)) + { + res= 1; + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "FILE"); + goto end_with_restore_list; + } + if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; @@ -2458,6 +2469,12 @@ case SQLCOM_PREPARE: #ifdef WITH_PARTITION_STORAGE_ENGINE { partition_info *part_info= thd->lex->part_info; + if (part_info != NULL && has_external_data_or_index_dir(*part_info) && + check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE)) + { + res= -1; + goto end_with_restore_list; + } if (part_info && !(part_info= thd->lex->part_info->get_clone(true))) { res= -1; From 202355104f3a4b2524a6b623886c8bf4db49c02e Mon Sep 17 00:00:00 2001 From: "mysql-builder@oracle.com" <> Date: Thu, 24 Nov 2016 21:53:55 +0100 Subject: [PATCH 030/124] From 64cc76bbf8e4d21cffdf2b2b3644ff8a71d4d97a Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Sat, 26 Nov 2016 20:41:48 +0530 Subject: [PATCH 031/124] Followup fix for Bug#25088048 - ADDITIONAL ISSUES IN MYSQLD_SAFE - Removed mysql.conf, mysqld.service and mysql-systemd-start from sles spec file (cherry picked from commit 35c1adc17c1a99b2c256d374500437a6ce21339e) --- packaging/rpm-sles/mysql.spec.in | 43 -------------------------------- 1 file changed, 43 deletions(-) diff --git a/packaging/rpm-sles/mysql.spec.in b/packaging/rpm-sles/mysql.spec.in index 6652cdcccb6..1b5f1806321 100644 --- a/packaging/rpm-sles/mysql.spec.in +++ b/packaging/rpm-sles/mysql.spec.in @@ -24,7 +24,6 @@ # Regression tests may take a long time, override the default to skip them %{!?runselftest:%global runselftest 0} -%{!?with_systemd: %global systemd 0} %{!?with_debuginfo: %global nodebuginfo 1} %{!?product_suffix: %global product_suffix community} %{!?feature_set: %global feature_set community} @@ -69,9 +68,6 @@ Source0: https://cdn.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/%{src URL: http://www.mysql.com/ Packager: MySQL Release Engineering Vendor: %{mysql_vendor} -Source1: mysql-systemd-start -Source2: mysqld.service -Source3: mysql.conf Source4: my_config.h Source90: filter-provides.sh Source91: filter-requires.sh @@ -81,9 +77,6 @@ BuildRequires: libaio-devel BuildRequires: ncurses-devel BuildRequires: openssl-devel BuildRequires: zlib-devel -%if 0%{?systemd} -BuildRequires: systemd -%endif BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) %if 0%{?rhel} > 6 @@ -141,15 +134,9 @@ Obsoletes: mariadb-server Obsoletes: mariadb-galera-server Provides: mysql = %{version}-%{release} Provides: mysql-tools = %{version}-%{release} -%if 0%{?systemd} -Requires(post): systemd -Requires(preun): systemd -Requires(postun): systemd -%else PreReq: insserv PreReq: sed PreReq: pwdutils -%endif Conflicts: otherproviders(mysql) Conflicts: otherproviders(mysql-debug) Conflicts: otherproviders(mysql-tools) @@ -435,13 +422,7 @@ make DESTDIR=%{buildroot} install install -D -m 0644 $MBD/release/support-files/mysql-log-rotate %{buildroot}%{_sysconfdir}/logrotate.d/mysql install -D -m 0644 $MBD/release/packaging/rpm-sles/my.cnf %{buildroot}%{_sysconfdir}/my.cnf install -d %{buildroot}%{_sysconfdir}/my.cnf.d -%if 0%{?systemd} -install -D -m 0755 %{SOURCE1} %{buildroot}%{_bindir}/mysql-systemd-start -install -D -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/mysqld.service -%else install -D -m 0755 $MBD/release/packaging/rpm-sles/mysql.init %{buildroot}%{_sysconfdir}/init.d/mysql -%endif -install -D -m 0644 %{SOURCE3} %{buildroot}%{_prefix}/lib/tmpfiles.d/mysql.conf # Make library links install -d -m 0755 %{buildroot}%{_sysconfdir}/ld.so.conf.d @@ -461,9 +442,6 @@ rm -rf %{buildroot}%{_datadir}/mysql/mysql.server rm -rf %{buildroot}%{_datadir}/mysql/mysqld_multi.server rm -f %{buildroot}%{_datadir}/mysql/{ndb-config-2-node,config*}.ini rm -f %{buildroot}%{_datadir}/mysql/my-*.cnf -%if 0%{?systemd} -rm -rf %{buildroot}%{_sysconfdir}/init.d/mysql -%endif rm -rf %{buildroot}%{_bindir}/mysql_embedded rm -rf %{buildroot}%{_bindir}/mysql_setpermission rm -rf %{buildroot}%{_mandir}/man1/mysql_setpermission.1* @@ -496,31 +474,18 @@ datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n /bin/chmod 0755 "$datadir" /bin/touch /var/log/mysql/mysqld.log /bin/chown mysql:mysql /var/log/mysql/mysqld.log >/dev/null 2>&1 || : -%if 0%{?systemd} -%systemd_post mysqld.service -/sbin/service mysqld enable >/dev/null 2>&1 || : -%else /sbin/insserv /etc/init.d/mysql -%endif %preun server -%if 0%{?systemd} -%systemd_preun mysqld.service -%else if [ "$1" -eq 0 ]; then /usr/sbin/rcmysql stop >/dev/null 2>&1 || : /sbin/insserv /etc/init.d fi -%endif %postun server -%if 0%{?systemd} -%systemd_postun_with_restart mysqld.service -%else if [ $1 -ge 1 ]; then /usr/sbin/rcmysql condrestart >/dev/null 2>&1 || : fi -%endif %post libs -p /sbin/ldconfig @@ -596,9 +561,6 @@ fi %attr(755, root, root) %{_bindir}/replace %attr(755, root, root) %{_bindir}/resolve_stack_dump %attr(755, root, root) %{_bindir}/resolveip -%if 0%{?systemd} -%attr(755, root, root) %{_bindir}/mysql-systemd-start -%endif %attr(755, root, root) %{_sbindir}/mysqld %attr(755, root, root) %{_sbindir}/mysqld-debug %attr(755, root, root) %{_sbindir}/rcmysql @@ -629,12 +591,7 @@ fi %attr(644, root, root) %{_datadir}/mysql/mysql_test_data_timezone.sql %attr(644, root, root) %{_datadir}/mysql/mysql-log-rotate %attr(644, root, root) %{_datadir}/mysql/magic -%attr(644, root, root) %{_prefix}/lib/tmpfiles.d/mysql.conf -%if 0%{?systemd} -%attr(644, root, root) %{_unitdir}/mysqld.service -%else %attr(755, root, root) %{_sysconfdir}/init.d/mysql -%endif %attr(644, root, root) %config(noreplace,missingok) %{_sysconfdir}/logrotate.d/mysql %dir %attr(755, mysql, mysql) /var/lib/mysql %dir %attr(755, mysql, mysql) /var/run/mysql From 2d78b25c49407fb3f17fd4e44b551e8b43ffa4b5 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 27 Nov 2016 14:42:37 +0100 Subject: [PATCH 032/124] - Fix null pointer java error when connecting to jdbc:drill driver. By setting the context class loader. modified: storage/connect/JavaWrappers.jar modified: storage/connect/JdbcInterface.java modified: storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar --- storage/connect/JavaWrappers.jar | Bin 19615 -> 19696 bytes storage/connect/JdbcInterface.java | 3 +++ .../connect/std_data/JdbcMariaDB.jar | Bin 6021866 -> 6021947 bytes 3 files changed, 3 insertions(+) diff --git a/storage/connect/JavaWrappers.jar b/storage/connect/JavaWrappers.jar index d5353d2cbfd08c449d2c4ddc7a81b1f8c32c1ad1..8c01c364a3f4d8c05872438b5f3cd766cb3929e3 100644 GIT binary patch delta 7907 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 diff --git a/storage/connect/JdbcInterface.java b/storage/connect/JdbcInterface.java index 07dcaf985b4..a1b1360e6ea 100644 --- a/storage/connect/JdbcInterface.java +++ b/storage/connect/JdbcInterface.java @@ -82,6 +82,9 @@ public class JdbcInterface { System.out.println("URL=" + parms[1]); CheckURL(parms[1], null); + + // This is required for drivers using context class loaders + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); if (parms[2] != null && !parms[2].isEmpty()) { if (DEBUG) diff --git a/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar b/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar index 9d461ad6223b41e2a18d97773a064aa8f96405cc..8525da74018a98ffbd5e6bc434940e885ff9b9a5 100644 GIT binary patch delta 147634 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

    yfm(S=wE79z0UwxEgddZ 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 delta 146234 zcmZ@g2|U!_x0x|BjA4eE!7#S0iAYo`ON&y<(!wB1n@EcmEy9pWD@wW1f)=HXQf^Vv zz97<~P_(FsinM8a_j~W4U+=y5`F~!%=bU@)+0VK6`<-9$jSsYz>mO*!o^Et`K_3ML zg+3=YFF2*FDo^*AH7(UZ-iZ3Qz*XLaf&W;nXh8nhsWOB?XT~f@t>h1qes+9w*Jx1s z1q-9KMn;Xd)K067lrxa`rD<}!T;(ory*=BNX*y_z$&AI>j~FMs-;Fv^?R~6p>om{$ zzL$>%+?zL~IB)sAlgrQUUf}h+;rxe+-9v86=l}YYy6VHzruq-V>m0s1L^tofTB&+Z zboBn{O<`A(R%Yc{2|R31wzO~x$NrFxZnumNzBPJb&Xp7KZSgl;^=qH5T=?dZXMX1G zhdWCbjo7<(f0c)0*6BPRxEWY2x`Z+OOwh#^swn&h_w|oPrKUY@;4{ll7nUbgy)x98Rh!_K2=Z5 znxFiAbo)w+0d0pxvpx6KR}41GWWRdPNnnTVsjsj*vSCxx`-urRrfjUYv<{{1yz_Ka z!kr^x^$&s|Df_c&#dPns{7)TwFMDPd&Z+1U`;96aamKd7XZUjCU|ND-sQm+VZCCsG zLz%8i~2DuWVo&B>C4h&{mLDzAf>>fVO4XV z44pe?!mI(0>1)zHuU!L9`q$mCHN1K>Jt8ju;@B&08do!|8}vA14xEaW&b_6lvtf*U zYe@S>yTCQME8~-kLN_OlYF=Jtqui3CyLRG!E4B5;M+Y^Ao;V-8>;NddVh^uqxU9UE z6}YD3^yoS!ZQC^k%Zw+|+}w~<(3R5P??4@WTLjQ6y(n)tv7VRgQrvW}#9007=Bqy} z7kyQ;p7Z(rs6J6)!^2DHOr`*mSYv+5+cH;&WtBaYpOZ|Se2mHS4YOylc?7K;Vqw|o_iqEfgJiGKeU|6&B zVZF6^XRp%&QeJS!(l)M5UU*>mh-Jg8J?5p)sh(98*u^t)u561B{C2gIA9ueXxRrbL zv9)Kx>?6g>wPQ3^HXB-3IMeDcc1j19LFab<;VAJO)18QW0^@!pgyHc>2>uP|x-s!SVk#TJed& z)s6c+eFo@cjdSR9waGrXdEi@p2d4eg+`VhUCP!8*{xZm`h0k;t?{V4omYPn~SMy`i z^&TO$jkCYqXIkzr7-3ufN^i!AFOol-9y^~YyUW*&V#=kfoynW*H(#CwV z87dF^UN>6PE-{*!V=3g?OcFJ#9Z=u)%QpV`p#>t1d1{AZZf6;G(k|F+D6i8yEebn% zLUcZ=xoqOg*16I@CoiRxJjryky6@xADLhyry_d@A(u&c^RZ-6$()KlYUlQG4aACcpdA*;UDNisGC5A1t89RJR`;>2xSF+wl3@lu=n{LoR|?IfpZe%MX^#x)YQW z+3&M-Yx7{y*F0~pKY5%kyI;&r&4V@@B>wgo9-A`z=)UQ1Qzp6BPrH%HavJr(2Zq!Z zE@|d=nsR@s-j1E0&HR=Atkf~xb<^4*>)SP+HD9&4b^f)M?+XjRS5BNR(_hNx2WJ-# zRM%agaB!bwgk8~9am<4(*xc}VIsZ|gEg!7=StzfNChENKX;wVWSw4fa$~xOJr~SB1 zQ{IMawA|JH2+xmUp~P zdf0%<7v|i`AT9kk<#JE3}esTDN}mB$*r$y ziHThQroR4pDy`G?HgF`{YBS0&mS2&MM90EK*E-ku>tLa^d*;lRL_fG>>0+ z%X39KyDqd*uqxiSqVA>DZ>#V%FLO>mFz~q0)VKA~mcCI-B6AGBF!z@2K7aqJ+}tiL zyE~0pM{F8$@;TZ@qbhZjZ}biMo@bfDyYiIz)pbc(vwNXUKu1tV#X;%A^22_~!b^ck zk55^|I$rI+F?Fu1b*JdURxhvB$5V7?jeBA=>xZ(g>yp8vgO+~jP$>@@#2fXQea~#F z(%f&BivyH?dR<&RXF+Q06f2Xl+g2XBT>Smw>(`-%8a20X-6}hBTj^1)Vrc{4_1nd0 zWwGL^{)3OWKXBgV;&0etv+2{~e$w}K6L+2drpzqKTy*VQ%B<+ugYIcYIL7Uo4(KbGLWew0t=&NRoTnvUcfiqnetF(JaCIyY2qNuIm;I7QCIuZF^w< z!9Bsrf<<2;P_8;YK(~C^nekmtGe3^|zHlOYnMs!LRBnIWgssuJaTnyoKwb~KV+ z`y#Qa_;RIA&RE}|J??U5 zbS}pkJ+1h8=5pe}dm8Sy(&l=X3=mJ-RyH71y7S^>w?I`Dm!emt`!-H9`Q^as+wYfe z-GjNxzxNz*f8mtwJ-1!s;OET~rm0vum~1lz?GdW2c0~Y|dRizuxfh_iw|0 zI&h^L#nRxM*o2bGBm0;3H7h>;RCs;(QLCWC^oMK9PhYOFIFwWdT~hu$Xv}P{oHX31 z%xa_d)9)F}E;){+jfr`Ef7-Lf8omZgVrP9^^nFE6vG2O<(Eu02(GQCFE zp82yaeq4Hvu9IR*yJPIQZHdX3W2%R7uFst4>$a)VqFOq=WLwRFX0<+3#v08q=jNDy zaE-7TQ`#?c*_(a5J-Q#Jtm<>PV{hX@L*=!)8`p-^+#0;S?`Yw%_K*RKA3QpAATIsT z*@@};Qzm$vlO8nrE}eSbdC%M9K|0~Nu>!^OuglJ)R*ZUdY)JglP1!$Nrrv*;+MqP{ zRrJlbxi(R?8>eiuyKeEhe29ahms^g{{3YKm`ApM3I`&~k>^u)MkA)w*60UW;bzWqq zYu(UvB+Bmo0j=$M)}4J?`=}OJduSf@+Pgk()7qx{H_KZFUK@JdYU541w7Ay#Qa_&x z@3|`L10i8^_j$dkSLa?aTP!HP?g{=6-D3QqI}9#pa7YuRqW?G&?)PjQNUmW)1;(%1jR*uuBd&${ki zU>5LMx_y29Ypw_E-7 zf?i1*lT6o{ZqMsGtofCnPeMnhT_(HpY|4%1a8=>EcPq{B)hJFqnm1=^QbW|O3|C>w z^o@s`&)vzih+SjikOPJ>N}d$iC;u#3_i@=#hbGP$*G0=uybH_Np7HX&VgEkGlPd?6 zdr9`+*=}92JwjvboyUX1Gjl{|PaZxpHnwHnX03hur8oRyH-+4;Z0;B|F81~9%INQ5 zM^BW#eUMRbihXbPlFe3-i4(^-Ztq;Aw}W7xs+~C}AG+%VTnnGR^l45^|KNtX zpQnZ|%A?GjV}B6+lOt?9Vf3c`PZ7`wH?Q$23nJs zK25N-|339w(g^j($%`r@!MU$j&8DnmdmJ9!6*WxfQO%)`Bkv1OJ{lXi=J1>i=hZXT z?9&>ieKLQOx}m1`WbJ@aZD-a!^0Yc}=$%5Yj@KtI%^z}W%T&L8S@Ha-Q{0M@u^RV3 zyj8n<$bG;8o=3Ljh=ii^@lp9pcDz?dEyoi$w1o z>0oBeR|^NzZR?8PjK7q1&iY+J=+eeH$&+IznU)5UuaJzcEUq{C?X zxxV%GpZLmG<&WQHk3QzG?A+7Q{g*zk^B7eU5*qR{>M_SXaD#69kHm8qI~Hc>7izxg z`ZcsBQ@Xx+^MHAJ2WJ*ED;M8B6CP82((1}d<*S`)_jxe~-uhej-*@Ri=ANVx_V&Mj zy#A&)Z0uC$>7%b({~B{|!(}HuhjY)fbe?YRRI%+dcz9`;X?4RK>t^9HtrrXI+t$xJ zIc8?jros1r@V3@et#10%H-KC4%$Zxw5_|ng(fP~`Gt9pvT^+b+0DIP)MS~7J%Q}8w z>icYZ*z~+Vrj@Eit_nqiOhll+&6`UktX!Oymzuc;)Fii+?1$q2lX#JnKx!hdC96z0;O#OO?KKW(cuS%+@1N|;R5^ai|efo_q5edJXJrT7LnoOYe$pzc59A&X6Z0FXEO+lR>PUZi6W0Wr)v9a*5evE=- zy$7vq_|228|u_EPl@j8Iu2MKtxSiadN_I-!l#@)@t41b#HV+CoHf% zG&o~&l+vi{lM3v#Ab)G?Qr|s$y$0Q1|759JhW(mCjndC9p|6|xVe4aDFU|^IuY9-c zNP5eRyH5QoqIDKD^r`X5N?(-eDjhT;X>-!y^qIO&V=Wfn9v}MpN9Yf^bH8~R-)}40 zO}Wu@^M3gl_eb}+SyODMH2ck7W$nYxxNvacgZ<-wMC#tApEWwTaq^|A%Bn7{+91}o zpuWjJ*=;3}vky$r_B*6}V!Ow^>_gVx9ov+fb2 zhsT@_4?E4Ac*y(v)R2Kuw`V?hds?BwT5;0c>NnElkr}}@ixZ|U?C@TCC;sim#vKO& zY;K2{Om}Hn;BwQ9HNomi^`YZO)&#s7_s#u{#nDlF9?5yoe~2$=Sq8E>6@$jFt2oA9 zVYqUV__CYs(bTjT4U!9i4=%hGXU|*eKP3Nz#?r06{BqIjVJ3Bw8k+-)FXhr#w@zHz z`g4Zkq#J(2q_^%EeOcz;y2tj^`&xs2{daymuFAh_Yg(@Lni0moaChXS$@^LpH!W!t z+|T}KZ>Cz)SR^uy?;mkdIr56!^hxyA%ZpQoW(w{~?59s$r|@gZzPO^}f=yNlFUrD9 zJoeiwtY7!Bt;tNMZk73obw2Z*+ly5F>dViX8NWNiZF)6e-*~Cd62pLs!}lW1EEkRW zzCye5K=HSUMaddj^TPL!^StVCxx)6^=4Ri(QR7yo4{q(NbJVJKy~F;iN$s!Ba*7`f zZr{1Q&hX1#&DEy`JDZ|a%3Js9m+1a_ccQ9h$petIwUAT>fx+JMSdmHJ5_5 z5l5H1?>G7Bpe?N#dGjz=`pI{q*~YszdVZZ(=YN`UD0bIE$K%!9Ij^tI`<1f$_!098 z@x$>3!`aJxZ}p$CcAD+hx~z{6Z8ujQGI2~+Z}%Ivd-z*%;J9}y9rjkfIk3Kj_xXp* zks7P9Cv+pmxRl?WHL!oJaO|GLpB}6CH!m0XyFNQ0DKE|3bI9BI_^IT_tB=P?&6)rVxq7s~Yx zPAIr(SLgWK_{YTYQ^F^CY24X%Qt|7gtI^VpgLj{O=sUJIj5F*^jJhnl%DZ7zr=0K`G(4pasAe*2GqKGxtZo{>o~aFYNqr_ zh?};7zxGxI^~Dbyj;7a*e5=q@oO$Tv7p8{pFq{5IuHgQnWy=HM&r?O||kHuOSHb(!HGjH5I<7ZvU!w*?e&)h7dO#@0-T+aNEqxoTU z$2ZNk*Q?+9U8+1a4BjHvB*U&}m92mRy z?u&8F(_{BM`oup&ulv|EVvJAw{aYo8p&|Ha$?5bT)q==nSKcSZv@ zd%snFxQ-v%p;;(3ZPR?Mk$3#XfvFWY8>`ckW^IUn^~_IYlH1Rlr(i}#@tP@jBfUc2 z_=V2vu<%dyNw=C+9{BduuDrsEr57eocs?Q~+wtVWgA4t4D|r^ENmXip_TAH=FsV@^ z)VySa+DqeM2|+hbeu*sFP$G9TnlZd?NN!@uI@_)Vtq~1NuPv^>D-DgQ)kz<4`s?9+ z_YOT=Cz^09d;w@ZGrglU6kHgP>gMOT>SA?Kxi~u~OKH%#my-&!QXhU?{4>%@r7Q9C z=ijQoy9`6WnSQMCc|O1?F+@7j?VH{FIVEF$eeA#XXI_}qAC8^ z?$rOYQTO!_oqmmRZF#Ku(irLE334l*1a>)RfFwh>ve_xOGW)~s1u?+CD=GQWSIb$4 ziQ)oqmML7ox>K54Es|(aPa1a>_Mt?wT1O=*$X`fw0JLU z@$!9e>~yY2(@=pB3eo=_&SiXYDcm1bEtnQ;KCd)8=i(R9Ypr(yKc)_vE;UV0`eKk% zeEX%Y5ezShEps~frTELcWb2OhSNWe>4|Uu+z&tWy!H=ukAJ+;C~I?@G_Ek|P`IV@*N+#~v+69Jr>Tvw@{B)u#pz_5 zQ(#7)_pvUlNfFVWN_*E1vr}AfI{N%%yEt#Rbw^dITEb4xi`ySkZEII1mv?8q&m7^3 z!w08%1}+iioo27|=s0WX%&`y47z|__W~*Jj2EFht%T# zby({?VriQCf17e|VG5&W?zcheH8*v>WMrPHDX0y+-~WB~sIupoJ{>JrZJxckpDv)s zyi{QMvrOJyo=tC!bhJCVby-I3n57R~Ov4V}AFG~oecg%2pEdjoySBG2VtJ_iQ8oQ- zRj2!=)=A3z-RI*9nw0mgIL=A_r+=K&&!Fd(55L)O{5|LQrggtH)VtE|y`4L}O8Ri) zZ=p+@^0-?y*4G-wPAInzo_yOrE7$hksNHu2-*@bf8fnZnAL!Xk-?`w7=k;7)&q6G8izuk?808w|^Flogmk@sjYp&=Vw{{ zH`qFE4!gY};yf$*JtH$Yp)#g%sgtD_SAVMG$o>zr45#}oa6d8lu=nukn^x}Go^Y#r z%kz%AUgp<6%)BcYVE!&(yY~~7YV(^WC$^-T{IYiaz-p%J|59*uVpp@IBfAEs#C8Ov z3>e*P#|+zPdT`n^&4Wq}md%UZtBw0r&oQ0U#dGB*bk0bLWgc{*S68m-T&n-;e5&aQ zbI+&AE=AK*2k0d%Gj6%MqColBZTIRa?iZA$ih|_07fM;*`kKXxE`L{B^Xb^1`-AsP z+&Zu5=;^ydRSC( zdolLx_<*>F6PhPHI9@rjKR+z-_l?v^k;}4+c*2x%0TW-BT(!9wH1nd1pW9Bf7Sik5%ac*-&-Y4$>jtLShd!C_pjX@GY(Xw9G}|wr;n!_OQFG> zYcA30)92U7KIpmo&2FCn|J22bS_Sn384S7$dae6vumT6a*8MO_OM#AF{HAi;jHrJL z2Du&QV!#W(V*GEGzaIYgioXf9!as=iw;?p83+j0qpaZKY{|N^6Nm>d%?iG5CG)G$V?Tg7OM}&x)mC@QhL~Vd~0sqk?lGM{F=; zahMSw`7lI#<=I2!}uVnY}#MAfWj|?Q_sGsapzxRYJ<&sLg2j9hX|Nb zbV!Z@rw;sJ4*u9mlv5X7P{eeeao$8U1m%E=K@vg1^$WQSRYW|#&tLyHB6Y@eF}0La zaQI4rDz&yC;K4xr2iS9ohS};CJZU;gEHOjNO9&$9-dx~(OpXQS*h%yY?zIMBagh|x z6oa&9-bOp~<mRQ1x}j(DKSI!hNhs%A^`R{UIJxfj*d>kSXfGx}9RNypUxho7za%_g&SQs26 z=Za;6=uv`g1)je}TL*W@2_ae=NvDWY10I+IBnSsche-smBSdbJGG_8s6Iq}eVF1&Y z$sNZFz~V_nM;N87=oi4KvZ*jTAuU;=!O~xgs2JfbtJSurLw?J!@gr zO*uufcek8+koQn-DAAjOK_vSt9NSn5;)pB;jRA5UBpNV@Mten~Ct?SRmG{cX#+eM7 zkO;~3LkcZ%l;{;I(iRhY^aL5)$EJNJOSgUS5rRBrnkiO*VgwN*rV{lCkx>p2ZrNK0 z^Fdvpw<@r9lBj_B&Jsh|DW;v1$8>oHv;vZplzB@XXbRw&vqTd(50)_DS##Pz!o-t4 zSqOhy(iW4gv4o`~B_ep%nr1Cr3$;X@}85@LC)iXlpJ|87V-U@jcp4!F0hM5yBDgzNq6{Mz z&@u&hH=Kah<0bOYc@3?RxC;^6faGz=)AQHTY{|Z|Lc{_kduU7$>?&cyXPanSh-Q?3 zAu3*~BxWdc17vO?K#WykjPj13<~T&4k{J^Loj94{SmljeZ`SaFl) zhW}9f>}CW$x=D0E)kLH<`xdPqG0}oDpW$h@Xl$_hAuSb?sy?Dw;y*?{LeYTY5*&R* z!zCV+KcX39NarJ(8U91BhGv2P*!GI23-TLj@-U)?HiTF-JCjdf0Kqt*%^j)H^q9sX zSUCj+8P?td1)6>>?JnljuE~T8@mtYoYNmM}s6beo_R_CQA%KL<{W#hF|`s zMBvc-9nG2O*bQTY5ASI#5F0OH15Yys6FzRGwGxt&u}Ej-;tEc!ybjlq_xTwUP#ou&j-zS4-vRA10#pfYcXHVpboOC`b>l<8oE8Yun4 zBD5uARCOU*?oTK_+(8sP8lCmu&(A<(7p)y{hdoCT0NyW@nty)Kn*TTa9tIJc%19M~ znXg0@xV)nA!QkJt9hf4}4TT(Lw%S*sQuv4Vf%x&1og#)G#8lY6rHXU~_>@MMBXVMA z==w<%AxEC>LV^m1J)%>FQWjmGaKdyIhz<pP%ygVsEH zC?UbBqDKy}n2y#~tI`h>#6ELQx7gDqLQu%3w_!o4@Jq9zD}o9EomiJL0fuM>NHn2H zNFPc#P@+%a<$M#sbQbci3hdx&Hl`>_{({T) zn!^Sg`ep)KU`w~g%c+_{O4}7%`a*)l(N2{+5IYMwHE=MU$K40|x0Zb#@yO$tI;{BFL41Dpcs`B*3%4}%ww zc);yV6HExAXJBOaA{OKX)6bEq0EaIY;@uqj1j78d2o-A#n?9GWO{z|hJ>b4@y3;>& zKz;$e4sSvA$Fzm?hr~iuOQ!gM{6!K4Ais#7PT*AG?1l@$@#}^P;Q1nY14d#Enj&N( zW4mQ7rjz5#^Qqdp06lTR@d)IU-;3$)M3P=a^ip~n=5uc#iWp2gZ?QxjNS4u;5dPgf zVArzlI$?0In|Ane`d&Y(Ki{U#>EWe0;i z&e4Twk*G4rAErkTjsJ^;rAO$e$%g+RE*<-S5Eo9;r;?i9yCQQrs^7ED($D_G3L*iL z@V>C|Jl%;z4rOzQ#2Z40ae$ylAv|%J{y^(LiYkE3D^WTW*3)x|wy0Sef|`}+D3IAm zUqm>gd4M|yFT+C?V#R=C$H`lE?MEY)HGAINC7EX~rO{RDhNHT9E zh01RxTySBISSYXbPZ_0Z8ANbn(hxCE^vDDkR?2H)nc~@E6tgmr3RGMrzm6ov%0x8H z=^vG6|HBg3P6`g+$H?C$^&bZn1p^4C06(mkmyLu}qryxu0*r`3(XFsa9(^-UP1vY- znt`+!i5^^oDfHDp*21f@BwGG@r8nQq*0qi%D zF^eEDzX%tG0BqWT&c(H(8Iiq~f(TJb9w|B)JdR;X!Wz3B3x3Xx;irs^P6`FJhiH?e zFP!7cupxW!3Q)tqqTTXmY$Y)42rN+7CUk1v8^}27gt_!^2Gci7)M3&-hHUD(+@r$9 z%}51F7DIusI)zM1bnCYT4U&2L8S@EZpc^`$;C&|^VoWD6oERAPj=ae^h688e6zaLi)vc_}D^=iFdi|7)%1 zoo@ZeC`L)KXdCizMY$}Ppg|QwmVl_@ngFBi$P?-J8OsS5T=fw946<9d;EJFQ(SZ*? zkSzRq#v@`Dj16vLXu`e?j9>z5i$)Eef`P15RGn&{Gv*M^XkQbMl8UCxl}(Hx>e%mC z0{t^b%rOP>hVaX8#x^1W)}!hNLlJ20M1HzWXUY)-t^?Q*kvq{@QAL3{|F0F; zY6mz>-d~$rrJ<&eRp{a}WxW^|ABv>o=9Lgv@qi;GiCx|>==T= z9IvN|>Ic7j=7E z0WO%qOp`T+9)1>cnSV&=_N)a6rU=~kphg}R#ym!_xa(u39m1Jcu%GcsBqt~~If3wtF-PaH z5XoGFZ@j1ju^~o4s~F~0qDe1IoWS%aR``d@oJ_>!^g8B3A{5rMdvAF-VIwn&u)mqY z984)zxQ$uZt&#;u0!(F4lZECw<_@NBuZv(DU`F8!TYyfos5)V74lqf#BL!auV!^-z z%sLVZMBW2T77RJU^ds!hNuzf?3$`6&t{`=|hZxlDN9}Uod8Rkvf@hJGdZrT4zr-ZB zh*arID`T?3n-V0j^Z?R%$t9+2(8mXSgoFq=kQfe6W>p8!0pIcC(^!Q={N7BMeH06nXi#n^1v@0d^PA&CyiJcPQm|6`_r2#T8x610>o#VsK} zN5TU^IY>azz^o()D!j1ts~eC~r8(#Zd;bgOMC=cU%pkk!pyoA97IYY0p;lVP8{l&~_NLAOjng7x6Vt3JL);>{+ra>b#{wG@DVxSw|!Tp!W#Y7$RIR z7hW#n^4O8JgqRA~4!k0097`3f%0;z1a|~-2S%$7q2tSChKe4MJI+jDW5uW*(Ls62`$-mQKt*$mJNO9)^!lid)^9NamE29Sfn ztScmGk>Rie3NU#lYb4=E=1EVM0zfb&Fd!7^8+#l%jUU2#LzZ^<=Q5Y)v6R%1Jb-nJr;`A)N486?1Am zDd8w}zn-K-NpF{hE*yKl1!$qTw(IT24wnDdymMV8ytrAqHIaREx$=ohT5gegj@zp-%z z=-A}>hBcC$XHZp>VN1`TtEk?aR+QL;Ck2P!|F9Ucvx|blaI9ia`~pOw0aq(1gc0}j z<^w`-pr(?7fW+2+R&ZdjiUPWOr@V%WP48wLSi)0)vY4S75!Q@i1*{8^wTt))vU1Vu zi*76vo>5nLC|lc|UzB_t@UalZ{wFa)0GQH2N_t{^+Z zpi2)!INw3xAX$MYc+4cQNWz6Kt_mwjUBC^k8zF?>+!YFOenAw4=SdI3J%l2GDG>@S zWJ{9jHi}Fztr+clahZbPZ_81LOAi%z=;A{`Hp|cOupD)N$u*pS*I>mnLeSA14Dh~o<)rRQ_-GICP0 zQDgy^OXvht$yRJ9b+ubxF8s(-G$9IN`^A|mvH^mjx#0_PPsGVFQy*6_*kP zv80HY2Zx#~#`VI|N>Lzxwon{EKzNnJO7ZYtkG3|7QABZsoka|Z>BieD9_Xb5mo6g# z%tk1d_rhR5C&jYAA4e%x|Mh6?q9{9gP$yAXHBNC9VUMkjq~(IuSJ8AG;->hGWHzba zHj4bzk_$|@%TsYfbx8o>gu$u>-$IUc z-N=4~4F^$Suf%_$=>#2IDCMngqbPJvWy?|zH+zgozfIk@>|_TMSK$k63IW->*vkp5 zcb^4!&^~uF*w+XG9V-cYczZ7!5E$Cq7C4uoLE%IedlYdbHPb`hA$GbfzLEa{dei_4 z<>->6^C;VgSOf(cns7I=c_8?h91|vDpX>_-v^aseI5^& zP)Pv$9Z{0?K$PZYK<|hW8gIeEmQ_>!EGuX;4+Au$iSNHT;K<2bSxFH}{7 zVdFW8WC59ODB~fR5cZ$Qxla(?)f6KHaHt1IcJ}BsxAh}r?sh*;E)fdf;oyc)8pJ6e zFnm3N`v`)eyVcnoS$)Dm--7_*HOQqm=W@u06#(61$(kFr3{=)gOrcpA$AKgvx$&c9 z#!UA{ax%z_N9K|q#G(}(3p}mEeOoyTH{*ImuKi>rsvzhIa=E8SSxEz9djb+zom5tY zo2->z6FtbBOfAEROgrTlfrK9(33?FuJCqa23gj_EObifA0a%+EG2yawWm#kEuCtgQ z2k`1pim`H)X(U^FLLH*rK9gwdm0;0jWft@*RQ^V4Vh<~b5I*?JEbw1qAgM<~)1Q0F zlSp$XQy(RB)KhdDQ(TWOM6w?%%TDDe@eMHoKCM+wB?5K#b-Y3c7Bnj71Yq@hUE%De zq6{*}swjaEPmwa2jw%&I@Lr2kBoL9T{>P>eA>MjpemJnvqayU#uhK{oqjz)12Gq2p z&Z^{)OzI8MhAS#+;6wx3H~5l@FJX_%Hx5UHmAX*u;S2???2{GziVtITRk$3IDd-A+ z5SF4h3_Ml2Ot?jrJB?8E@B|p4EadJXo1r8l!+h^V6^wrK2!dW9iEXsF9b~ zQIE0cK9voFbh+sy<$C>sv44!Y3^>4mt4FZtLiX>q7@J_ob;DSQX1^dpho&b~wy4b! z2@`C3g)Tfdm~qt!wm0u65?E=@O(Te2E913(O(-FcSaP=$Y>#LVVe3h@p)Ci%1vcov z(}9iFTNmPdxm=L)8tK+y%MCRmCZ!q>wl~5uNgU!E&aBs51&|jcyW+;?!=QC<&^d+` z%q1U0L3BaZOl*iljv|4c^SD{KY2coVSCy^ja-eY>H-_whwZ*gu5o>}a>45=E9D9PB zjDsAagA^cJ;5verRTXjzNd@kK0R&To=WcPW$cKMazCh(y+$AzIpve@XwS#(l5I~QL z@Yj2;5pD|I(kcQ35|Ozw{2O-;NoQO!sRa~P09EKbJ#wu24}uM>+t870xi&9_G#Y%e zz#>~2^M;Yk!?)fP479XK`oUrgUNtcb>cED;+Lp%wC4+cmTbvIc$M6(E@CWol^~WF{ znZhuS9ylCf%iHo-jp|15{&V_8hBSoM!+7Dc$l8NGVCtq+0k$7eKz5GcnG;*%_u2@n z_TQIW*hmx@eE5h`=$JFlh-4Z{VRR&z$m0V4cBGW03-2OP3eQ()g#hYJfT41u9b$$>Z~@l;p34p~1bnr8sTD|oJi z0*go?AVL)X)#VUOA8v}}35lzzqaRol%hQI9>v%f}9lEl!!Q6YQ7OYC-L1M<d=Q6@Z5GUjG=w88u69MlIVb!xa zi1?2B%+z#V6XDX^qp$?}T@ra1n#ofk@z{M*V}Nd~7A(%?Z6wKvZ{Oms@>pPgu`Ga5 zztsf@qzn%hqvIM@yc;HfFG_haL{O@>Lqu0k-Xmiv@Ul(Mc=9BYP%e;HfvD;kf~ppt zI#g=nW%hUky}E1R*^@_PDMA7yzfhdc{K(TG-~Lc8g;_jR2XfPb?@uX-d0~sJdcS|C zt}4)W#&DRP>JHrQAgXUIG8>!~q1pU5HRb(5u|#uFEyCW0Xwo*7ZO;}P?)>Ph1T`k8 zt|cH`hpC-FV}Yt7EcZ~IJe9HrM2#4bq<)SVqg4j*Pl4(RqI1tGxUWc6b_H+Yq8sM63zpuc&H~fWj{MSgrc+g(zlB!2yTvs{uJTRXckf0Vo7CyQAts ziUFQw5KIjotx&y6U}#`P<%5D{-BY#d2`Xdou~C%`K_>SJ{T> zGXph0q9qaSHmfmV-g>o_gc$kV7$VqPLf4}k3`$bFOw_`6eAaZn3h>yj z))TG9!1|XO3tUk0Re&km)d0~H#T^<*uB$0h2q6s5Pz&!inzn3(7ROf|YUilckY+{+ zKv=Ef_zIw1zM2(5crM|~5F;+Cu|XpTZFK0oS|||;hZ-dmMA+YCb38R+K{qM;n!#UN3aV6n(f8fI)XE5gk{KdIED@u}E$fN0)}_(&m|wfQ2lFJ;6u4ZZ@HBtXKCGvMp|tJN_I zam0+@NTK5pm>!D%p1+0 zM5Z_#kcg8IIH?O*(0L+15SNBtPWi!nHCPwOKT6z%Q|Lr6zl~IXoV9pIvB*~szFNd5 z7uyi&*+z_t0~M3RiF~=BMdYgkcP!`2zRAHZ?8d6V@+kf?+0Rav@U6gcEo8j-G`

    fwVjW?r2WX3eZz>8$6D7{3zX{mG9kNzKZH1=ds`k@(#1c8t77&sEn`rr=c^5( z^-v72_`#PQhES(Mlde9J&f^DPgK*OO&0j${p{Yq1V5|Po_eBRteP0%E*GF2sU<#Co zj=i4iCQ*h%*n%6fM0+VRMin3ZAb1#0Ap0o@&JKzx9H1`vO*ZO*0R&S5WtzSmxKK~< zg5)Rlsn5<7A@9EvFrf5AV0C!KNbrf+33<^LwwefJLl;up7NAESa5F^a&F?4ZOX?(w zd^^x)BH%*NAi*FK*VI5lvBL{ss-2*$*9hHkbZj$1wm#}8Sc~UeNEJDjP{}t&`w#XIh{^o}B`5eb1MR;nNFclVri_i%L2%iig|fsJ4h4wHQverJl&)#31uAqE)y4F(LwSA?K`MHxUBa&ki(P7JR^AN_Amu0>)KA1X+kBimMWcAuJQL6MfOp z?+mQJ3Y6fN3c+l$C&~~z&{!eR0Pie(m4W*hO+{EzB`_kE!}99;3I%Y$D*>JO08OTN zg*udW3KkMB1NlNXIQ*-?mV^mabIzs+ZxC7M4HUY8{#Gav3YCTAn_F~WVT*pLhxpd3 z2xVV1_wWT`YczP?Hbl%%l5$7!E$l0ti;WHu-(5tpZZU<>eUMQ0YL9w-iELsH z0&P$cQynbikP#mpJn_~-7&cBAM_}l((iS3d4iI+e-6kTLE98N^K`3d}{DpopHQfX< zgr=>p3cMU3Bt8V_tWIs#7h22}#*qj|#x^1B&{T|fWJC2x;c8N+s0ao6%hegMVzsc7 z(4l~_hreQkvVK97LL>mel;Ej2;R8}YadmMn7V4(O3R$o$NjQ%<2E_#72__9e{d`lV za1ddPYYkd}=JG5d`Q{8a7!2BbK)8lnQsQ9OpR6tb`a@A+OF{n+&Mg*(kx;-#NovJm zwMro|2ck->nOw3*cE506c#V`aB1Ap1(bXq^2?5di>qa<=d-o64 zQfI<(a_UdX4F%b{UT6S(ha;YmTIxEah<2~ggw;CgTZ%p7pHR9yiK za6}=ZoS{yBln7B2XZ0G4S_(?{s4D^$CuGef`RXF#D=IoMGQtU+fSO9x_Y+rjYa~EF zT0jeKUr|>l&Y^5jSgS7Ux;VQV->GYZd}p+M>{Ip0#QeRgsfzXTEKc7vi;RqjVa_TkCiPQk4_9T(lzD~>5!l8DaPnWl;eFB zfr2Zl2YP!no{^Isx=ccuA=^Vnvf33n#6M5N1~Y)D@XEf{>dq`I5GLkA|MMEzgcTJj z|FDAN$~9yq{hzf?6Oaiu-qj$V?E-4rh0fI)L8K7l;EM3m6v4)48efUSNiq4UVFbm` zHDo;)m&jm|rV^-dLyjzesZl3;heo|5bpEMf20wn+up)*)(cuV#e`;8f!bVvg=F>E- z$QSL{bQCLSprNTiR#1%*BG})<26{xphC6EZMq*8a-nLEcW&jhdG(VBJ!`?>3Tv+O) znM_o`5~PgOlofu81X_>LoJ6=#wH=^G^s3)alLPPhXs#e);7=o~!ZmH+Za+-{2`1## zUScJ%^^2AY;0LNQE134;CW!Q-}(^`(}D0FFY^TT=wsl6aozP_EiC>tSG?qm73%K z-4c=Tp?AIJgnxI#Oy9rL98Y%puaHpMrfExd>kd7lKK$`P(@A#Jqk2v0GgMrVU6?Tb ztL7E*!CbH46athKJX6pu8>tW3BMh<=i$ zk704i0li#JCrgfN+_b-Kqp z_5i_naI3mj3o#@m0pQI=x24r)S}TY$*x)JqMFP0aTub&1FjX!AvJLtL&RitH086b` zeQ~(qszdDt-95EruEgUP#Q-3fBD^tKYZA#HoCu|RMe5MQPfPW$IS6r9gjvhA#^aF+ z$1B#LDq2e!+C*u|x-m{O{U|Lp_%vE8g48N38G@<8ojbG)NxSMb0b;-@Jgn6_+}eVw z`6yzB)GAa4P((VM$kwxs%Fu_F|;H9(aQs;S}W8fe6Lp(Sf{xSV1vY5^*6NRyTV@eK|K zrwG*De=kIrIH_N>atMN|pAfCs^OwJ@7oZ?;XKTw^6iyH%o&j))Kqb)nbko=9)?h9LewWpC2MGp)-Tk5L zwgT82g`)J)Gwl)*{{O)$!^Sr4fkbi2F=_SM#?a@Z_Fz&t&ql2{Wo#-fq2eSo-~Y>5+?LcoDT#1azVcslOpq5>aJ z602h_u-!wPPxz6a=|qbA!FQ9zqov0_;0t7Qa zlbdWQKpHs0xJYpZUIum6h{?|h;JgHJ3E2_B+`z{K)B%#$i;YR&?-tY&M65+xsilaw zlYLPKMswJDu>ttGN8Ev{G42Nl#0Nw7iQi!mNqEXymFv(+X;G$lD%lI^=?LuBqh2fA zFE%DQNU|Og!_|3WDVd*eT%@Rp*>HG?coK0HF685pWn$U9P5BV!SBO)|!4S($kpM)Z0Mnj`r{bW5C?OV;0GiP(K1~Gg z}5VSHHPhC z>ntJ+aPdYAM9@d1b6?gFsA_>>QRX_bTV8Buv{n~zlTgXd+lp+^*FuN120+yzm_I;A z_Fo9XcJ3x-K>eXQQN*WM4@9R7o{iCY-s3>n=%OS0?iN=xM1j6Sa@CPtbzydh#1Lvs z)>-;rP6`0gF~HqGofo8GQ!lKLn>6A3Af1J>$$)wb*_fcC1wn|;-@WpG*t!nzsEQ{Z zNzoQtlE+LJFiOKsxCKNbZuO7Yj&Hv499cssaK6S?NJV6p$iiQCd(G1Su9k zrP@101wm2x|90lxT@wF%AK#ao*_oZTv$Om5?OVJI19AHjSoHG;0td7CF)bwsg^*Ln z2IlbQh*DmHK@p8mt~X}}8sx+mEv6+ig341Emx45YRiF=tH_hJ)As4(7IGbhXWC{i% zW?7Awcwk51MUovckSKzcObyFWjIMYy@E>+2ZHG23!?-!SE3njB_Qi++ZwIa=QhKIG zj~1Jjqtp%F7s!uM=phY2o#X@i0zYMQP;pqXFR-I9)gxwRzZ3X0Z}rebNAz#j*K`!! zhT`Ul(eDRJ>OprjFp~bD$B`MLCP2QX&1!>lX z2#`lE26kpdD+BH@O>CDSe!d+z zfRv{fIfnifSZ}dO*N$UGjTqVTRDd-69ms1Vnfp)RT=wCqe*+_k==Q&X(e%dz&yY~u z5mgf*C*BP#=hZ(hzQS{=o*`}u;VBZ=z~`<$K{L4+#64%e;({+@9p(P0AXmNtL0$VK zujU46?^)92QR9Mj9&$`UP%Td@bnVj@gM!{-aYDw2dCS*_1P$kCT7N0QTLzB`dX@8y z*ZCrEadARWC<)qTVi29Fzy)8p?k+o|lW1r_EmG8gAYD2!Xafl+)8_>>ae!IG>?9^$ z3UU&G>#^K;Y*ElZ9FlZt*MVihjFqpg4ARP9+@=>LuCA|Xc_8W9&p`>I?@LHf4Qqmi zvUm&M3d$6_UqV!yUJrVWb30(=vcC*UA#Y3k{D}N1haU|3O50(X+ zV`lqhqp$ER2z3*UuhevHejZ9LycE=(EGFN&9P|b22aXA1(W@9|$1VkV%Wu97>Ocqy zS;uh@(Oqoiy>$Mf>D8J@xw9$gSw?t0j|;li-9cB|H`e&KdTNCG(0t{pn?W8dmL(YQ z64~vb!yLtQC*lKZf;x$3UxQh{xD)g@BPt(F_Le{04Vud)qWkLB9uMgx*E#F_I2X}9 za;Lm?6ojtxY*KdX> zBJBNk)3p~bZpIY&xL&8F1Q>~s5=d<;*#Z(zZGq^^qI5mkCh!&W`DIIuuhhlqx-frb zL!uaqb*}0MqJwg6LlY<)1FUSn22F-Lhps6bt%lr0+&u>bww>tm!T{jn}PZ zm@>bDb&-o7(GB9h=qAVQ=PW|RJ)zT1=VZCWdyBwXAt)Yq)wsD9H-Agc8Y>FtFP)y! zSzZKHHwwZ5IyrBuZW7l)xPCA}?AwiAOK0gm;sJq?n?nJj9HW>xiN1Sl>^C;d*RiN@ zT~Fch7Dfy}KCwm4doinK zH0b)X>b9(76+j+;MW?-ldvI!Sbo~gO14$u=zNYi!JgA18z>w=?Wo$35yoJ~}_`2=~ zW^6Ov_V;wI;_6l%uK^Kcj@-f=4o@hgjNPfrX2#I0XZ^oA91`EDa}o{vkj;psN}Ya9TUEy=o#( z9KgoUs7757hm$fsByp0B@97>VhuIQ2+6T*7AL@KKH`C>U2%r17P@xDTmMacnd*G3; zbqVZGsGcmZey6+3lBj@H`g;nGMz}5hN8Q6582Qm5QS!`nog0(Evq}wgg?wh#A^VG_1u0v}#$f zZ8nt9UprW-@~}L!GI%o^%r=bx<|g;74X$8z@M)A#F!AyS=yuSC;9=|v)h*9)SC7~D zwVGcLB1SoSV{kI7f}dkKfGxQTqu_W=lpMJ=*f4}FXzfS7>l!kKg|bW|$opMGS{)gb zC~6wmS@NSLk0a9>+7g_)vrzEEY;H__Z$E{FXGCy_e=}I{ zX~33;hVUUniP851dj#R8Jq}a(LZXiPkmpDh>1w+yy7r-IqU=hIUhKXda*09#MRt^I z{3}Fz%ttoEPY==iDrRKeKOufBJ8t{ML5+KwDso)g&~2Q^z*BqWPYEj^Y**3!E3Ct| zcL>#XG;P)J#98pGn{((}yo6AT1c5~YP8xk4+Clyv6uOmj9o?u6hkJ;+uTego>K59a z7c4dkAiQLc%+M1YqN)#xid%c0xIQ8*LiG3s+rYbvLj4S+s-^VQdb>R#biEcRxY1io z`5@Fs07maVc90hz2_3`t2q{)_;+vs$T7G>h%v)T0H?)%sI1sv@%|9G43D_jgLh6Qa z34SKVw(9rp>CkbujIL6vn}qt>lPtxG*bArcv6RP~VjX1p#n48sWNb;F43_?FXb`Jl zGnhh%E%!|4`#BF8_eFSNFT2H<@3{j#LvTIiOA0 zodhM4>lruMlBVXrgA^(hdt zASrAfKQH?vCu|yEpm3qtG_k~SimCpQS2ox)>BV+%5f0(w7ShOKJ zP+YrS6DRA(glRj*!|s6-VE$ra6Lu2p$A$5|tP+drwaf~Cg~@LxglSiWE}WW$OO$7X z;iUG%VMcE9a8MM%I>;W6hW)~^XK9CHs#C)FjGIJ=@e)rCnHI+Pu&EsAEiy~=&Js+u z{SAyY;^!&P&kEZTLJH2kkjgNjdp!*2+y6kEoqsh;y5f_yT9P75u;rl(M*-@jXJuKbC|AkAl13M0~vQewcR-A$Bz7;d1d2dV2}%CibAR zirDV1U)PGSvW)oqCNjhv552bGXr(8+iQ+$NT!oL9{sxg+BzF)o9rfE+^CPKUFKc=?#UVvFL^?DB>Zowj%0ebE1;F2hPSp8oZJZFOR6&%ip zI<(O1wHXO>J_h^>J#IWz^bNPMynMx=*A6n1To#0*L^@z6io<_}a{vhAUszns?XK^@ zBNsg$CYkVuUi|$RhV|TNeIg@U*`VNW*x*`>{v;7l6q4m)5}};Onsj^lN31@FqYHH) za&?`-nayWwGCp3vlIIAk5hbusa*xyKuhQS;COy{cx%1^`YTcK6)ZzsslYX6zn;M253MU4a=>6pwvtE1VX5|f}j|?B8 z*N%fLr%DWrIObvTv9p-arq)fqG)ljRwZiJorq`x43IQuZOny>}H{>BU zgyIw=pPj6?-0pig2M08!=sjAkHcn5D4czmTzMT6*@(QefO5a63`?P*HtCUrz*RDoV zO@Z_jKReWV$s4ov&sbN7-g3breF;xSYVb)6z6Uv-SYtqu%DHRxk8xL7YG#Pqp?4C& z>-9t_;YF?p1-c3nL!D~9#39F8d%5=&{SNDJupwOJtFP&`hdG!yG(^E>{aFf7OvwZa zlf$>@`E-wzZ|JqX1|m4%RNGk=?a;fhHNwHFN(XW4t7B}c|z3J;QR@7LEdZKG?Ezlc4k=S;4`AFovF=W{KB zFRb{B`N#FHt-OT16DSrRhp}qh5HyuX_1d0|CGF$lt>gLvZ97mOqZhZ_YP-nbbNVIB z*unr0Q7-Fy@u>%jAux3mb-o513%#Qc<}Fy%THYeIdn)cA237)lma{a{tX{ZGVG~wXn)m*Ri&}i1e;S0ptsYFp5m@CWSL&xUv2n^VMyY7In-pB!2@Q7a?lkYa9?@6r@IUpVfdT9q;dC_Wn&Fl zJbXw+wAIP86AaI^(9T;F`__627|d0^`mkXaBgp|Ez*QrU8lGdm2w&>ZLH3zy_>eGJ;&a(F!|)x$u%z`D{}d&=%716#;Vca*Buu@i_N(nEbLJWzVSQ{tcyY1e z1RF|qDNijmXpr)upQ7$CgxcH{<1XlsA)O_*bpfpQ`V^U_FaV}`<%mTT8e^&tu_mC_ zPp&^|_>sp6x#XsT9sA6nt>3LoMcsFxxOBnrF4>$yN`d6*i-y~*0aZs}+)4g>)o_`u zYDu+TL@%AcHfa0GH2TrlL(coo@OCptZoh$nKkg?(0H6_rUNxTU*)KCR}@xOr-efAjh>2=NU&> zVPbnoExrKMA-t)ze#1g*-GqB6Vq%$7cswga2?mH@>FO4)EzZd$fVs+7Ji@=_=fusF z>=v$-`4o>ak>Q{4gBButD-51Ys}8@&Rlkj__u%kp+$BjmSP#W-4-5C@>`Q^4@KCt+ zGKUI$;c7r};W$2Ad)1I8>C9>2&UjBPJcA$cQYO;qS5?Xy{#DAAXg8Qb+r{)%wc6Ukle>6jo-Dx9}M@ zO^sdQ(Q@q8@R!(&q}9>xn4ZeEhg-Ib6h-=*;W->ym=d%^L5+cMmeclxYbQ5pOf_u| z$HV`<;o7YLHrVF}EHHNJyW!ePw>08n-VJw^pC1ixq4QGQw6~D69n5vNNm9)Wa_#MC<5MI9`tH8qrbC>l~ro_|(;mMJ$mW=o+D& zmavxbVpwH&cTo@&@jB%dceTEY5mig=S>-?z{@%g_@M(|fgO*GXQ!8*!K~owKxa z5}64oy)OoJ!_}48u;4VI1QJ3ag8O!h2x*15rVz7+b=%ikv z@RnR;-xJ+3^{rsru6O%3v=!_~$L=#*GrgUpBHcJErMD`?uFtw(>(NTSj~yaMw(3$0N<|`tO&#Tw?vanS zl3oTDM!wa`)519o?7bg}JjDW8C6!)FBhy>MrtXZ)Vwg333fFXKbmNoAlbrZySPo9d zM0oG3NbNx{johYhBNy@pC8ePW-cfiim{IE@cmEq%!sC@j{o-y>&SFRgGEk;-)BqpovrM7wBU zl#_JJi|WPG3egg5Vnvkp!Y3v4VHHuH@>Kt*m7HCbKP1|n<)4(T=T}E{XDz7=yHFFQ zopz+`>Yt5N>^>-J-@_CyR^3F?$tYe(+13NWKSa5SuST8YpX-ZbBE{t#SS0s{sKR{ej22v=4HBo$I=acvVxrIT5t|lWy2}f> z(Tli1v-IXJ?&d;_H_D;|SPYdXWK(r?Iop-e27WrriNm8uu>`P9q;Sly^%g!4MxP)7 zTJ_^LCi+&hp}u%!w3AF&6rIREpo9%+-Nm8TfM{45y^%VTSkw1o16#$DXyV??KouvW z-9_I5i0ru|dI2kGk9RQW>#2O0Z8w04&|RTBy(uAKs6}RSAs4);RytcIIhR(g~i)uaOke{O8U;@Ngq)hoGns0m-G{lHL_(rrA9X9&yx1&8p zyJA!w1OJT9;5mXO52845J9;y(r)UsSC~Q%UH#+o)VzVgA%X>~ew9C9G6o!@{6t1}U z(C*8zsw*15>)|C%m0m8Y_lL4<;e=T|NP*XT0ReEwU!+6M9f^)ll*w5 z5>s+aB~o3`l$cR$S{nZfA-B(s$+u-C0hpJJSrAi40!dg}+h`&O0qZ0mejz52&juad zfEk})=Z?o{r%@0IQF7Snn15rHx)MJfSvPB!;`sq^#@e>Aw?>jh$W=-fMx3}WR@*PM zM8BI@H~{@#9TWQjCu&OQXP$`Vc5;F<(T1dYnU@lc`+m70@&;nO%;QXL+T!g)1E=n zJk>A=!}y0Wafi4au7iAjQk>>r zYNufJL$GXHJ0&idq?L!K#%YTM)vZK}3(SOmZm)|w!GnV6@zY6eo*n1LLQ#_|&&7S! zOq44EhWvFw+!Ne{0*7FWUx*vd?w|o$H!03hTorNc#kOG(KCV7ad)HA3FF~O>p9V$W zHE|yDmlbi*wh<%&+s^60R);rrj&~HEBcNc|wzy~c0D+ph#o!TGfc^4eTp>%UU~e5r&e?gN7@%aM?(cc4m=CNBX)l4T5^C0r+_^_Uu z#I$G*9@W!DOnVTC!W`c7N)$0w6cP_L|6$FDY2X+zon6&ayM>2f6BX=yZO@NcKG-%& zo*&Y)yEUAmWX!0Z{3#H@V$A93FHer|*@hlDt=i=semsib@^SF+qys&hY-?P=oy6vG@bYWNdpa|m zbN8s8&f@vwJspJ8c;rD~J*EBmp0}+vs6h-F53&TN6)8u z6@lSl5FQiIc!YPaPq^SwFnkiS*FAoXi<+$K)5}#Z&gk_$2L(kE_<746eR}zfvHAJe z*Lrp0$Id)&LQ>gdf3I(BaVt{}^*X|#ZA)!%F*G{W%TdN0>6OH_VN0w8wl^cF^WaC& zx&7z8Jed{A-1|~5ZHvI#xj6Xr77Q^>CC+wsMulG%g zkQaj!7Lmc#FA+Tn_IbTW!tY$%sx2(}PIAH}jtd$B?`I~=W{c9;?EM%h<_t@yZ(eaJ zTjY;V&_3ivWG5yi3}VNsK#*lK63+7W7jeN)N7;X60&nGsmIe{S)+X4?)vFVzP7>`8sA>t+_wigSZ2CH2|6UWd1lIZObEv<}A#IfLM$UG;;C8oEcm7vu& zsu5K&a?TTpVcdj%e(`i-F2$zA&z&}NiWAe3;#}t?YUhqfnZP+CN&yfCx1@V9{drl=WmIgvhsT3I`$D95Ft+g zoai8fe@o=!rb5M}^!y|7*AV5IJ-$iWX)a>-X-JZG-kt_@-7Hii7iK|ZM?=z47R5Fd zQ-bI*8=h#FlBDObvOV}HD@cmvwSx`zN_CPKy8|iQATJF{%4DZ1p)kie%DkaT4J_ z#1)(RC4!%;b!7L1PDpYkDJ5jk9vYB!>((TB%9_bZtC=sXtC5|07K>2q$vVrvPbF#3 zx5?)flaugq<>xT>COw_>0GUYQ(5q$y{FPEazcx@hFH5TCJcg&Nc<*Oi5Ya!RRyZD5;G;Y&?+cqPBbFsf$OcqiZDpQ^Z$`+SrC45QwtxVyNhwzC*K zF3C~;m74rCx1;R5CO!F68<|+R7&G>!-pK~G1J!9)70fXwS^H>>ibjb?bNr^W82Ukh zzj&i6nNvJE!^xRB$xh;0Rq_|qKcv$@x);ExoiTYMcL@803&31O-3u54Kbn#^StTI~ zXL0HUtd2jdO|G+OVuL%0>E`5R1b=u97zNKvb`W(-k%meKC4b94w<6^5p~+vjWbPp! z9iIFmx5N1dVvJ8_EW?tba#XVR#2or-hzrXg;y0s{oj6G$%rr#I^4f5j{a|uDv!^o_ zFo1^$nwab&-x!m8KljlJQ8q4FJFaNka#v&$WO3Aognd@?JW5j@VFT)tFSOL{NDCu- zh#v(qr*2kq8=Gnpq>U^d(ng>Ro@X%zqA5_|r_hsP zzGCJ4WHTYjT12$sHcsQK+wa90ksKz5EJ&VWYeDjMSeUHsd{S2mCZ3Ged&p;&Bwt~X zEb-wX7cWho-BLLRnOmP+&g~GcWO7{Du?o8(=uuE-aB?^C)+!9s^)Dvx$q*{#)SiOQiVQS!k0)VuOhiX5i8QyA#Qti zOwnFdvFtz~i7DDWol^ALJh%(-NHEuclrV;ot_mi~8xW&oLsEuY%SWy8T|-JWPbId- zcU0rW2`R_8v8@gx_RpoJd}b}CnTvR1Jt)@Jq->{tB?Rxuv^3~Rg4&mm&)yxGGJ_{6 zvM=#_d`ya#FKn1b<#VRB!LH0n8Of?zX@&bMi1NAxDgSc3AV~&_ zhSe!u#e`Ro*AFgA31lv)4;Udk)u)VMmOarC`1OmoT9z@Y(Y4RqZ?3{ zJG_}Pjpt~KzK(LsJ1O&70tzpv;3$W_m$HZLVwpwAjgGSS@sxP34q-Zj@Y{$Ye)C5u z6Sy(K#w(cdT#5%vYI~ARoS(m#(w)omuHR+{ifxXmIC}m~3fqu`0?1cXe3yb-)xJ%+ zL-B>&fe+0)rur!OuN-pLvwybsL9ZhMpZPu|fky^C%d=u-(+?>)^uA3!`g#zF&xXkV zB?a@VLSO;W3?ce$!iv1%TFUj#Rx$~)PWJSZOpBi`vdJyAdsl*~2$VSb^SL|yB$uit z0!`Y>`05Z{fKGj}Kl-OZ8y{ZLwMq9mS9%sSdJD@6>DUiOf2tB%0s~ zH^s`9dP$ZEd8xQ=Lm@0ia~5~ssP$9EbifyuQeAQgi*x(l0;kTLl_6YIlQ7wRe(EP3 z6joyQcLQ^=j45AvdUC;S&JrLm% z%2e8WfqkJ}vws~$<*anyW+_O?PKFycE8Rg{{t{mAd_46e^-Sim!e#J@R2LQ)G8}C~ zqTl``^*aCc)7ez)aVd3qMlU`I4|>gYCX5bapE~zm{<-V3rmlkWyzJ) zhgd_aF9<8aWppQ!kxC{Dg}0n~JM}vAqr63k^4+MuHvW_9`+pD~^0#}bI8v?5U~`g% z%tIb;llB*5QEA~K6J;dubCj6~B{NNN7KESN&^_%Qi%a9h zg1{RkQE6lRh@u6;K~Bg?!;Z3IMVm}SarG@sjh+Q**sf3rTT&uy?Ax_oBC0s;>HmkU z15#coPAi~55jOpRuovgv#)je80cmYmMw;u0r@~4xFfG}Wm|79?#;CL?mI9}J*#uZ- zq#bvmcDBIndjJ!B;iGA%2;MSU1dyF&^`x{CR+Q2KbxVjZpG?Eff>IO?3sa3lW$sgH zlejU)CO#qiXj*5n`v7Xu_H}797-1V6s&9E{R@xt|6%{)c_CBKSAm*LhbJCvWK3a6{ zBd#9AJaOvTG`xVRBxp%1o93sPn9LUD=*?Tscs}hujy_uHnP;WD2)CEgP7@QWrNrVb zX|BTkg=FVMPQjd!`^8scFYVuPfy!qNIX&&6fCWOMuA2y_Q zVFb;xq%x7MJB&=8xiJk}r%I`oSh@POG`#Mm5VlYRnX9OH2a{>grZi{9+6El3ZqmH@ zKVnEAP?srI|CQcT{`-bSzW;+2?nf}~57?H5&1=Pgd=Gv&qId*;{$_g`P8t6n&clw> z2FS;DTC7HMC}|Fat2lN$(O z|8y_W{Wy|cKuY?1#95F8ggAH{QCgdq-kwwV@RIZ;vBdA@Q|ZN;Xh$I0up{X{0-_<$ z%};j{74wtr#o&*i*6~^Ce%u=<#%=_b2jNFgTBw>%;yl~=`t$>w^%g9HP{a-hZ;96l zZWFz9ekJ`|&JXzONjYXqI*xuS)o$%d_w}H^JdUKl!;L>Zp1y!PBFjDZaczwJ>RdWb zVJpR9xk_34W%@NAA}jtgeFX>m__&NpG0inY)8&azYdh{9mGQpD35rS}cW|izs!DMv zF2g}S8=mnM(M!;Wu?eRus{reRTU&d3il5FQJi7MI=+89>99Ah#ZpmNa_pxb-&pA6^;k*c%{$FA;bVoE5+5XYh6Ue*GRl) z-|yq*MTnZ>z7xg0uhDqYXMMhUg!%<6vw*PV6p-np>$1Kdaw#w|EOUye|EeECnQL2DN3a?tOXtz2`mK4Zac z3j@N&E$HnmwqC&(M0@qi+QBBk)SoVZa1yb9fN6YD)=xAtn=L9p8!Un+W;)7|rYxK= zMwb#~-*V|@m0qIVWSc;6iMu@dL>AubQ8KFemO!6Q$->U40^#+iWMX!7YF4Bc0oHmO z;n_h1{#hF)(x+wJrS=r(MGs};ovZ0toSkU$FMlZ84FfgHRlYnut8OHAwPaAT8dCRv<*}pJPiYNsW z8GmE>{Og$PY-X&)lMwG~riCbxa@dpE%XxlOKLvg|h>ANHvpr{ICviKgZRGL=**Nd2 zOm360;vYoHFVANWVUJmCbB>zPCLgJSW*y~Y%d)qJ5yBQwR;-Bn7s+MP-fVpCM0J6& zqZyNE*B{Kj#gm_<3taJd7b)WWvFtbgOMrswF4&#?AiJ2S8Eg?mQ!^^RKfepdP5(B# zFZXr$r|d}Pp_U?j+vPY(pP#dL@H9?70t}1u-?QIk{jIR&IO#JwpVXw z&t=0>*$bHW@-t>{`9_Ka}GgSiKuOoGB+uQ)mS#I~u31*Z2rrsC(xpNLr=ay;@ zn<$-ga8+~f97l2d9#qZml5>)U_B;Dha9f@mx*s6jxQ|@W`QU!s(ScJmO)j&SL)kIo|TU z%A8HS0RY2x-Ut{EOR~vx_vg6Doe$^S$FP8@IpJimys0_tG8D)sY|ehNx~!O=6TS`pa#ba?bKka1It*9L;|6;EtTJ98Ripaof@CD{ExV+YF<2MNVi}dLU;X zI|`l+6sw%f7;TL?i&&~7hgmBLq|w?eSd2ZA^Cqbcc(BNPFK4m!m;B?s9G7NIV_o3Q zZpU)=^HiY-WQWglUSd6o{=uT;GKDm;!#n$4bt2yx;&BX1`A95aN zan;X_i+;-C2q50&Zs`84-*PV6TFAYBJdx;ko=iVfCSYrB%hw5{E#rUPUF7llv zxl>sNWL&%}crw=sAEz?w<(#Ft_cH>oQQ8p5W*yBQvd{8dZ^kNq68tpBU|Qli0woY` zu3eDdUMxD9>nJk3%>m-AleweC_bYRsBT10M{Kd&#xo%>mH^%krt8(>hKSWsoQ~m6X zWYb}7u0Lm&kKWAF5Pf|hMAi1(!JJ(bD+yL<%m6EHZYN`8?oaG;?46JnuCi}qt}}bV zvTcIbw)W+*pmO5TTy0rt6XTRG#Q5uj+$Y%G*e>;#uv8FRfJScA4e%iLsEoPG}d zE*Ce3S+QUIn5%8r5q8P1xr=RBaiBB!)&7?Iax<7`7r>Hk<{q@dVrBSWx%23!1eZ(n z*X|{GIks-apst{Dv(Ia$i`b@MX-;`~p~))GkFI%-H~YERGw)EdpLITYFYr%Gpm!2? z0?aP5%s;Q09c0^pymySk%^l^7=De3U zW5X!{;<-?B7xCzbyc5(+MYyaPnRktYn*zRD7-oT~WAn6%hnnmimuKSipe!z<9?fge zcsAwXb>&C%9FSk~Cb1^e_XIuqUNJKd57Crhbh$#noV=~{3wv4qVvpYJF5C<-?43Dz z!`Vcb_X6eA<$3FQ;SWw*X(&qQ`6&-d>j0D(fOA+VT2svq$B3JBIPV763!u=+=Pu+4 z9&sd;J_15jUCP57p-LzvhTL!^uZHB7aL5d{1I!rcF{#;QooFo~+x?6NuRw9C2}<|5 zo!7v#vzkTaUv2Z}a`8{BS9#|1hPqG`@|lkLI0UXbrk{Bs`Qf}5L1y=lgxMQ<S02uHlZKr9&v+4QNuF-P9A)k*Gi&p4_Cj?=IqCBFd>8Tj zn0#khH!S}f_7kPy>40&>VhRWl)b7D(#K_5U`M(oACCV?x=l{e;qX0nPlDS(%@e~t# zU`F})$$YK)L$nh+SA}qqi)Q3!aNMgpLUeg9-%H+_osaJjC>g2mpy%@4#FH^*e;GY5 z{}V<~(SgSN5JJ5_=r1ut;FUW?h5->pe;}WB7Egbk@8r|#p$Yd-7~j%$yl}yb#`f~S zlKhp-8EZa&;qqcW&iOCN?;xLBntvb5_tC5Q-NmUmOvPa@=5Hp4Nx&BOY|&E}`b8zV zVl2SeS?>Qle=dgz)+hdQ$d~!+IcQt96KLlu<9^D&!dP$*6?=P{-DUP4`L3Ep0F#g2 z$iF&*IzsX1FUA}Dar{8t0J+N8Zx$D7^s~=H{eEUr)D8YJcYMDLt}Ma5vs^v1-*R?y zg=;~8teD&Hu$~x`ccZuT>%-n9+SyzCo#YTvb*LP-x8J9%6-D)+#(qDt?{VZKKm;bC zj2nNnUoD3rQG9)=A6}kR9wLh4SNh?N4fRt|NW)kCHgUS5pVxlvH&Siu88HO2CKI9CR)E`TQq8XNiM)b5jsz?`NeVA z5T2qm4Q0s6(t;$WP;$$kD{<2_v8Ta-pPj|MG~~HlV?kF&sPGU#bQERj=<>xu1^7g- z5>gHO`k4@AT{?Qq9a*rJ;Z*o+dm4z$3`C~Sn1UKcV3Dec0)&s)GO^%8Th~fkA`lH3 zV7Kexf@y3E8@uZnW;Z!zQbAi5%%ZZV6q5`7)e?iMl+bq)H&G()nOX2^OB;F0kLDIM za0~d+AhvHPXfM|+EV$B2u`_)j$&O_O=ebC?NuuiuNg6j4;Hads1T9O*U0=RlfFlkH zW_6c@yI!(&CV$*j;LT(z;DjmD+)4J>TTsZ_YDTpeuVrFsvia=-+^?>#7|6u-?|XG)Yk9~XDyVQuN# zT`cQw4i%4{D}ILrR%%M9sqNERwsY-e(HF(XxCb>UiXNAWLx_M1pw-_L2guo%ijT5g ztuQfuAY^#<%i`NiN(B%aN49Dw|NXwWmID<*6d=r1C?971UVM*DG3Q2cDs}eGjpAJT z!|7)61@(vg{$_Cq+s5S|uvKw@Sn`&|{}iWlpSV{rSiXL@_y;ZPW)ymh9!DzO#Lq^I z!^ZX{!CYd~eSuBimAHrm6AEkJpb|bcqVlw_2na6ulDMO;_7+FqF2M`(AthgP;iS3{ z;Ta_#QH$aG%YtQ>-X)z`cw8A6EKb!Rt=!+IWCg=6U#$!l6~!g?t%3|~L&dOKvxm4Z zv*b6$O?B4MmmDW5Osn4Y z_mz5xy9&J3tWsP_Nebs>+=$7t$P)uf)-sIb3x2u8!FFY;>Ro9j8i$lP$)n~H+)V+P zgha2BQgpRCBz2Qxhn4)!w%0oDC{_)|mf7l&CBiz-;+~%XI04-729AV=n#kw zMu;mz%}%oa+!9>js1uXHh&VGo!fY>{_m}+0OFV*L3ZDZxASO1%Ximi)s*kFFwZ zI8##d{~RJNjKcVfJzJs`x~)Ws8jbO>;e5$_4i>A=#Prcv8;!hD@)#p5F)2w}lyP>QRiTfoGry`@faT=!C~%)x9&?CKvxpiYS?eV<3R zg@>;g^q{%3oK;x*3s~0uCy-QI(hzOs)n%m@xH~nTsV9K!#n5pG+gmG2zhmAiZ1=1# z)fOY#NcI)Z<1x;@SW{Zftt`pWMe&j5b*0z1H;cY<(o3ayA+EXYy~Vbjr9N`sR*UT| zM)sCK;0xm|8=szl4S=(IOYtRLg`lr7+}U4>7x8Dtw4`lDWOu z99hOJlphqxUaWh>93=maEPH^&lcQtH+_?#!mHEo~DP_r=)abflj6ZzhWfF4ox|A|k zG4#6{hdq7EzSmM=c?I$8B!i2}@D&*)z2*g6X*&r~w6U~oG1qS`xY^60gUV{zJo|^0 zarud|0O{&kthUezj*rYmKwPHRYflVA;xB#+v*zQVnK6^;y}ned#7 z>T}8$W!mEpnp}YRfy7s%PBrrr7p7wUsr#}_+iF69X5b~$GQ35l)TE#O-}Qwn z%Z|`b39MH7SVpFsVv1vD-@{*x(~xC+eufc^5~%ct@5K&Co#f2F%$0tRVf{8)TV8eBH z=kl8@o3*h*xXCL)<+xx?^$Vd5!eu6$@JdMeNN#LR+k#k4>{jk5lf%okii4(F$f6w* zrLn3+6Z%IMFCT(S#!+n(n5ECbP zXH|K(e3Fc8PCE9P2g{87s(jT$3L&B7k30hLS2yWfRdF_hD9C+8QTD9z{|gm^*aY+? zgcVCG=COlpacpVqEUR9uz)fw+rT-7xX=O!w(#n=EETm52^m7;j16EfgjwgEZ0R(W8 z`K#efCjv**#unR=@b#8Yk-mEHN#t#uU1e|A?EGkr{BrCyBR zTggQMO%P`mBkCtEfvoO(DjkH}TS;plHP-a<^jnqM6Lc&*aT;cSWjOVRBmo^1W%>R} zC%J5Yr577qWd@1N(1U+A8=Th0T@G0qLz*};4koz_CQ!YKOH0i`LicXvK#}xLV`s zJP*e2o~-dm+Vcq`&}+YgmXINe&NH8(NwR%QE^OHw(hsZyIXY>KI7GX3|;jyx!7 zUIQ$Q+2MOP*q6LpiF-y={8QhGLM&bZpQ z`+vY(GQ9h9Aw%pM!uz|(wch>Pc>L!bj%+c*yMLfO8QNcaylJ%)h>phH!KQ@B%Gz&Z%s8q5YAQv1*5gl4T-B$}M#dBzeBZX&qB+3#V-~VBDJyBe}+J7=dEK$fMUISj_ zBtY2VnFBt`w$h444Q9uUkIWpv1qZd*^z48JI>o6TKY4FNNyv7k{u|b#|Aun|9^ff} z2r~a1(8tz9?ui_@lPf<n7KAwY*1(-gO*!-Jfw3)-4&urySfX4% zFtCifu-0P|q?6gJR=$wd1Z-2`hvgd}g3_ z`oYRxQMlpVw}H4Sg#usg8-3_ms5kK6fyIoq=}qDtdL33d+qR02(Ahfk+=R}~+E?vhD$8gj zp9{~;SVi5p2~K{`rK&HBZnX|!Wt@A}EJmn0NWz}QlqFOT66$cxBfYv*dC@4b^o(kC z3np1}SXC!Zj@ICjDuWQ9CXg^w;$P^e7o`9PJI41B1{!R8ojoVh4?2U$9y z>RXo?``m@hR3l5 zR=yok{O{vcXPJkJarwhjRYkOUrDj=Q(KNKJ*4T9i%=W~>s>7U&gH~1JhO<4$+>@7A z&ErHwwfDA-MlXfvDs$FV<+F>dtmO9fRrn~C(ijV0+~2Llc>YZ^zPhn$Lo)<1IQmA_ z!Mb^M*h7kWqWa6xQRZcd$G$WhY zrur<$2g#$-@HOj0?u@E7X;IZeDsk#9 zbY2oy{UrC%O6Gs#t1sCCR5tah&f}jciPdS;&tr+zMgN(YlSE~Hb&_;Qs!roEl9OM3 zTs2=BFi0;dR#!WSw0_kbzlfPg@!WoMs9f5wT3ZKOr0}4&a&S?#7g^PNH&!mIs7`P9A6bgT4r6tOn0^pm?=i4iTL4k{bf*FXA@dL_w;znvK4cz=J*W5C zzUtF-^1_hnZR|8SJXXXE!l$`T9YslXenfS5es+cIpcji9%?4RAxw;LxUZOFd7?tib ztJg7u)d$gT`#a{K`gcHodrmb!u9GkTzr%+GRIF%RQtcVq^9 z4mG50g9ifm%iS+muVQs>`9mGRTtx6Oa|coPzS%=`eIJ8%)5dDttfpuwU>9$$eut_S zsFx>Keo;M=kb5py-{c-F8OE>veU!zEk73J-EZpbI>Um+r2NsG|y#z{Md!zPv$pXX8 z_KwDF%n3tY6Y2M3=3rUrV%*FK_MN-&Cl(8akuZ$*96n;KF;X=789R%jGbd8W)* z%wk|3+Ci+%c3jZ4pckB6zT|z3`|uI*J7|jQC>9K%=%?qGdrH ztiWSfwUcO<&+f+Hj8wEQ zr}*xG@fCt&P2nrHY(bKp_?fx0IDXK0l;BSsZJRDmA2RaXfakkd07n za^C1=dWC0U!cGY=t2ZZuB0VBafp&KPW{GY+Oc}v;gUyAW4~@w? z*B&=eIN8|+HM@wy&Tdrv(vRYU#n6ssS6$x7s={MCo~b+LVrO^H$Ii~TMawzjbPtn0 z7_t-&N`C3tD`5AQqn#akYW8nQ_R_oAI$|gK#F&EG?&~Lp#F%2}{t~4^>eeDVyVAUY zSv?BN^6^BpOljmLuxge5*28O_ z2J#L3_iogtzmwzHe?$ouG2PzWHE5KE z96oXQ$OlIMr%m~vwO!jR6lY>hp?n3)P*c~o2hAennYIBUCeFlH17*YkdebZ_C$;Ii z^yxu9;`P2JR}%Hd^s~!0L&QJuKdyzSgGW$vaXQWvrc+uquKDYk^0sz%Gwki``m|_z zpYVz|l~Vu1)!GcjlDH)R~0wMw;8keZI5W>$!5lFaovfbg*IR8V;Sxx znB2ruy)+X(+Y1Z>_ghh};$$xqe+QsRp}gO*p_XoZ$4?X|Xrk060DbQhE80!0OE4M8 z`a75AEL!YfXE)T{&Mvuy5WT*&wvQykMkj(xw_galbo(zMO4asa!U3}*acWN7Qk_q( zi5-ciUexMPep2uzPdmFo5q5T&%}MM!U00kVL{yR~g1mj|&gajSbhfh-S*@GKh=-F* z<;2f0b(wcHWbdW3v+LJ_-w&PfHF{H3hzguhF>Onez3l9s!Jx@&(Q0S6HX@{Zn|zz! zHYc09wi}$*W@*;-2+@>m3Mb_|rvSRvWQF>O1(Vt|i=F2ce*X~0f0APAMpSndv~)N_ zb5b?v_*6h&8^O@tBip!&L#djlPAOE;eF_yWrl*;FY{8qJ2Glo?T2VcyhiwY_(-RDx z_GB9`QIKbHCHt+OyzS)ijxft0JG-J>Bxy{gg=!Ir=EOX#HE|U#jr)#ESOlJ z$#PMl4sKE?gQ(ctrjr;ty@px$>tEw{%+=0rZ+vUkWnyTC#(HxG=%; zM@Bu;#}q}~G$?2%XNInIZtEwm_tCn^+5uFC8>1R~w{;SI`)cE?v@cLk*-(yRVP8`> ziZ;>alk$Xic6O^VV)9#b|rR#Z1}HCJ=ob%k12X+?R9v^-N6 zGS2sDNB{T%>MU&2Ix2^oxIG;0C`6vgKo&Zb2Ua_36iQ#8ZwjSRvu4-Yd%q&Iy#ws* z5Z%rGJuR~GO_|iwiZ>rxJ{z;|V+pMd_`ySpT|V*u2_f8e*9-;dAKiIG%d>e z0rlQYg$fgk`f2mq!J0ishQPaR;oX+=Tb}r+pEkdR6oAxYp(53Z!38G1%Wk@YCaq@Z zz5-Jk$@z@;r)`5#&^*+s_1wC7owcbOg^yT8uucfZ~?Qrx|) zsd1tZy{2wqREHu{SK{(!P@kv{9qjBrM4m^QZ}#u2J*sJd7*d2HO{JeHplRFZpn`T4 z?;mU%B+e9Ryss$Ky+%g)VHH3G<*RDCw%H;|i%on1^7vx3`uu&dw#1|t+ln>Xg9_UD zsDkzsZY3HtpajtS37RA(l$iJ;!x;+t*{7;)33c%+0PS|3Z7V{~;m}2Jsfll)>w!Y4 z-PZtDo@*N_#+7PJseZyaNV|~}#{H)@+6o%ecnvvj@}mzw)VfKFD!{FosqF0PThNUh z)0$L-ltJ>t=fsX`leb5!I#CQ$$R%`c)JrOWO1WZ1h0`e9@p$x>IAo|sgi*_CJV6|;F!9{?nd9!t<(8n7H~L?)&_*Qj4-XmEgSgJLVkpecLEe z_g)QZooyz*q;N?abJsS@#Ekx0CV9O-x;v(RcNUlXn_|fxo&&(-qo0^b<^ZgRRK!1| zpy|I@p?K@|m$v?*VHRqs#ZygOOO3fPYrp}By99}#g>$h0`<>-vb{w z5S*WCvf=B0Yuia&pQ_c_{T7$5i386{Z!C*S?eMkBTi)Z7_=vlgN92chb#G{bbM zLLYOiKo?O}Ws0Rh`E_^9(j8!HKo?0Z*iXJ;;o&0M-^2`X=65YDepcL`ziC5v{cC$&C!?=hP^VXm{tggD7Fm1Rr$`q7e}J=ioeBh6ZRi27`58qMe;Mj=x2=yT z-B!bkkYNM-=bwejgE25dRhQO(6YjFCQ)^6}slyw4E}ohI^bGv(W^JbaSk^{(4Kj5S zCu+3y!?hZ8SksoF7u&Y;7pb*c*aVOE$O*zo3_^!3Lvdz1ZvRxRHV3V#1(!b^7<#5w zn^5oje$t$K=yVH=(~?21@G_f{$l66_kiO__C3O%p%_jbCZi7PY@=&O*BEz$tn}`a~ z%FvYw)%Vn7|1RWfY0}=pbC72Du+yLUeS-eI(XhMH-ue%BQIZ*+8l;818rE$Ke1z99 zlmCALu7~gU*Mh)fD6Ai2<)QwV$`rzXuogRg2P;GP5+CtYr*^p83q>_K<>jD*Z-;?P z5V*7)h5rU{`ws_e(ljY9lYjPT$QYuHjN&0c-3n$@-4GKm(B4qcu6l+x=wYer z7J|D9H8Y%1juGvs;BGHgudm^RR;d>4>$@p@SMlsnP1qxqCr5RHuqtJ=RQWTl>6xLX z5E=rHym4%u8UhYz-ZH@!3D05LieM19w|y*1^%5@D4Kwj4S`I1b>1gh|=(Y#8b%$${ z!VrMox&6l}``3luO+%MGAz{B3PI<2xnJ~t-!!tRg9rA(Ss6wAw5cwc% zdbc2&6ld)#Q@|4z4kXGp_refy!u2&~nJykBj zr6%?k@fELDybCEPFK77W$R-n&6BOGAP(;H){PwIg(vIE3N@B0e}crnrEq!+HM||w7#kQf_k7w}6|_0f7*a+$zbk4^-(--eHDM5H zZQGSYuXPn-GA^%ttNuzu*&FyH*SaH)(}&0F)_Q(jkJoEJTLCr818Gq_r>`|w3?yYR zYMt4QLucb3%#t=!X#d_EdUvp@922AKdhafu(5vl@ODCD{Apc3tt7~73@?|SUR2(@3 zT-*k7)XIUnExPtyy<|Tmq`H*z)sqKt`ZGgRPE3|U%4I4xfN2HxiNa@vB?3Bj2#01S zVuPT6qVVDqD5_zi2E}I#(|@mi7=+r!;g777-lRBDRgKj}gHQv%Bm>fIxPkj`Yn-H^ z2)pCS+@Y#SMtvFoHh43PQCA^eNx~n8B>}vDIA=lzB#A`zdik zIARoL?|Q=orlZ+DFPKvuTTHu}!Q-v^@*lP0S7z5({(7>Lw94ymIj*Jh4*`~T_7kyRsAv8?&UBO!(34qm?5C>8(YK-?%m_wM1) zJtfd{6nb<&hkE}Z#0nggweKeU;dCTr6@5)b=JGNnbF;)?!S^xtkNm zD5*c`lx<)|4qFQq>5WE(Zn+fYN60ea_T%2JXfq!i%0ds`Fi!0+AfJ+!BeO@V%Co%k z%MP#4bwq{ZptcY#9sXAK0qa@^a%(hSBc_c(hwmoK!14qdSq{w7Rn?ifns zM@+|{0V*PbiZ{vNTy;Dt9ItZzEpoee`Oe-&CS}SzC|`Od){mDUuf~`4(yoh{H7y?p zj@_p-judY~UQaK}*SHM-lj3{N)WO#sFNSr(c%UxL;ZWm!+HRE&w^z$#@MVN~9Lh006OGGz4xRYNwqa_4s5_8q$0 zhT3XNx?8uIb9S330)$o*QJ?Wn4xPIb_0dH*H(Hj1(p6fse_+?s;q++A2|v5L1#HW zVlsl>nUh40H-n;%+|fZjnR5q{qojv2Zq^0j7nr& zb$)-jlFBnNaxVKD;-s~kp(B%u^-4SY@LalZsfnJE3#}oAlU0paub8Z~c-a_4E+CRU zMk_BJ&Ud{G?HFfP$fb|E`B#WD6x}H&5sH0u3Qh1e)KOy56lkKgzXtEE)nCk1pmqgv zRLZHchNM;nLl0_Xywi75{LEmA_ax>W1@tS0o)FMBAt;ddrwEGP>zhvM1YM26IIXLr zEv%G7IhR$_#1_fLY2Y%Y3Wr)(H4N2qu^rmcEC5`5!9`yERjkhG_fCh7`_<`Nv3Dcs~e3f-^bQ0G}<6t|oOXx%OxdZvqEkhUSmDC%n*M}3_o zwzs@y1NtJJL%Yrv%qLMOvh}RwAYV{9D|O$JeQiRr=3oN4@Al^^3* zbaReh6Ob+gsXSG8!lTWq7^cJGxe(oGCodW@PvkC?d4OhRacI3=hHm88Suu^U<+N%K zMLC4^Ph@Fu-Av%t^JIE5x_Sp{t|SRKn-?NBhYih1gZX0l89yIYb>GMMX;3C)$#F6N z_uII@EE+!YHMTEgM>_wIrjWNbrE`ZkE(k=6L(NMoC?c2Bw>f8sgDkm*p5#F~(!3cp zMH)Fd6_T7hsUb2X(WeYuN)g?mM0sa5MBb(F5etA1zo5aF#U&~nLZQK4&s`g=9zrYg zF@oh})A2kV`U?xh99c|R{k+Oi#djgJ|6jrkTmA*qo*O!-iGPV&?$r2q-wD(*9JR>$ zPrR$4cP%Bg-a_!3SHSVs_YGZ1tA)Y?bfu`kLJi7+94Ul%%PzrRqWDLTIR4i{G2nL$ z?p^;hq?iIJ~=6@zIKfjpmsIVyaKDv;z8k*xVnQP**{f;J1NCai)Q2Ra&?!n&^@R+DGQ%*vVy zoXEk2A_i~NW$1sSAW%7IP`0`9H8}l>8b(emzs%GYz7(}Ssm)OX>lnF^@M}WWxfC_2 zF-I9TF+xaIGJKe5sq^z}8=@*YSY<69Y{m=KYi@*07Yv8dCr|o1Bo+$IvoEdCF43I+ zezcJ*qh}p(X>_IWRxqhZG+#DsW0Jc}RhP=2wj44JRq^80maDv3O&PU{hxbBAQOl}y z$!7_ibZ~d0@}-)y_|%N0=itXiqe*gqZ|cJfh4h7Z8ui$&K-HJ~X;7vlc7;e?^rxtU z12`&ug-DHMQ|P*Z99m(Jk(*Wk))gM)qa@;sP zNkh*wb}Wg0a0G=q5U-UY``JGD)XRRb(I2*@b8j!Tq-9CJl`40p!S;JB?=6J}`(jTt zKr;R<<20j#mIrz8Z9YKjAn>wJT(Jc zx-8UiF(dPdkp;P#A!_+b@nwmOcOucNg{x#~`&Da%fNPCREv3VPWc6y4zoEq&llZkp zj^tHI`5zQtuu)Uqm{eaQ@;PnS0M&b|4(jDrBXe?gau+_B<~}P}Q5VfzihxP(Ak%|7 zh3=N{V~fG1M@jBF?2%SlD;iLDEo!+Wpii=mEXl;R!X2%msP5Uk08sX9--oGrR+>xd zU>HXi)Ghn^qbEcK>%^4Sb{)7(Jx8G~#QZ!e=(<$R4>28BWq17#bk-)cB2emb6Oyw| zY)pNj<^Rd!<-^wt<;1K9H1j5}>&1Gc(^sumIWXDo1y{5j1FrvIq{xA!L%xQdZxDNI z0GAI19GZL|<8kN)p_hpiW&Tiu!ix(VRCdfO?e3qQ(+O_E2bIW*Ur63;Q1Nft2W>>Q zp`ME|(Q`H~Pr7Xs83MMc*{L$g-Hde6){UaFLm<|lA)qfeiX)^i!hPCQMIF7+sNgHEp~w5(bKH6(M@#%3g`mGE zU~|FPm`vEFa$r1%s%8a#0WIC8mFKEeBx@U=t4J}#(0@08i<3Oi*qo>;iMg?7<9*jd zXnFLuEE7&NG4aQ47h0uz>iR7bd6!;DG`1v`9aUyb33*L7^qmc<9nm_uU#Dy7&56TM zV;}9(>ukrW!}3veC5#w(Zb?bfRANq2cZl$9`2y_H9v{I`FLnt1N2c$*H5>|Uj>)~5 zr2k)9QZq7Vq;XKG!yL?sJ{iyXZQrS~Ws_mqXjwgDaph(}} z(%z{^%jw5+B)OcWs?2mhZ2f?mD-ds_l@0-)t;lm_lf>$y$?`N zCk@nyEZQfIC}dGos53_u?-OTb%=QDi*i{2HB(eKNPTM}^b7EgiUKMeFK(>_v4@%Ed zhPI2t|9%a*5B(woe$5zuWie&oR8-`jjctSQ=jQ$H|4tk&Gk4C=VV1)1uirc$=nT0+OJ1NAZn2pv*#wv zrVheqdDRwXh9`N^`Xqk?Y_R}bvLr{Z9jrDV9Z^9?NL-i+poMVWHPF!McN&)i2J0$w=n+7f z=X3~}Lu@c(wTC6k4BA)cq;|Q2w5Rc@zb2!uO25^0uofrn2U2FI6LL}4f(Q;h1}HPr z-a9OkwtzwJ-xw?<#ks1QtZ2o*QFLh(FFN3F!7znFGa7Sf4xmi<+&f%UHDYI``J=WHPZ4O2ZCJ%;KQg~h*%ddC= z{EK%}{(dB3tDX_N*TVWN1t^0H&CN;Wd1kmR+QuArRxYRBy&eH-d}COTF_v^p|-725#1t}*9iU6 zv<0lm=QMMCjW4#RDj@2R?`ep zd_^p!!mh%IoH3VPK{{iVnS}?bs4ph8mzy>PPshEh7Kk-{B}18Pr=d5(O>!||=1myb zcOgdDa?}|h(JTI({=UD3HJRU5+(T@XSU>bn82EX=(i3K6MNU8Xn&_l?*C3@wT@F0~ zC~IJpQ`n8g=%X#DRG#m;6TN@L92D^nipDhJMU(y!XUu0ZC?*yF$faf$W~A;LA(p9U z#+A0<+6i1`6+dlG=~=pzgkJ~S#nBWHM1o^1yvWz{Lhoy@soSbCx;ML)4%63?-0P|c zHbQ^V@}1RGEC&*PL-;h8OI{X(P;U#UP(GpApc^O6>1I)hjK3+;{O#*C9=#E=o+_4`}KZ2c=c2C$2|-e+57qQ)iAXq18)jt&$$WFhV;`x<=s?OWg1^t-)+M% zu$hWFW#?r^yl<(ZSbcNvz3gV-#BcUimFysYln&FxKVS^>2n#D@e0IZhm)S6eih8A@ zr^vaQLU;(KnFu@GZ)1F9mAB;n0a~#o-ENC+<14x5AA`LX|4$9{*q2>Kacm+Qr5GhX?i7m^p#%)+KVyV2ZN2s31R z`B{%lDo}ZoRZXqT$?JO}1b#8I<-<16;bsH{^45WEQw_Z>F>w=Cb9uJWm&2WKRwTFd z*}LqPl)fsH!mQsK{ey61foO>ACoZn0RPLnn8Y@ffy2bK7+LFJAq8v$s`(o)hfI?3m zC58793U0qI@>OT1mz~_I2?Bxxr30yW^5DLRBHbRKsDTN|dVqru^G&QPk+`|SYW7~8 zF{BWq=>~KyJK1!S`9M{LSuH#DlxIWBJCHWE)+WTGP@H-SF2vC$L!yWOBXex6t%<6k zm_bqi(x2|2DP%+}9j)!i*+PM5r!iukIX)rW+MFH9U}yFQYq-B$(p9IB&y3o%(0?e@SSoZqP%dOdW<3&{ z9fux4oJJLO@Oc%jor(2-La`qI0dH1G2e1B5xYlHfx*w)Ng=ri4oT3UVYf$E7a20DV zDzkw$kAYWJJ)Qbktj;%6)Gw6=?r>Hsqa#VPcxSe2|({AcVxVN$J=CZr;drYEUsLGSgkF8zEmM5a_+#+xp{feS0 z_~l*^b$S!{T1|JWng2j75)vyUv<&o z%}Mx6aiZ>Tb&;hW#7ux*SzEbPog=gdyI`QiCHfqp9JTYU5b!>Q=5*oE*siERbFr}XJD^OvbJW~-s;bNs*r3ku zMWK$Nzn>#Y*V}N`0a97PrsNEwb#GRN)Os&ArDpovJvR%akA5Rf8Nf*wgOpX8^B$t~ z9m=84hT5>>JA6p7o$`jGsFgT`4;Vc9x06k=w`v}&fNHFvCwb+J940MAW{tD)XQ?+< z*Od>n*~lXZR5*LQgrTB70`+P+&bZXD+faA`L#3yr1w1RkaqV%YWLGCo}enxVu%0%rd=Em4caD_EaGx z_mip#6V>!H%6~vIgH{dJZlu#^aYSw$MTH?vAyAkmKMR2hDC%UI24zHI2&4}GBJd5q z0DpK1#}EA?&My6@D!BC=R(k~NLVw8;3s!PcG{BH}eZ{e@D__LC@tm@9-7MqzGa+5CO=KtB?ft4T7OL1FqoNe`YuxpUbN-Y~%hCJ2OQs?wqA- z$9R~IoM-CZm`O;+{SrQU>n|9~Y}^5Z+>7fgM&!val?U^hmu^1ZQLzJ_dOBEo;S|}r zgq%I^v$#7pT#v6Uf#I$5b+-14GkK1Evds){G`+ZPRWkkt=l7+25%NYcmvqg5nNX!;} z@~hTd19~&`N`OS~c9GNPlvOOrNdtu^Uhf*9R=X=YsEjMN)?_pePBXm^pYg^a6O9dm zmBU_iej~1G3fYmdWflHv)cmsGH}1Ly#r=8_g${n8fm)CXhN3_{L!g4ok=4eE6B%l# zc(H2t4sUK~1sjb{hy1-bED979dm?J_qA>5y%{rSF(IglgywiKmgm&mQH@ zn>^+ttot_7Co=!Jc+`c8VpGS?j*Np^S?A0)f|NHKbJQ^-g`a@9N1-vzMFC@lzp_!; z7|`pjDHM-)w6QZM%MdBELDh8QxpQ7{>GU{?JgBOZ3}c0-HV!==vU#~rnKCnmmG1Jr z9f+QZ!Vj&~HbE`x|KN2GGEw-GXz3I>Wju#oHc|N7D$b^W+D_C!-N~Jj$73c?)C;_= zLff1;)sCAI6Sn9^jd$%ZZf8PIvW~DdWh%r7GDGn0glkwqQ8>KC z+ChaSb&uMakp~tEKiO2>YJ2a0Fb3TawabZ~T}R|XHY_{DtgMYCnBG63gP&!o@VkAv z6xHyY4(h@=J7*GZA;!JCcclL*bk-ked1Xo2ee-k*#aSu*&ATQJuFWcFud zKRWbBtQ7uaPJtEbx4Wf-T5-!RfYr}LZ)FYq)qIXmu~tGDbSH&&F4RCxNs+ZsyR{8a z;ZJlJ9(p1g#EK?S{M#2g_;D|F8~k~yYojF?N@LInxtq;C=oGTF74=oN1-~+%G$<1? z$W}P?$+q>pv*6zzB7r2QZnl5d&^u_m=^16UN1y09Dek1cfjw?USc%zrSo>aIYr@{o zAT=p>dwbH|PT}uXt+Ye=e{FdA!M66i8)>W4?135Y#4&a36@KSmO`*@qap)p@g}0)MZ+ML$^8z<>gUm z?O+ZybyWCsH=a9puFZxgvoR{2`>$4olOC&LZ%1+*gpCeq_H<${^h_U@lb49G)iv}+ zq@X%9N)4NNp^IbwEv8rMJEEzW40L`;X-*2ybF*;gY(2`u>Hl4NFkCa$uK+ygRYy7F zjSL|zMCO*me=azQ<`z4lxh*1fP_@em=dLaXlu;uMstR*;y|cS6XoBg=0}{%sq1DkE zQl$Bu9E^xfdExIo%Y#*;c#hwmVDE_ccF}Up<6Sc;z9IrCDj@K#qmhnwF&svg zF7(V<;df_t#b@^DfT?q=QrgUGjg<@G6KXD^y@@W6z6yIo7Y5e6? z_V|Vul*TkYf38!=1GL=Zw|HdXn$jh`)}kcU8Dl@z73|Ni*AST!4>tv8d^gxTk&s3r z+^OAoOkX`j*AsDOL=JZ*Zj?*%C%Njlf$6P1I;c@@3V%^%NWBT?mq4*Kq1Z~2VompH z=xs^*K6?|=dcIhVyrlfTAJpLaHujqLK22IWaa!z)hz;*Gs2dGN{}-|HxOEAE#&s=o4CgD+1872CV9gI;VPer(!ktUKD$4k+^J%nP}`f{E=&Z{6)jrl-PPIJpB^ti6@87kT)KR3yJ+^A4KMQ3Ts&b zjDGSDUMSB~;dz!{6dGYf-uPln95Zt8BU=XwN6~Dz+1G8biVN_E@|gIGO!89ra`~(m z%CE83l*ikyHV*if18QZBeA#r*`ip4fK&*OXr@D!>^;Ydu7 z%dy8dlIy1gl6f%>mgLY-p@_#fBdX}zAQcHKlGlT&v81xU5<-sn3qwxV_j_&u&IHb1 z-Xr)F&q-6eIoOcrt%T7;2B0YeyK7J;DnO9F zOYL^BCz|~fHOpE4*JC+pbfEBA{qYz51LLSd0?4*N#fd2-(%zax!wgLVOHXtyNMWGD zZ_}QO8@4D21Nse|gFLZ)oXzx~m~Zymj**aaH*_y+ zC~pPP3sU%1%$OiB_yevr2&S_#Na4=w5QVC0RP>^YP) z?p(W{joLsIPefBek_`_3n<~SfYz`L7$YU@@eV6kLnie7^Ywr*MTV3R&UW%gw`6EQ( zPa`g%s9$+Hs3#!`zfI#FFPPxalTR zp&RdX3e^wAlw;6X9FS`MZO(I3M2jc9NGv>i=fJ=}B;yP)kf0*wnBR;QLmNT;wM#gPTb#=3y5W64oO1tBS>aTvf2>hu6OW4ktU~91TfkRl%p> z=HBnE&~c$&rJbW~oVI`+iLEN;75z=)v$|rC9K;~O2C>d>9%)-mjM5d=P-ENSg2C(I zj`nOQFr8Rb2X5>Lh6`nn(=za23a*jtNEWPc3L+Pi9gWH1>O%A9fYa|Yo+Q*#Dy2<8 zC+8)K@bT%KexJ4@%IN^V6R9H$lIJNU3jP9&tR2q4z=6eqnNWI;_a9pA1A&Sln8(r}W#*3pV-j0JiZ z+uga_8ndticB|yY!ihtaz9BPLyDjREH&OX@Oc1iO8cA|%DKSh*HnpLo{g;K3Vy`&b zva=e@B3#`T*WUu)nF4c`CnKk8qQEg)oZ4kR{fqx?0ZwpnG9p2Bgo}=>1Kf$by12P@ zM3A!uIQ=bU$fQW6BEn%5`&37`EsF@C&f+kxGP}IHLC}F@i2~$ zj6^ne?rd@z`zhY~{eQtZzlH0OJN(p6nX@UeY9J=`6{-eXX242l z##Z(m;W;{mhBgohfzA)B1bxJu^QvWO)rb78L;nc;nWnxpfF`Ei)}XvuWafD2UFBLt zuOT9{JNXpH=l#Is8CjFe%amE{U;66F$orHkoH#^@ffpVHzTJu_G>nXk616R$&>mko z^ygRIF8fANN54^2MV#R%XGEGe6y_1%5GeIe9n{u_BFg%!mT?k&+2AM!k=$GLtVr8N zh$!6~iHLGY#J%;WVURB|Tx9hhw4tOtqFmJobrm^LKo}`%#N|$F44^{=4$Q1jj$0bj zRGnju=SGst)uE~UAWBe?ylkSFk?|GFnP|OMzfO4@=qt(h5#7sPYifv2p(!=Qu#0Sh z3XkFCJPp5Y^`ViA5n`=pqaNKd9#-KDtB{@7U)WL*h5VWGns?R4juh60^Xf(_HxP|a!_q@#;PTRiOqwe$%vWCf5pbkDYBEJlFl?RQ8WPo9 zQJ5*GH%FtYWR+%;+*~myKbs4gGt2s&`xDjY!#B%TuoEA55b9tubH_QM1(>crFQZIJ zvkSrq*vOu}#l8MWbj3JKOfu7Z7j;TDXeqpL9R8wz^a@1Ihqw zy=LPAO6pG%oXaCmTTsrJm`4jw<`NB7;~r@6=A>`5!ryO8p(szB$q+@&$;D_9AiSWc zm@hi0+A$(CHsIFcIAi#}7VuONI*LZ9_f3a>U5ps$IVh-KO`k-yQmPQ^RtmqodZV!O zReGMX!Eau4Dv4~R@HfL2v_jEKCzxP2v`CJ>d`Ng3r4uv3nQg%Tr9$~PBrDW7erYpGgi(6#6Qiag zdl(7nn@D=?K)l+DDWcC?|GxD3>h>_EScxclJY^b1zKk!gv&xwFD{sp^XypvFBFAO{ z6DfUl_Q)j@P2CQn4VcfN+wc$O9ZbxIV+6HUob=l-pb85kuNRcJ(k^%{|2&x-Sq|Tq zX~YOw73iAIGY;I#$-ho;hDE~0W0fT8a)5(MA76yj?|3=VwA`o8bm60 zRrtql?7q%^)E#q4RpeKi>ePndrL~41o|lNn#e}W6)S(BjdHN|bz?(#^}!A4|*tVqtjrjO81 zw>|(rc4Xk%WM3cA`{yaxt%3mi^u@pEsydSXn}{ybO3O*#|d1U0SZ4AH->`WE)?LL0U~KvNWpO%w45x`HoEAnp{y>wi)zT$ zPzFmkxsa@_F4f4ofugEI15voqRtAn@ITqHE_-Mb;vG75=e~Slu9&{mB4!YDP69)+u z&Km?4<<2n{Rmpw&FWP%Q=wH^HcOjF8!fGOiA|uh@f{O_;E7?}+J{SabFX!(wQ}evU(j+k2-b{;$Y3`~M_*Ncudi^LI?iuA-dWUjX z3s#1tRCFmzVupzU+

    P3b^UA!N%iVOu#An%Rj$D-)~X3V&i{4XF`d3A1k>Y<0;h ziX~CQMPe>>IEp^*!;2OS7gq6&LgV^tpg6)eLb$x#3>T#z47N(u(viqgk}^W!SJA>V zJLK0#@6cB)bKUKds0~uYbHIZf=tI5Q6j8c^(jzYYeI#S_Rszdws z{`&x|r8<-^C%(^2)uF#NTKG-RQE1ASMH&=86}W;z)9|4cQGpYgl_e(l0bx(mf1-gS zF{8?JwONLS-hvGOL(pF}IR0uh+G-6;jFB2JCQFC@^cc}#v+t$_w8743u)I_lxSP^9 zB!5SgtSVeqKYIgFPQcdWWmJWIob={sky$wT^I*nY!~uOkDo-biiOm=>v!xmr6(&Jc z1+KHTBx>4i&W}pTf`K9RhC9}Sl-U?Bau_|8=#4Ge(;5pcRw$r78bVqZyPA;nu|n+! zDXPv(4a$-{cnQ4b6@?aqHYeCZ199j|**N#T=7kcIg#%xZ3|3V>YFHVQN9)95$g6el zt8LMszac4RYn>mS;g~cIJBm34sI}=h(JKA9xpyaEMX?;ydzcP2PT`W2aY}vW#&SWe z|I?OajmI+5a=fs+D$(RT-Cd%uY|Ca*3wN)^EA`2Q64G)-bvM^Q4f`9GUZTBqqNJT! zHRcmg&8lEtwq=MLpDS4e;y2@J`b~&A3~`cd<26G$eIW`nF25+3KWk8EJ)%q$Zeqwp zKto$`=o$Qju`L(-DVkc|WAv#!Di^jUg(*rc5|JV-@37gDcgEOV>Fibd!c^0CoV2K& zo6h<~-R890P^?eBV0|LrZOQIJ>G|E3&`A($X+O@Oet$Pd^1Nhg{(P4=^G#5plXvL= zK5n3f9&^ngH%qNA?z6bn*IuaA3+F`SweX`6nnIRj#$=(E^vS3{dy)?77a&ZJ?o)uW zn8Hy%=c8>YQ-m(QFPnAJ9HIq6w04rwT$-js|8LJ);+V5b~NsoO%pq- z&uFoJt2wm#bg`*=ZQAvWt{84{uzY#uy1#>yChv6PpQ>OgIXE3$RvqK0h-^1I?Ud~{ z>*<$6FwpK!r31D~Ig~z>_@)Z?IIZpF7gsSvE#V$9!R!2*;Re<$r4qUPrx;=xqpk+f zjZY^GF*%wZbB>bMCZ6ZrY)H%up|~zHAYe6QCI!lr9GW3k8MlvIx?c^^b&b%{v&z$3 z8hR5_ZKkk{7Bj(W{u7Q`HB;f=?>*4nu^biXEe1@Kj^t&^7?8r5N*gw+rvE!L#t(7m zK>yNGA1I>yIx=N$o`nk9exiT~qVFbFpew3WzwiN!=RiU7TyVvZyqOQ>B+OR$ci864 z27|iB9GWvnu_aGti#5Pcih66RgGx7Z$HV;C|78-I-EZH0H>Q!jh_2w0bbi~)YYOpW zPAfC>8qv>}Whl;asH^(@5ocC_kyDro16ZnI~e5?@RJy4nR!$;VC&G-+*MzQ({@Go>=UQih!6$ z&^eg&bbh^>P^MMbmpd8hR^K*W)SLY-k0Gx5Q_}tO#XK5k*YHbw4Bp;wWbz;xO^W9$ z{EgXtDN412|5v`Sc+T%qygMJOY%;ZX3|<%uqb`O&57!YCM=D8fs={B!{nJEIuA#v{ zFge3&b$)t%DANGabb-hWcUu6}h2!Qvg?cSgtVrep;jF&ao!Hj3JRX;hDLo_J9iT%$ zZXgUqvo*f_XZ#35Ojx@y6PHpYY5SMbjP=*@zffr&(J-+gul^E|rr+ACeZHcG&hh_@@t2N>9>$u~^>G!|!@&cw1TA967oe2jlYS zzdcCnG{rP6O}MnJcg9udiC(gR2b7a>g}G$GVw^|@c>rs4w_ou~vQc#~Iu=PVo!`cj zoOD;3sGfc)R6q9=DNYk-j%^44uTGIlMB&dYvCCQu&bgDy=iMF2vXakMYzCddaSrzS z?X{Lm0ZE@iA?y&?pRZ2+c#Skqa4N`yvC=o}*orj&?BUT{F|N8|T*0O3{O(*81>&x` z+mhK!gd1MA1ohv#E^rr@lSf?~;+??FT_yzF zM!`Ox1^E6l-VbT$27`YAZTrRDheR$HJZSIeEh7V$i{6?;d+YQUvU#}@)R-Qw$Z~oV z+XB735o*IQ*ZDpE=3b^%lMYdpTEsRDYZ2SHi7GUvMf(n=KCe!!%64(}9QwnZeb|0* z_hJ3J_v*oJSn9sBNI#(pF$S#=cOd4kfEZ_gkZmiJrp(o>NO5o99~&JOolD2hNQ62oy#AfxC{X;C@KqN-@FMtU}v% z_9T^7Dg32o`U0iFz(jmua42eAx=M5nyB)Zeg9FHmRf-w&S6@)v;1LJ=k;EAu)}&>I z;=)X*>Oit-A_hb-!l9;8{rCQ4>{$U{l4vUGxSIiHm*)wb`)aW?X|Nh#r)2`XX_*JE zY@Zk7NS7^Kp3ZOQ3J;QW%p(Zz8VmM6D4!1{;5q3YxWkI7nXISR6#LA>GQQBGbSSfK z6XO$3_O20E2kxu^pY{6~xIU?|Rs;yG)&d-MP=Gg=fO9C=;1~lp*0#0sI)I(E)z8@=B|r@3&v_jC)Kxrg4PcdJ=9by*LN zUGR(~I@OObjv#O#2iA+50Qr=l)_`AQ+B6e%F0R*Wb_N6lWb(X)P#Pdy)|aV=DJdq$@b->UKKpck|kS(>pHv@TqXr- zP}tti5*37O1L`5ZDo?9T-X>I+PN4(CIP}FfVIDTy0WGM)q20ENP2765qH7ev10`XQ zHj;A|`-ytL%yaToV5y4SM zb_fXzD0E$Y4z09P__3}#0aZnE=+>Qr_9BIjX~d!PGqLUFpD9ibL}mhooFS_hDE>yj za^v9{ zI;uNIz0MM1+U^4Mb}tI8PLg{Iow2Fr<^B!@uIO<3481JS0FtpwoCN4=_bz=Zh%8~( zjU>f>9?YdCLp*ucvyLe0QFJ{NQfEVI*@|8!ar!yKJj-jPF4ztE7L4Mk@IO4uQB+y& zMF71+!297w%s%9u7w=K5c~~~NRxkQ(>9hDFkFyEcQ3w@7-wDQs^e?G0FA{n$_;cLBP z3k@@Vfh-bfLpcR!w@5>3O`h%-p76(hG-@1TkRp)mGmwqUhZkx~{ul9=$sk8WI z3woBIA!?O3fE+e+`uhik1yc*q!)u#|l%U_fP3zI-TD@%XX3OIoP}n+wB>wZA+fV*Fo1oRT=bh7dY+F(3_Hs!y*pNJ`A;} zu+5o+EUL*7;U0sJ0Q!ADhb}$<=R>WLO_>=Kb@dQO4Ls~=t3{a}1?uw=j%s&Qsl;0F zG;`&nvTz-(u+t!Ww@ulc^!!nUzw!TrG6=-RDitQ@B!*i2u@awm45+*3H7FZ0`-m`& zyA)OL21nhvp(|{gY@iN54J#@ff_@U9d|C0)k0~h*2t7u-#`G1pwiorb zTGkf6ye9%i+1E@V2|2>obSPF19>(BMgRq@WHz6~AzR4WBiq(6C>gUfS;!v-fiB z^+?t!#s9Ynx$_l$=ObA159nWd&EA2RAU2h~Ovo!eFGsTSxaf_jQta#dIi%1$GJWS$Zi@4rwckEc*3!DPZzp+aT_T}HP&c?Zp!W>@;s)P=dc()f8^ zR?KPWtif97HY!l}A7u>5gVVx`JD-8qX-WT$J^w{s_Uw^r*5FCN=r>zN3QyzE4?aCHKtnutS0avX#-pke7m_%O?0;?~esI83_m39#~ z`nFss+2f?>J$4eB&tpASoDVvWxgZbTO-|YM!(9L>2(1X*tjQoEl1sBLf*WzspuO2{ zIkSrMRWnYPh4F5NhGc_(<;LkVFDX7G_L7*@Z|$->{1XPh1N03ga~S2Rq33QVW6#g3 zl&*{5ffAo;b}uv3r|3^y5vzAeG(T(_js0 z03jjXcI;zJtd)I#{Ihx)qM7FYrKjx+m4zs--p*u56>lT5 z;d!~>D?sHo)(vljJu+H8(pZ02S z4b5}ws$qqrir2&#+)PpZdg`E_T~qjb)GbU3hF?T}qau>va%>dQo71=XN9d0|XO=jH zLcPh6e}uwW^tw$zCrrg~vAHf#p4U-ru@+@dhL)fvQdG`t&MS6~w;QQgAmS!n&C4OE z-h4`5k%Zk471X~0F3kkAU_LtY0N&YWk?4%c?J6$A5V40Ev8SN(!&g&o2(#RqlkQvz z98b<-@8%= z-)xn)4Lg&=?0U$*ChO?)<~@INKD#n_A)7lQ-X0lwy<;1+@)cScrK7VlWhSlH@HZzD zLC>@tenPeXE$H7PoRMullH}eI)0^2{$Vawn%HyoaU8On`?Lv*Dt>$j9K5WQVmFmmh zPFCMl_*eT&9rpK%;j zo4|18>G8`a4M#7s@w2xT>1HS7m~>)jJXY*UMj@^R zv?x^k*ql4G5TfN8Xi)qO+&F4CX7~0Ver3w+QI~!g#-pXC5Pu3P_7PYmC35KJM4$2`{e(!=ZKJ6A!!#%x z?K}Fc3wn+JF{=Yiv)HwCEk#+pP=o(OkRSgaSS>!np>9Wg%4vPYVTu}moT6Nb;RzqS zt~62jUCYg8s~ph3Ycb`@n|sD*IenYQiZ>f3h4peTMqq8y*Qs>E{SQ0^D>e&_5`#O^ z<7{u?ODaoUWOJK~X8J@tbyoQaq{_Ujf!b={vu5TokK*?{;`oUFd~{xJkDfE_zw=lk z`G%L?==%AX)4M!Xf|v%c_i=4%41wr#8$pslA>TOZ_@^Qbkp2`E&ibK&nvsI1CFjn7 zGB}RIIF~3ak?`DmV?DxyZ5f zqgf`z_PKa8tHpDaeOr~Wv?pVqi&b|z!1~v#lS9wN+bu-^=#3=CMPe|~PeK`dZ0<`Y zbnx{igNwvuIj#uosLjlOTtLCoIk+~d{z9>4DSi8vbG(wFq-prmP*Rpn2gafi zDTq;7)S~-Jx@ZJII=^one6d&5z2~6bzikt-y(F)W8hp>hVZRgouy^d?PTivchM0KKkc)@!k&wa=Y08GReNW5q zg&^_)kv#EtoJ3OIBKKwaPB_MpcMvOPDyzj^dp&*}1y|T0z@D3Zjmfch;!MkPid(cv zi?bv@3q&_Zy{F|)2sI6RFXoHc6zp~3pKy4H{k>NJIsnhGp+p0Nd^&bB%GzF_X73xgQ(KwBcOlU@B+~v z#nT<6Q}T}qsAoI=$UV5-mXn6s`IXat!R09Bg70iFVP1U{q2JB_R=3LnhmZJ!DM{zI ziiCd>=M&;Sq3BXqTGWZ8eiHjZJ%7#L7>?e`!t~*-QxF@S9vV_(a@hmlG`QSD+#=b~ zuY!w4?*+{6!>o$9w_5s=*w(1^-|S4n0r3=nAQZ zLMplap9JZb5>ltx=Wp#s9l!8LwvO(hoNM#1qFd9ZG#yM&BYA+c91N1V!(GW0$>IC|U4bbX(4M46Uk> zeq?o|pEvysMp-hUeHZ@B5<3+!gH-$>PDMojfNXoCNWULSMdpukj%*w_A3Ae}ManUM zaYH}Sx+&)L8z{_ZeKH@Jq=S}b8s(U#unD8B!ai)uXf1Ax4w?sAYU#3Hy4Rf1dXqsd z{G6z>W43qbCmN9#El}|>eon;tmzcXfegU^Jmf^fe*I%Odk|_9E2R{6 zp6gC*^wfOZG|&SF$6kJ9Qhz^ZGD=UR+GbPmkKPQ7jq^T!c3L4{QJj5$hO0qdJQXc% zs}FF}AO`kjZvru8?i#k#=K+*yg_%d55Njs-k=Mig{KzwXHGeqQ)L|tGS@&|lkr;kc=ONoFuh{@36@Oooexz-RU%B5_Z@IM4G>*j*Bbj>C+A2N;w(38l=`6H{exgX8*WQm~>{tOaGIPA2 zE&DDFll#;T^EUJrmpcMSc^UlgL{_RQd!dfgMp!@UfkH#QzT4i~nnjqyM~B4O$u&?9UV;F?5;RxlaY}r0P z5_Z@xkc91rqUp6u=1)@0!6)|+!&PE@82Ana*FWM%wjF`b_!_qm85|Z|V5u%g6ian^w(|Mg z+Wn#jvcPqaVeyqnaW248U4;?7e|_QeABcyp!g?!7L{mwjrJ8^C%F7Bubt<6zoyhG1 zOl=8PqUnhgmGzaQQXKuul3L&V?6tAP?ZEw(tD(nZR;8D^KO9JuHTa>BiROR#r|RpkKL> z{oJ_fv}QNrW~=6J$JVulJViA*bfm4CXJuAU=&{-y+N_ShBgyd=8va62XCo*I?_$~s zkJ!o%(83lRnod zgX-JK--e0BMrZv&3H#f^iycP}ULNE3I+G*^7~&0kHGd`T3uQG8-=cI-dy{47s#uZK z;Ud%w&gxvt6<*?Rcph1*oB@=cXP34+fI+oH&Y;LaNNDK@==Y%<8ttg&d7l9k`fC^| zbc7Ym8SZaIthdcL4?a{_~%6FGyrDgO3kVxZ`XWQrPz z8zYqW0VlN^(?qrSf3lxIt9`)MQyN0aQ>bv|)28~HGOJ_c|1I?Fq=Mq;i~s%-`OfJi zs+_tiyS%)0Ubz9QNtmbFQD2=(!T4N3sxV$g(78p~Q)NjCC5XYJ6_ns-IiVS^@{n`W zVh#;W6Wzwf`->AZ>(cL6sGtXVd@Uyn%B%TP=4Wa7=F52BM`rk&5hG_Ym zWy4kg+zV2a(*}-Ox&fM}-+5!G%M>+g6ItK_F~4sDs(BOf=+BSX4zpY!%wMnqUr8NZ zkjJL^%0go(u*z zew&xJ$_l2$1oB^RuA|0ed&91XpV_M2rt z>%ELy2l`^r%e`)Mg44Hf6GMA|8)`K^&7mvY)cm!EcZb4jUHHF^54*)lKe(y+IXzc* zFldiQIcSSg9{Zb+dw21lICs&kK@{I4Uk9I;?{7&|l|+|3Rb8mL1FnKbf${}_K@a3Y z*z$V-g*kf&1;6s!kmQNZq<6~XpgrZGPD!(Wbqn>IvCME83Jt+D;VoIf&;K-qthANX zNN@M`JqFN1I>OHt1F=n_>IE1K!4 z_GAyqRI3+fOYZxro%Dx&(ZQQ|iJ>2m7+B5)J(>z}WGC3|8>d&i)ck`M6TDE%V8Uh?(^>OTVw%7_du8(>2s=LuaON~oVgA67btUXtrR zZKP8u(_1*kJjxHB#LMVM`#Q=NuSq3v2kcN*t zTk&tBwDl?n{S6&C!9ia!Jnr~HtixS7v|b#l(Worg52%C$j*9aWA=5=KW9xnp)CG!? z-NvqgoOF+$7&&(+gJFX?)WToPUt#`$c1z^Y?*8fu%xvaR=*jUMddy#_vVcNcq;RNB zfC!jt2LRf45{C{95G|QQparGgN=P6aB=Y7Q+}9bl~;AhRf{=O&Ii zQb8>~(?Fpkw{qyGtuS30Sn(;Y@?4MM(0BkeE=TT#+c|yzAT{492ymU!ejBwUkjnAr zuAQ9pbdXSDaS$pzn8l$HyL2n8_I#gL(*Lc{caMhNjO^S4Bcro9lhO|l{?QYLzgPWs zuTG%}`(R=v(O6nAWO%!uqemPFD9@q`W)BKQwLZ#Gvx9}(whaDg77Y(k=C?%nw!b-P z=rFH*b{Sr8)3e~FcU z-+|EXD!5p=GtBN#QY6#w1lVdjZ(R0*xXqx?0=>NUy_QeuBboBr1~+pH!@@$pd1(Rj z?~?_UO6KB9kfjn(X_O_`%2_>yc(s31*}L+Lwkm5Ot9Ycj`wIH8 zA~k4hOG7fkmC**0%dUYsL8obD)S2xLp{l7}S;B|$3CQl8b`yMJU?n~hpEM6an_5}T zKmHvVQ?zsj_WoaVD(!xcdNW!#(rk>1FUY^q>Xz1LV0TiZirSe~*M5tAa-=UJa32-KcA%%=!$wJJ zEkO5flF&w*WeHxztcyqLwZ%Hj=SbnlfKxBX0`qGLHng4bY4S&c^8n`2?e7+qhQ2`z z?%cnylp*9?TN-6M=uv-qL%LF1<49CnBVGqMzcc((IvVIby>QXj9T}4Cf7UtxK4TE}UOL|?Yonws4>ly<34N%UYuG!C;r(r64Mi*xAEQXPa z7WS=&vU)=ppd!r~Qr(nyDQD2i=#c9?Cmc;kEIbOwEE4p8P?$Tz3clddbH9)v&R0sH znPFD$2E6>~F@<}$!fipi9i*JW1u!Vyw4|Fb9|J!LcJ>4KZZ!#R2QW7s&r`3~%&&$W z3r%6h^P5RphcGu})BL2Kvl*Y!10~M5zT`9B!2XyOTG$htHfldJb-twSTwl7er21g- zVYdX2+2dweVElI(uFG{dn&60+v@HCk^zQxu_rRwt9NfuYX()49%2MMp7vYAN7cV>~;e=B|nM-)k5b|89DJnVK5Mgk|MjCMv zcJ#U5|GHtq&BSIIj7jJBy0)P2(@2JHvl@X*zeciEjb#7cXV8fu6dQ=qXcmeF%*{`9 z@K)0G-@hK+XCSvYwb z;26+#xh>SFDe$k?s_}SoxT$n5n;5?CMlHS!x#`P{y~qDrx(tY3WO*hD(Jx;y?6vz7iPU*HTxU z)5~8b)3U(H5}ed-Z1E=wY7Q?je~5hK{$<;@?Oo7dmLgVHdf>AlEe?7S#q?RYdpeBF zz`k&3SBCJo161W2I%7wKY z+#HuTHTSB)_RvMPF)#+z)o;&PRG?8Ya?P=vfo~1-q7x}z__BVumlc0Lo?A-yjD!#2 zu#|7uFGdYIznNqetEtW9ebe|rYe)3-M$Fo3byS@ux$d0iWlkxva>`yAiyD{B;y6dT z8!KPw63H!x13AgG#XIn4tR_bY)<0ur}i zVE@73ROeBzBDKUS?KHvLsz}ygLUOr#)==OA@K*bndsA7liqvzOw^-`)X3T4YW`xgR zs0wtUjmB0uwU%XyErNtBQx2u*{4UI7q_z|}3rC~0*`6A6lKQY`N!huPsyfugitU&! z=zGM;uYv;N`hi90Cm}(mrLTrU zyg?1)(V!G8MkGpXS1)1E4Wxxy)5CZ<4IO)YV{P5-P%=U*wHJN5L`z?q5^}4Q2n7k3+jkHF^)=PsN7BhwLy`|>Prl|wF`rmp+AZY(;V9Y`mU#d#^4XmVE}_- ztZ>@2b{g>+RTCoHr>laB$tnGH>71NRWeZf^e2 z!ax*s)frcKT>`J|F{M6Yh33xp5gXv#T3`IVGH(Dnspy_?>LQ&&J37hkxY~&cO4gxdEicwmOr-)IHw?)4HMOa6i(FXUxb&0zv&$MDL9XQpGzwS~&i z+fCB#KIn}47j73Qi!S-A>MnrBUJ}suT{I%~-D86Ry`o=$PzVN3eF^yT-a~YShQ^wbgS;*e~mePs#T3r)X$`bP%Ss5-*3uw zO(5qE8e2W{0-EfuQj;ILqPB6C`4}A&3+o2V=+Z)t-=%Blxa(yMwbxdlvbxDt!CM9$ zYA2vh-8JI9?gtH5R^H-+#X;DMx zqlC(L)TW+E7bhlR*YU8$>?;g#+WluQcJAp)jn##`cgq2kAXf*V?S(Vf$RzQdUsI^SQU^#m)Q zcLH^@r`+NB$)Jrt38+sm>BFM%ANtM9(}`YikW+eTDsZ=ZYPpeAkxA=OA*b`uvJO}Xs4ICiMTg$JpGG_? z|MA6<8*Eqk72-QJz1>zF`i}YZR$iK$9=j#8oW$v-f3&io2ynl_aA9vXuJ( zpjJN-s7?c<_v2-okrKwq#VytVG=CcQ1BCH=!^2ycGIFg87 zP%jbgR+9xfR@W_Xd%catY0Ml6(3ZM@UISU+Sb`MiVFD_y(69iE@6r=B;tPuZwi+CI zfr^(SSW@%pvr!g!w-FUHWpGJ580sJ2hvCox-Kuso8;|7IkSP7k<3v=vKSP53kJl33 zg!8#;zs1xP6YP0Zu8zLaPs#$xmunf4*Qr{T1$sJB|GcTm|69uFazQDbO~JPVAwuG9 ziTivT%-lWYF~b^b%32JEW&Tqn-FW!EEYRoy+HUD3+djmp&!h+xn2ZAIwol8G1+oUo zwtpCeiaowaaFxLtagno+-ji|csqZ3-A3VyG}|S}@eRp)$Dt{m`(HP%a=n3+EZW^h68nPg+R3#E{}q| zb=gwN4Zffav{PG0FSt$yk6tj%v`ee)$iHae4%4SXjje1AcnW0@rs({-t`qd8BQ)ZS zZ~YOd5I5OyE(!R9PnB~R^f?~3V7&XDt8Ge`M@UUQV5nVL0#)~NZF6!ODN)`dfhu)V zpl06$>P~Non!r%O4+QGm12FVGDx-s|4AuQVfqMBLP|SyOF`P#M)eG-gFfrcz04lz* zEH#j!J{i;1(O8j;HmPG&>wF&8Lq8*i>~Zt7f3I}9H7?L7JMKewdJ|H)|HE>wmpc{9c#2k@XG){UbW4^=bAn7d@tWZ0G*M=}8%;zlt)H>F?daaKI;I8p#mr@>@K+2~4qukmDP6E` zESIa841%&N!$#ByK zPk857y9Di>YS=Ii^GZjgUe$BMY8yH+8S=VMmUBbYWN?XfX3+9<+qte~!S}ki-*~xg zgPNK;7hY@)rp(D2ahbu?o7p+W7_losGdl@r##E`C#|%2Xi-4MRtt(DqaZ4Q#)9xR}yXaB27u^JX z-|ls7`BcSMp;N{*+_Z*rU6Ih((L)d%n3M=4Z#{X)XVMQ(Zbrr_kjYasa)Vfm)Z2(V|33V9tBXh}Dq&5@ZiiSxxX9 zEvX^RT~XJBl4puty2%kDjqCI8-ZLmU(u1pTIL)Au)0CX&Vwn3R%WjBH2DF`pfF_yMD?!tfrS)xQsA^U^sDDw4H_>Zh*h6*| z<7YIns;Zmptr@*N)lbogXN^OL?>%+_YB-Mws!{FI@muIUNL4`#t+x2F>dvpw$*iVS*L{y0a^TI?|Yh(iGDfG^V?N-d`wZ z_tEJ;a?7GO?%-dLjsS?!$a0ZJJhSlg=z>c1Am>sTrh2!rTpz}-8g1)S&z9bek)deT zB2;y#pFloi%qxu#=;6RdQ#mx*Usd121VKM0RW7R1Qo-fZAO@{k@J;)72Aw~i zL2)f(Qa!tZodSh`T8@{C7-|v8fN2MV&X^>ic_jA(<^?Zkm4r5zM$l4ICCBM0L>sPHAyxcV~a(pdt!{56S$K|rEp36~d#!`Xmyj&)w$1?) zFoNx>1+u0O%jG9H?AuMfaTK~jQ<3K@^p`xW&bqTdTB7z*TUXVi@@e((*4q~;5q}v# zKOIZ&j=p6IuenlJ!WGmONP9Y#UeAJmx5+D67`*2CcubBLaf(E3Tx)l7ZWYP)g50m) z#P|$7D#6cJ%E0Ik!1_zA=;|s2$PHF$YcRTGh4FQg>ZqysBcjdaNO zx3aGh?MRbq%SeOh-)jlfuY4}1_FGzPM>Kc_t3Gw2=r_K)PnRi^#B`J`)s{)%MBCD3 z>^b_t#TgG_cJ>ff-D#gX2-2jEz9wY8T1w!s8eFP%6)4SWImzAj-qb4*;ejI-hw9Os z*ISV8T`ecMY{p>M5CLsC)Yp{Ct&xF4daeYZ8T567$lmljh6 z^wCt`qU-jnjN-ppg2H@l{^DpYpe`wtzE)G664uIH@lW3>g)~LQK}hndyETc@*2->8 zp6Wh41Vjx%q+YvJUM~1mTPF|pG+KvR&a4)7k69;Y4a4A>Io+@#H~_m z@>tR8|In^=SS-7&*N8{BzaQMzj3o&^pqE@Q#0q}*Pm$gR=1Wfdnibh>kFaX_(XbTW ziHFFQ3d-QW4xbmr8eZ@<=ZB;C73Bh~9xu|njna>JJS=0T`vW7d1f9FAjR+HXMzWmMCmj47(RpBbgq$85#;{WyGY)kkR27^7aDU)@$u zTc`xp^TnC%9~Y4&VTF3G{`u<%3bDJV)f)TZCkiFi_j92O{!$3Ptq?+KphcCZ4yXJ| zQp#5J4ij=E!!Hcd;tlEkR?O)P^_!vcLIf%y)X$Y)GQy>JY%`?ehsL->Y+_*}@N6pR z|7^op&{_^J^vZVa&qFZihVZlMy9|h$>nn!U)+ihLJ9wV7|=pqLiM zv>kLZ1uiZVdQ&^vutnNJWoh{WskM`y#hV@gy+48_wW@1x5%h<*_}PkBj5R%S2kLKf zLZB|4@bfBAXeLALKB+}j;R@w5XZ}^cjKiA<#O|%m(}`Ug8`ZSRkOOyu$7GJIM*DZ- zKnjCiV$fOG*4c%S)afD`z4SRkQiiIr3#cns87hEg?ZQk6Xqa-`lvonS2DZ>b$7T`g zQsypAXHL|>{LJglAj-oqi&hcMroi2r4xE4bZt(AuBl!Q^Ee)W;9za{&5zs$({4B&h zo~-J|*PireL6R+8O`wWvb=tW{6U}=mB|9UAy&A~wFs!R0+Wn9*^`gkVnEe>P5q*o7 z@xWGv9!8&f(r^Emk$Te3y;ub^(#1P0|74@;M=&LK71tME8EI8A+J|#xASK6rXn^G} znzv6=iPC=gm7-M#@jXA|GO*&*gOi{Z_Njg~6_?I5cOO=&to#L5zCOOVJfpFp=zSUs zGTx6P1FZam>iI(;Fx4fJ*hleyZ>;%$Hfnqbb;>{?(botP5;g=%p4~r~%zNjHBtS zz#oRPYNdmsR`taym*ZoO06(~!!2hpX{nC6>j;mV11dBeEu9VDQQjsex>c)T^|GCEs%;eom59EOtGGL8<`(%aGh4oLfd{^k4IPw1FU zD5IVMnvT$+e|#anJg?gP7^+SmrA2vhXd;8QAFqYl(7t1caUg4$)nJpvbEu#MDyXL# z8g7$y=#NjXZ$=VP>;2J8ADaU$w4hDHv?&9R@JiDo(pSY z1hSAyy^d98>CnHQRo|4~2FnW-FIm#935H%M3`*?)-ptV!vZnRNr58AI9QDt}*Q%_3 zv(@O_@5l2kYcjm_gw+BycWZr9cbz+cnSiz0_DK03bTA+KP){633rd+#N+z;ctgYKK zQJ2YDEkhG}nJF#P_ykbx*6E;LtgCNMvtP<^z{vi>L@QL2jeqLUeZzX4LaR<-)yS$k z!uVO@OIy|~$Zmoc)6q6IXK*zQ>~(nLdx$<2{M18l`X+55Q;PWqOCZ+Ns5xt2zXg5K zo7}QCYw68s{XcTLI{FXlx7eyh+0n>2>0Hm2T{|dWYwGE_AJsUi3E=V%Jc;s0w`!0Tt2K48}B$5|7unqed5GE4@?e zHXDs`KTLzoGZlR@`JB;A<3b%i1EF^0vGR@SeK~(CN_bh{kt{FENT%99p%H1A$-da& z;yD$QpmMbHoTeq6J*#o&jd1uoyN(B@gB4DNNs&)Fry0+Qj_mzkCHAFx&E@0Kb zppOA9UOd8|21fXg<&ERuSr-AO(Hz{GX|E)88slG)6YxO&+`}XNe?ySA=1`+bkY|&0 zOGVG}H)3}P8c_SIn)1Bp?e0Ir&q5m`(OV-`MW@bG70trVIFoT~7KHiVB8hvSrSah4 zikAWQTV4Rh35FH^*1Vf}MK7PP+t>&_lns|NT2;~3HM*s6&0a~GzSiHI7v;PYv%!1e z7G0`7Tm9i5VM3h1?g|K&?3DyN0|P8+`4x>P$6aE$T_<&M(O0FZkGcxnunUE7_&Vns zUW2l@COw4vHBcGc;#7@k)-{bEZ&16C%&yB}ZvSB&qqf^Exsq0S>|d`y%Kq2E=gnt{ z8*kdcfUaG~o(9wEABLOpw*ZIFMp!=&zoBvDwOy_i=-U}b4JfCu%6j!LC{>;UZ)r+VwcFUT z<74GE*g9^N1lw+FqJ+vA_^MF=YdjWS#sQTJ+BWYFaLzUo_x=vfYco!scL5&lD8W~3 z0&r;tGnVLz0m4$n*k7CK`xGJ1?rO$!Rs-*00KaNP@9%2j857rn%I)q0 z^{gdB1=Gm;$S$(FcQI(M&RVE7xpxV$EhrWC0Qh-51b)*4T(!nZy#%!Q<-P&*ctk)G zih3vwcjQBWpAY2VR>D%Y4+^j<;AZs*1cOI#f}tGDo0j$Gcz*-jFSG3`(weG4IDxVs zX~yt6qjDjM^C`OWNE1n3Wg41`3f`RxD9br<3z^ftxPe|wv0}ID=oL#+aT;RNkgh(` zM6jYd_L%k<5>@Knkmhx7IE?e*v&E{=1NUb* zI=4Fv*KmQrrKSWLlKH|$WeV7ieFps4%^cr{Qa|7kXv?Q^a_o}a>%|6)POA!f#ipxT zQktTlYl!PM?>TgvkbsPkrZ2@k(^TTkoBCf?2D`*H92VD8RrK}rK&G%@3LG3%f`0uc zotnoB$l;%?i+i6O=vE-;1xDbtun>WzH1|9?->{4Bir3y8NLSAV+Nj>zpvEuJprq||B~MeiP-3R3!OR?AoCVvB=vN)|UD+Y%H@}oi z@U)GqRcH`9N~M5NNM@W|v9(Va%$b%z$R#pE{knM-=g) zG0POODslDmfw$W9AIj)wOk+hz|M7sC*Vh z2bHAocXAGG`wkMc!s|aDH6HZFGRTCs<)e-=RDTSVYosv^@ijOn)^``&Rg~1BdVH#$8tVu>X7#*S&RFB^{*`ae~V_uQRh#ZFkW`s zCzL&=VSqaH7iD?175fJ})WNv-M*ybo$aUoNKTRlaMiV2S)>~1531m|@qv3ESO9eVR zJP6;LN8@xL>z6zKLsiX33Dk{IL6%g0gUn*q_zaZy7=|iC+dkt%zJ4sd%u0=BsNMxA ze-3@cps8a;0f#RdkyhkxSX|%6 zJ96=ol;00wU>)Eus_7USLUMBcF4JJjcQBX}A>~`}9a}%F&Mge=9xuWFewWMrKMWiW zOXaPp`$JQeQ+N6S@QuC_+^%0^d@awuW@Vg?Fx>6o64z-&V@q)_J#b-HZe$o#!1R(_ zrmz;4CKVJYNijd=@b3K+%*+@jfyOLJ9lm2L@|yqCRfYJr(S-CQME7Kr%;>tg-R z3)G6K^l1+Cav1;A$(eWa3krz7HTIepHU&0d5MKD4!Mz0qw54h2!p7{7j%@qmUl8}g z0bK(3-!hvJ{u{Vb8M?TIzhyJGFgINFdQ@Z#^Q+3aaD{rNC<+O>Gt zBufsd6GNtpwktv0zcg;&)ZeBwvY(X;ALu!yPZoMgEpFj`T95ku2hQ|k$-*0A?$lXN z5o;}WXEfgG_@JlQ6^SMq^-XBXzBGP`=3zAI{5G)yBAHP`A5A$}fd&>=oM?c)XdlgC z&;wo!T7|CYDx$utfcXSra*Fo!^fJbhWr5782|U4E;wjB%{P((6|nOnpEMhE9#KRuxP5bw?d61>?{_xZO^Gh5s9X7IHw&_x1tfe20K zXG2yc72#_9OX3D_gGqQHc}B1`^((1}?UMh(Hm~msn_}N8LrFTnT9jT=5v!d$tn9~` zysRyml~P2;$*UB=wzDP6j-{mb#sI9>mll^&{CMM?t2Y1U5Aiy}VZkbOep~2$DWx{| zDb&-l?Gg}KAp4>YPyIFr(}vB#Zj@jsJ7Sz6DyU9N4V5~)mwnq=oKM62aSR&9Q3ajf z<^A-|P!SpZ3Pw=x!K377q}1k}mI#2}Hkxguh@>|k-96}vk!;=v;EOLf5lnjj1eaCq zUNfbiYWnu`JXCcF|7>-t#OoL*sfDrP%Ig?u3?BcS3MQY^!DVT?v24LHfHAc07|W{l zOhC5gY%o$*AY<3SaLo<<_x_y;7!;$S71v@ief2l%_V)yrTS{}SS| zFYP#)vl+;0Q-GP|y?J>;?|NN|6el$P7)FJjL&ch*eD<8lQ1R0Z^g(AHBgH`eN zdcKrqp*R+CZ+GUkAII*By#}jNPl*Fr0kIKw*8(*x7)j|CiYwV$Dq_=aR0^lQ)iHEv3szwnW*%GZ~;7T}N52i`NYL73V)J6bGter8sc&4jWx%XFCkh5fI2z zWoaJs1Zk3$G}&}3F!*=A777=%AOzPgc*(WKn{`Xtd4zoj!QO~A?DPej6^jr1Jv6y0+o0+#FFOZqn0yNxAOvZxr`L)J%g6X z5>UztaiI+M?krOczn?zpGDDT8nYOZqCAKIqnL{1PB0Hoc-OWekG1T{~tUyJoTvoB+ zY#NjW)bW;pj>w0mFsR;L0iAO<#IT5GS{iWUMOSzYb{Ajs4>-N~U`aMAuQG{s8H^HxK zd0F?U@~EZdF9Ch@3&LiUm%?T-RIOrk)lsRq=y<4Mkz)x?_8=Hpf)h|Xd&P$9*=M1Ac|1*v`oDW_cp)K$V#K<8S9;>zg?QqF!1 z^*?KYO0ofJXFlpULmen9P(LduWw{RHpPBxfj%wExk#HE*aF9Cu?X=~W3Htvw+^M=5 zeJTomYaOI)M;uVgxk>{1H6Lp32{@fvJK=l&pQoG*FTB4eW+My;CRZ%LYeMQuDsGdMAsi=spW&R`@ zwh*pV%%99bR{V*7D8)1g^`zqq#Je)QM&|;mcAcs?E5h8l&N`mO(cz zDu-1wJe1PHLo4z06Q`Yfin^BuEqjSr9f|&q;Is}jJu=jmqK8R|nQTD`(V@CwUH|Tb zdlrf7YP+RPe27xvTCQmlv$C6gFP!QaGSKIcJI#XjJHM#Xf%;36!&UUhFV9r~|? zFw05RFeCDEQA9?dlM7V(s56aqk$o~dG-&-{n8*~IpL14~`nL;RK{4KQ55vYbWp5T1 zeJbj8AF5bMGLNkUjW_NeN;~_9y3pHW(r2attiNv%9jm0&{GYOm^!%1is!l_j95=wU1dCY2Y>4)Or>qE zN?9_iEM1TH+C3$PB1*SK5UQ?Lj{+;pNIkJK+VIb&Q1aOv>deBv!$y>wjzGAZrRiRjsag@LJlHZ8mQxa*N#% z)~jnNRk{fcE#1VKG|T1Ie&1tz_I^X))fNX&)U+3z=tOnJi|g<0`=`D^kb6DM%2_1_ zzP|>QHO=*GB5q>j5(TlPU>d%OV<;zIpn8{*=_S5OOl(ZC9*S*|Nx19NJzkp;oz_8H z)oyIHC_x79iW3*fCvDw9_C;7Nh^5YTuf`RVU`~p=Qk9eTUp?UTDfH`3NMA)I{fCZ> z6p6z=O^hh1QhgGK6o1}YU>p~RqRDE9!eu#Usg}+ zl5CmJHqcyE^>rISdYetsQk7CQ!>#SxxG-QeD-o-$&t?+Ho#ak{`0k|uge z1DngBf0DFNoE(|Z#F!r7H6h*wFBv{@ioiR0NrxWf1?ZeioZdu)y1djXhF?2F z;N506Da~^;yjA1&b}#uFEjo&*N3C#tticuTFuRF;K}Yk+B!0iM-7(yM_0 z@0_;`uJ@kY-kCjS83KjXP${daBsKSuOPI3f-UjMZcD`GV`^c}+^u%mqzs zNE0GYMb!Jb*>oNTLlj1|`s>O?Bn$Z{A_MMbdhAFOOh##K3X={_t)Ym+PP`E%@34~A z)EWQ7b#q`y?!ib%wE#m^-G~N~^yr-?P6a~QS&y&N8+wew`cWN0yvP--L2pW>Ys%1| zdQH|Xc{(Vcm%5D%t5os%M<}lm6sd0H-jAZt!J3LVjMs7DwY~?t6e~7%S7Fjmp9HBv zEt!(wsg-YSun{3sD@rXmHRrgdloHp}u1L(64y^vEzLZf*slv4~dwZ!a*2uLQL#OH` z=jHxXqPAS9y4U93t7&cNYyN4_<>`D3oBGj(J<_eIv?!k{xzn$sY}z~mkFFkL`?t`) zwUwIO6TbXey1`nE`~*m$mcU|rQyROyX<3S_BL_^oIuQTs0UB9H@!;YcXM40hgt2Le zv8kR8o*$>vbrg3_Rhc%{3x&S!sjnh70o(h6m0M{oswS7kYfJQo0B~WA_tjAlK6$p*k~)&DAD&HPQ@^_(xQw$E zs1AOLI8=7CeX5Z=Mt>cQvq~y1&q4(0CY0k929=Dg*AkVn$F5yeq@BYA=?_0S9FD9! zJEH=)vio|fsz^&j3excUa_!o$KExUtE1*7c%}i-aeJOD!Lv3rLMcL32m=%|$*Y3y$ z?IB11B6++L?X>g;6y+~_qqjd;?d>8^%l#EQ&gI~gCxiUJWhS_&&3#&LL7FzOnK2z& zfX}3u3XL0pOX)-%)T+d0X4I#zoc1T&+2+~}U1Eu*tLGhuf!abgw7G#C9ETXcoWTP1 zx`9ken*;!AHBvwu21vJ|FsR>H0Zk5&wA&bT=0pL_4Uit?7lSs(e8emg&=ORup-k&U zu#~>-9D&-ou2~6MF{ha!&1xt`TFUUw3w7{U8!BQuDUYE%*J)9f=X0W>JyRoK8`Jax{+(#OSrBC4q_$@4id;TmR-6$_rH7xFhTOt;?5lsKFUNL@nTp zv(2c@IlMQ@UcKS8PtNqnOhJIz2wMzlkED0L86})=W=qS0q&hYS!J}Wl-;9DDG%HJw z^1*Kb*1!EPnKYKscVJ@xGG0*o#)>$sH3I;>X|%4f;>MfV{K4|>@o3^Bgk$P#@)mmA zSP|#uDg>iYB>4u*EM_P6w*id_R;qBxua0s3zz&M9gg(`t?~qX#RW%NCq}iM08uUHN z>i;kyvk)nfUkI3uq1GWv6|Tc^_*?&I9a&=C8Q_pAa^r4B=s$EmmJB;cym5S)V{;p1=@HaR1#w{!DJ%ZZxplS8S$L%P}%rBM4 zO5LI3O_8W9-%PRNx*AB2Td@P<^H4t)Njkq*G2zrUHr$>Pn#m@NYX$~YXlXNP(^>5A zYPf|_sm1%JVi+^21Zof_Lo0lRVy`!yW`rr?%-at9UA*+9a7vmKuKu2sdAJXZdM=rT zE0wuur_8owvNO*q_@~}m+qEd1DyD{ei`z_C*?Hk8>qy(em8!h#dGl2+EXTs0M^$TN z_o{GmN<$ZzH)yPgg6G|AE{L5<5<6S*j@Gr=1vSjwULgb zNs%%MuoH!f>-#sSME~Yal#$=#zZrOCHx4dOb)uw?kBveVk<>p*4pe>@LG(g$jzJ0` zD@wNQKB)93a%gpOiIy3u2GM|etYfr3G$UG0w<{U6*Lnec6)pD=uKl`T!yepv4)Jl^ zO6PZR10xOPX4g9gWfyN^fa6xCX8)Ur0f zyX3Z3ocY2;_XE1>8`|3Ibz?YjUeCS_Xt%JxJ*aCN8MPzpk=$8 zrMCTSj;v$P)HX6ivyTJm-Jj$er?~Sm{AAml3VYEn-7xv78|MC}IW76q+>N%!NjpD= z!g_V-PMn-LzqK7T@g^+q7S!vkqgdn($t7O#;iK~MG0TY?fxM1?l~hEVXkfft>@0mX z<>4W?kpIx#>P6scrwFoij&R}^Q*efTn|SS60Y=&Qrzx9F%*EVv!`Xh4=Dp`GvthmK>=Ux9)a&{DKd zBYnkHhMI*Sow4C4Lq!JlAFFST*a>l8m%Xs3uz7cv>NaR)(r zxR7eNuQ#&x|GUSt3lN?7zl;sbm@)2rT z=ihfVVaP^UW;m(DoHt6)zwDrt;}*1ct)E$SNJvnzx<$BMr=#2{N&k4l>=}&vIE=fB zir*YO&%o-poDxx*I_#D))Ygs=?aWkxdel+&q<6j4(Y3&ZZHB6ibq|&YjEh?*MVujx z>I4P>DFT|A5`n}cW@m17X$%#QoDwSllp)>gB)!RdhFZN^penCH#|8G3i}9SvcQkh~ zJ@10asWmd5I(L>i{EMsVQ)>vs2zYCxf zk7%I=WPB98nFO2Q4M<`5#Tf$s{&+-5I@d)h$NNq3KkXO<4YBhm>Q!w2<63%aYClJs zSA@smH`PFE3xU-d#dZ@ERF3+0m8;&Au1u!xTuP+ydi|X*G;a{6I+a4JrIU= z4D*lLjx2Kose5;sWsK;K3U59X(DB`+ZkI6V*ykLY`d@?@|2medE=2#rKP;v2KV*5- zN2ntH6HK!IgXhG)Lom6UrYpv&GxI8ts8*>~?4 zYN9cv_eKua&?M5HTNvjR-4m#xHUjn2Cb9xu86ZpTWT;0KIV!ccVnttj%7mbKFJPX! z7GSz(;x;W7+xBCaOVtW6SqCHW67Or7e!sxb4?OeHmADQT*12Te3v*WhqE;VOPdsbJ zD9cm(-ij+9_6yz|HF<_kV~<&@1EnpL)>|GRi{JMAEpsEYz|&R5?_C>SGuic#4xedK zZ!pF7k>T;EKA0XivcJpI&OVCx9Pb{0`YGKhwy$DOKJ6n*kz{lk-KUtoh%ZO)mVLk=*$FY=c{p3hBiCM9IGYozM9J_j%qFKmD z9qHM^$kO!oq+C-tKY2X!5?D6|>uNe8W1F7>`^z1IQT?HxiOZN&cGw|QoOyeFmqhzE zKv6feS3Lm+()<4MNR8(J6ur4p6jfG5;=Q7L>l?>VZ_@>8?*Q2sj~KMlb^-NHR7%sg zo-$YpNC3)xj}A)vb-*%)s(Vlebr}is0<-+i@Y9cK@#4#$#6&>TGqq4FI)DnfnO_2` zcpI}QdfYCu9KCmpDoKU|rOR>~2wWdWiR&~_PVh+#{JN?H?;j|qjJph6uetvw4AW>ThT`@?eZ!R%tDQ`i0WiWJNF<9ndSI0DQV9!$DhI{c> z^)IZ9Sp{Y=72&g|iq-5eEon*e8ls4BTiJGg z-7o|{InIUq-z-v1Z$^Eu$i(56A*lMkBJl0oMU|u9^QBa=9WhipP{pCr62gaKs4ilE zSD;5j6}*oDRq>&dz0a%IOspO=q6$m;z6;}Q&*;TA-eAWq9dn_d9S~GK9&V0fq!p;c z_$Yjo?1j`|!ZGQ7*(Qu0?#>#f*cZvk)xBu!*B65;3#l*lRMC_b5N98A!U8~gDR}5ZdbOkbElR+dgArdO zgk+rg`UNeGf+eV(MBWn49d`qbkSmOU5wOYHX%d`~7G=zjH*(9L%W$tYNZf@Has|6P zC@Cisq6A@zgxAvfJ=~T$QmMsdsM`BV=?oCLL*6PnByfs*IYUPpyD!R!Mvs(zK64~0 zD}I#Ysux*UvD0jNP3hN2dGO776#8WZ1∨WfcC_SI$twQ3$yno{2Iik6;;%T>z^1 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 PT>Yz9mW*?c2k!p>K;}@s From c8f0eeb9c8596be83fefb7fef9f9871e53edb020 Mon Sep 17 00:00:00 2001 From: Balasubramanian Kandasamy Date: Mon, 28 Nov 2016 16:38:03 +0530 Subject: [PATCH 033/124] Bug#25159791 BASEDIR: COMMAND NOT FOUND ERROR WHILE STARTING SERVER WITH INIT SCRIPTS (cherry picked from commit 7a39efab8a59ebdcd562fb788bc004ff338796ea) --- packaging/rpm-oel/mysql-systemd-start | 2 +- packaging/rpm-oel/mysql.init | 6 +++--- packaging/rpm-sles/mysql.init | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packaging/rpm-oel/mysql-systemd-start b/packaging/rpm-oel/mysql-systemd-start index af6e906efe1..c744bdceeb4 100644 --- a/packaging/rpm-oel/mysql-systemd-start +++ b/packaging/rpm-oel/mysql-systemd-start @@ -22,7 +22,7 @@ install_db () { datadir=$(get_option mysqld datadir "/var/lib/mysql") # Restore log, dir, perms and SELinux contexts - if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then install -d -m 0755 -omysql -gmysql "$datadir" || exit 1 fi log=/var/log/mysqld.log diff --git a/packaging/rpm-oel/mysql.init b/packaging/rpm-oel/mysql.init index 50d1bba017d..c3bbb277b91 100644 --- a/packaging/rpm-oel/mysql.init +++ b/packaging/rpm-oel/mysql.init @@ -76,10 +76,10 @@ start(){ [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile" if [ ! -d "$datadir/mysql" ] ; then # First, make sure $datadir is there with correct permissions - if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then install -d -m0755 -omysql -gmysql "$datadir" || exit 1 fi - if [ ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then chown mysql:mysql "$datadir" chmod 0755 "$datadir" fi @@ -99,7 +99,7 @@ start(){ return $ret fi fi - if [ ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then chown mysql:mysql "$datadir" chmod 0755 "$datadir" fi diff --git a/packaging/rpm-sles/mysql.init b/packaging/rpm-sles/mysql.init index 25762d9bee2..62f2a62e1b9 100644 --- a/packaging/rpm-sles/mysql.init +++ b/packaging/rpm-sles/mysql.init @@ -57,7 +57,7 @@ install_db () { logfile=$(get_option mysqld_safe log-error "/var/log/mysql/mysqld.log") # Restore log, dir, perms and SELinux contexts - if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(basedir "$datadir")" = "x/var/lib" ]; then + if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then install -d -m 0755 -omysql -gmysql "$datadir" || return 1 fi From 52ea5ad865b4f6b4b37176296a3be0a716c5109a Mon Sep 17 00:00:00 2001 From: SachinSetiya Date: Thu, 1 Dec 2016 11:24:04 +0530 Subject: [PATCH 034/124] MDEV-11016 wsrep_node_is_ready() check is too strict Problem:- The condition that checks for node readiness is too strict as it does not allow SELECTs even if these selects do not access any tables. For example,if we run SELECT 1; OR SELECT @@max_allowed_packet; Solution:- We need not to report this error when all_tables(lex->query_tables) is NULL: --- .../suite/galera/r/galera_var_dirty_reads.result | 13 +++++++++++++ .../suite/galera/t/galera_var_dirty_reads.test | 7 +++++++ sql/sql_parse.cc | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index 6d703c8cf95..6a2aa1eb5e7 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -18,6 +18,19 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; i 1 +SET @@session.wsrep_dirty_reads=OFF; +SELECT 2; +2 +2 +SELECT @@max_allowed_packet; +@@max_allowed_packet +4194304 +SELECT 2+2 from DUAL; +2+2 +4 +SELECT sysdate() from DUAL; +sysdate() +2016-10-28 23:13:06 SELECT * FROM t1; i 1 diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index dfd8d5ecf29..0c81779ca65 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -36,6 +36,13 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; +#Select query which does not access table should be allowed MDEV-11016 +SET @@session.wsrep_dirty_reads=OFF; +SELECT 2; +SELECT @@max_allowed_packet; +SELECT 2+2 from DUAL; +SELECT sysdate() from DUAL; + --disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' --enable_query_log diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ed1b7a5323..11613fac026 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2635,11 +2635,15 @@ mysql_execute_command(THD *thd) /* Bail out if DB snapshot has not been installed. We however, allow SET and SHOW queries. + SHOW and SELECT queries (only if wsrep_dirty_reads is set or when it + does not access ant table) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && + !(lex->sql_command == SQLCOM_SELECT && + !all_table) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, From 599d8cc2deee615526838ddc962778e51cd3a15a Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 2 Dec 2016 23:03:43 +0100 Subject: [PATCH 035/124] - MDEV-11366 SIGBUS errors in Connect Storage Engine for ArmHF and MIPS. Fix includes launchpad fix plus more to cover writing BIN tables. modified: storage/connect/tabfix.cpp modified: storage/connect/value.cpp modified: storage/connect/value.h - Typo: Change the name of filamzip to filamgz to prepare future ZIP tables. modified: storage/connect/CMakeLists.txt added: storage/connect/filamgz.cpp added: storage/connect/filamgz.h deleted: storage/connect/filamzip.cpp deleted: storage/connect/filamzip.h modified: storage/connect/plgdbsem.h modified: storage/connect/reldef.cpp modified: storage/connect/tabdos.cpp modified: storage/connect/tabdos.h modified: storage/connect/tabfix.cpp modified: storage/connect/tabfmt.cpp modified: storage/connect/tabjson.cpp --- storage/connect/CMakeLists.txt | 12 +-- storage/connect/{filamzip.cpp => filamgz.cpp} | 78 +++++++++---------- storage/connect/{filamzip.h => filamgz.h} | 28 +++---- storage/connect/plgdbsem.h | 2 +- storage/connect/reldef.cpp | 16 ++-- storage/connect/tabdos.cpp | 48 ++++++------ storage/connect/tabdos.h | 2 +- storage/connect/tabfix.cpp | 19 ++--- storage/connect/tabfmt.cpp | 22 +++--- storage/connect/tabjson.cpp | 20 ++--- storage/connect/value.cpp | 35 +++++++-- storage/connect/value.h | 66 +++++++++++----- 12 files changed, 197 insertions(+), 151 deletions(-) rename storage/connect/{filamzip.cpp => filamgz.cpp} (96%) rename storage/connect/{filamzip.h => filamgz.h} (91%) diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 46c4841ff97..f1567730b26 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -20,14 +20,14 @@ SET(CONNECT_SOURCES ha_connect.cc connect.cc user_connect.cc mycat.cc fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h array.cpp blkfil.cpp colblk.cpp csort.cpp -filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamzip.cpp +filamap.cpp filamdbf.cpp filamfix.cpp filamgz.cpp filamtxt.cpp filter.cpp json.cpp jsonudf.cpp maputil.cpp myconn.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp tabmysql.cpp taboccur.cpp tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvir.cpp tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h -engmsg.h filamap.h filamdbf.h filamfix.h filamtxt.h filamzip.h +engmsg.h filamap.h filamdbf.h filamfix.h filamgz.h filamtxt.h filter.h global.h ha_connect.h inihandl.h json.h jsonudf.h maputil.h msgid.h mycat.h myconn.h myutil.h os.h osutil.h plgcnx.h plgdbsem.h preparse.h reldef.h resource.h tabcol.h tabdos.h tabfix.h tabfmt.h tabjson.h tabmul.h tabmysql.h @@ -38,7 +38,7 @@ user_connect.h valblk.h value.h xindex.h xobject.h xtable.h) # Definitions that are shared for all OSes # add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS -Dconnect_EXPORTS) -add_definitions( -DHUGE_SUPPORT -DZIP_SUPPORT -DPIVOT_SUPPORT ) +add_definitions( -DHUGE_SUPPORT -DGZ_SUPPORT -DPIVOT_SUPPORT ) # @@ -270,9 +270,9 @@ IF(CONNECT_WITH_JDBC) # Find required libraries and include directories SET (JAVA_SOURCES JdbcInterface.java) add_jar(JdbcInterface ${JAVA_SOURCES}) - install_jar(JdbcInterface DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) - INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar - DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + install_jar(JdbcInterface DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/JavaWrappers.jar + DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) add_definitions(-DJDBC_SUPPORT) ELSE() SET(JDBC_LIBRARY "") diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamgz.cpp similarity index 96% rename from storage/connect/filamzip.cpp rename to storage/connect/filamgz.cpp index d9834e56dcd..07242ea633c 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamgz.cpp @@ -1,11 +1,11 @@ -/*********** File AM Zip C++ Program Source Code File (.CPP) ***********/ -/* PROGRAM NAME: FILAMZIP */ +/************ File AM GZ C++ Program Source Code File (.CPP) ***********/ +/* PROGRAM NAME: FILAMGZ */ /* ------------- */ /* Version 1.5 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -56,7 +56,7 @@ /***********************************************************************/ //#define ZLIB_DLL -#include "filamzip.h" +#include "filamgz.h" /***********************************************************************/ /* DB static variables. */ @@ -66,13 +66,13 @@ extern int num_read, num_there, num_eq[]; // Statistics /* ------------------------------------------------------------------- */ /***********************************************************************/ -/* Implementation of the ZIPFAM class. */ +/* Implementation of the GZFAM class. */ /***********************************************************************/ -ZIPFAM::ZIPFAM(PZIPFAM txfp) : TXTFAM(txfp) +GZFAM::GZFAM(PGZFAM txfp) : TXTFAM(txfp) { Zfile = txfp->Zfile; Zpos = txfp->Zpos; - } // end of ZIPFAM copy constructor + } // end of GZFAM copy constructor /***********************************************************************/ /* Zerror: Error function for gz calls. */ @@ -82,7 +82,7 @@ ZIPFAM::ZIPFAM(PZIPFAM txfp) : TXTFAM(txfp) /* library, errnum is set to Z_ERRNO and the application may consult */ /* errno to get the exact error code. */ /***********************************************************************/ -int ZIPFAM::Zerror(PGLOBAL g) +int GZFAM::Zerror(PGLOBAL g) { int errnum; @@ -101,7 +101,7 @@ int ZIPFAM::Zerror(PGLOBAL g) /***********************************************************************/ /* Reset: reset position values at the beginning of file. */ /***********************************************************************/ -void ZIPFAM::Reset(void) +void GZFAM::Reset(void) { TXTFAM::Reset(); //gzrewind(Zfile); // Useful ????? @@ -109,10 +109,10 @@ void ZIPFAM::Reset(void) } // end of Reset /***********************************************************************/ -/* ZIP GetFileLength: returns an estimate of what would be the */ +/* GZ GetFileLength: returns an estimate of what would be the */ /* uncompressed file size in number of bytes. */ /***********************************************************************/ -int ZIPFAM::GetFileLength(PGLOBAL g) +int GZFAM::GetFileLength(PGLOBAL g) { int len = TXTFAM::GetFileLength(g); @@ -124,9 +124,9 @@ int ZIPFAM::GetFileLength(PGLOBAL g) } // end of GetFileLength /***********************************************************************/ -/* ZIP Access Method opening routine. */ +/* GZ Access Method opening routine. */ /***********************************************************************/ -bool ZIPFAM::OpenTableFile(PGLOBAL g) +bool GZFAM::OpenTableFile(PGLOBAL g) { char opmode[4], filename[_MAX_PATH]; MODE mode = Tdbp->GetMode(); @@ -137,7 +137,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) break; case MODE_UPDATE: /*****************************************************************/ - /* Updating ZIP files not implemented yet. */ + /* Updating GZ files not implemented yet. */ /*****************************************************************/ strcpy(g->Message, MSG(UPD_ZIP_NOT_IMP)); return true; @@ -152,7 +152,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) // Last = Nrec; // For ZBKFAM Tdbp->ResetSize(); } else { - sprintf(g->Message, MSG(NO_PART_DEL), "ZIP"); + sprintf(g->Message, MSG(NO_PART_DEL), "GZ"); return true; } // endif filter @@ -196,7 +196,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) /* Allocate the line buffer. For mode Delete a bigger buffer has to */ /* be allocated because is it also used to move lines into the file. */ /***********************************************************************/ -bool ZIPFAM::AllocateBuffer(PGLOBAL g) +bool GZFAM::AllocateBuffer(PGLOBAL g) { MODE mode = Tdbp->GetMode(); @@ -223,7 +223,7 @@ bool ZIPFAM::AllocateBuffer(PGLOBAL g) /***********************************************************************/ /* GetRowID: return the RowID of last read record. */ /***********************************************************************/ -int ZIPFAM::GetRowID(void) +int GZFAM::GetRowID(void) { return Rows; } // end of GetRowID @@ -231,7 +231,7 @@ int ZIPFAM::GetRowID(void) /***********************************************************************/ /* GetPos: return the position of last read record. */ /***********************************************************************/ -int ZIPFAM::GetPos(void) +int GZFAM::GetPos(void) { return (int)Zpos; } // end of GetPos @@ -239,7 +239,7 @@ int ZIPFAM::GetPos(void) /***********************************************************************/ /* GetNextPos: return the position of next record. */ /***********************************************************************/ -int ZIPFAM::GetNextPos(void) +int GZFAM::GetNextPos(void) { return gztell(Zfile); } // end of GetNextPos @@ -247,9 +247,9 @@ int ZIPFAM::GetNextPos(void) /***********************************************************************/ /* SetPos: Replace the table at the specified position. */ /***********************************************************************/ -bool ZIPFAM::SetPos(PGLOBAL g, int pos __attribute__((unused))) +bool GZFAM::SetPos(PGLOBAL g, int pos __attribute__((unused))) { - sprintf(g->Message, MSG(NO_SETPOS_YET), "ZIP"); + sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ"); return true; #if 0 Fpos = pos; @@ -267,7 +267,7 @@ bool ZIPFAM::SetPos(PGLOBAL g, int pos __attribute__((unused))) /***********************************************************************/ /* Record file position in case of UPDATE or DELETE. */ /***********************************************************************/ -bool ZIPFAM::RecordPos(PGLOBAL) +bool GZFAM::RecordPos(PGLOBAL) { Zpos = gztell(Zfile); return false; @@ -276,7 +276,7 @@ bool ZIPFAM::RecordPos(PGLOBAL) /***********************************************************************/ /* Skip one record in file. */ /***********************************************************************/ -int ZIPFAM::SkipRecord(PGLOBAL g, bool header) +int GZFAM::SkipRecord(PGLOBAL g, bool header) { // Skip this record if (gzeof(Zfile)) @@ -293,7 +293,7 @@ int ZIPFAM::SkipRecord(PGLOBAL g, bool header) /***********************************************************************/ /* ReadBuffer: Read one line from a compressed text file. */ /***********************************************************************/ -int ZIPFAM::ReadBuffer(PGLOBAL g) +int GZFAM::ReadBuffer(PGLOBAL g) { char *p; int rc; @@ -357,7 +357,7 @@ int ZIPFAM::ReadBuffer(PGLOBAL g) /* WriteDB: Data Base write routine for ZDOS access method. */ /* Update is not possible without using a temporary file (NIY). */ /***********************************************************************/ -int ZIPFAM::WriteBuffer(PGLOBAL g) +int GZFAM::WriteBuffer(PGLOBAL g) { /*********************************************************************/ /* Prepare the write buffer. */ @@ -376,7 +376,7 @@ int ZIPFAM::WriteBuffer(PGLOBAL g) /***********************************************************************/ /* Data Base delete line routine for ZDOS access method. (NIY) */ /***********************************************************************/ -int ZIPFAM::DeleteRecords(PGLOBAL g, int) +int GZFAM::DeleteRecords(PGLOBAL g, int) { strcpy(g->Message, MSG(NO_ZIP_DELETE)); return RC_FX; @@ -385,21 +385,21 @@ int ZIPFAM::DeleteRecords(PGLOBAL g, int) /***********************************************************************/ /* Data Base close routine for DOS access method. */ /***********************************************************************/ -void ZIPFAM::CloseTableFile(PGLOBAL, bool) +void GZFAM::CloseTableFile(PGLOBAL, bool) { int rc = gzclose(Zfile); if (trace) - htrc("ZIP CloseDB: closing %s rc=%d\n", To_File, rc); + htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc); Zfile = NULL; // So we can know whether table is open //To_Fb->Count = 0; // Avoid double closing by PlugCloseAll } // end of CloseTableFile /***********************************************************************/ -/* Rewind routine for ZIP access method. */ +/* Rewind routine for GZ access method. */ /***********************************************************************/ -void ZIPFAM::Rewind(void) +void GZFAM::Rewind(void) { gzrewind(Zfile); } // end of Rewind @@ -409,7 +409,7 @@ void ZIPFAM::Rewind(void) /***********************************************************************/ /* Constructors. */ /***********************************************************************/ -ZBKFAM::ZBKFAM(PDOSDEF tdp) : ZIPFAM(tdp) +ZBKFAM::ZBKFAM(PDOSDEF tdp) : GZFAM(tdp) { Blocked = true; Block = tdp->GetBlock(); @@ -421,7 +421,7 @@ ZBKFAM::ZBKFAM(PDOSDEF tdp) : ZIPFAM(tdp) BlkPos = tdp->GetTo_Pos(); } // end of ZBKFAM standard constructor -ZBKFAM::ZBKFAM(PZBKFAM txfp) : ZIPFAM(txfp) +ZBKFAM::ZBKFAM(PZBKFAM txfp) : GZFAM(txfp) { CurLine = txfp->CurLine; NxtLine = txfp->NxtLine; @@ -505,7 +505,7 @@ int ZBKFAM::GetPos(void) /***********************************************************************/ bool ZBKFAM::RecordPos(PGLOBAL /*g*/) { -//strcpy(g->Message, "RecordPos not implemented for zip blocked tables"); +//strcpy(g->Message, "RecordPos not implemented for gz blocked tables"); //return true; return RC_OK; } // end of RecordPos @@ -515,7 +515,7 @@ bool ZBKFAM::RecordPos(PGLOBAL /*g*/) /***********************************************************************/ int ZBKFAM::SkipRecord(PGLOBAL /*g*/, bool) { -//strcpy(g->Message, "SkipRecord not implemented for zip blocked tables"); +//strcpy(g->Message, "SkipRecord not implemented for gz blocked tables"); //return RC_FX; return RC_OK; } // end of SkipRecord @@ -615,7 +615,7 @@ int ZBKFAM::WriteBuffer(PGLOBAL g) /*********************************************************************/ /* In Insert mode, blocs are added sequentialy to the file end. */ - /* Note: Update mode is not handled for zip files. */ + /* Note: Update mode is not handled for gz files. */ /*********************************************************************/ if (++CurNum == Rbuf) { /*******************************************************************/ @@ -703,7 +703,7 @@ void ZBKFAM::CloseTableFile(PGLOBAL g, bool) rc = gzclose(Zfile); if (trace) - htrc("ZIP CloseDB: closing %s rc=%d\n", To_File, rc); + htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc); Zfile = NULL; // So we can know whether table is open //To_Fb->Count = 0; // Avoid double closing by PlugCloseAll @@ -854,7 +854,7 @@ int ZIXFAM::WriteBuffer(PGLOBAL g) { /*********************************************************************/ /* In Insert mode, blocs are added sequentialy to the file end. */ - /* Note: Update mode is not handled for zip files. */ + /* Note: Update mode is not handled for gz files. */ /*********************************************************************/ if (++CurNum == Rbuf) { /*******************************************************************/ @@ -1062,7 +1062,7 @@ int ZLBFAM::GetNextPos(void) /***********************************************************************/ bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused))) { - sprintf(g->Message, MSG(NO_SETPOS_YET), "ZIP"); + sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ"); return true; #if 0 // All this must be checked if (pos < 0) { @@ -1423,4 +1423,4 @@ void ZLBFAM::Rewind(void) //Rbuf = 0; commented out in case we reuse last read block } // end of Rewind -/* ------------------------ End of ZipFam ---------------------------- */ +/* ------------------------ End of GzFam ---------------------------- */ diff --git a/storage/connect/filamzip.h b/storage/connect/filamgz.h similarity index 91% rename from storage/connect/filamzip.h rename to storage/connect/filamgz.h index edb8b5db323..d667fdddcc2 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamgz.h @@ -1,16 +1,16 @@ -/************** FilAmZip H Declares Source Code File (.H) **************/ -/* Name: FILAMZIP.H Version 1.2 */ +/*************** FilAmGz H Declares Source Code File (.H) **************/ +/* Name: FILAMGZ.H Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2016 */ /* */ /* This file contains the GZIP access method classes declares. */ /***********************************************************************/ -#ifndef __FILAMZIP_H -#define __FILAMZIP_H +#ifndef __FILAMGZ_H +#define __FILAMGZ_H #include "zlib.h" -typedef class ZIPFAM *PZIPFAM; +typedef class GZFAM *PGZFAM; typedef class ZBKFAM *PZBKFAM; typedef class ZIXFAM *PZIXFAM; typedef class ZLBFAM *PZLBFAM; @@ -20,19 +20,19 @@ typedef class ZLBFAM *PZLBFAM; /* variable record length files compressed using the gzip library */ /* functions. File is accessed record by record (row). */ /***********************************************************************/ -class DllExport ZIPFAM : public TXTFAM { +class DllExport GZFAM : public TXTFAM { // friend class DOSCOL; public: // Constructor - ZIPFAM(PDOSDEF tdp) : TXTFAM(tdp) {Zfile = NULL; Zpos = 0;} - ZIPFAM(PZIPFAM txfp); + GZFAM(PDOSDEF tdp) : TXTFAM(tdp) {Zfile = NULL; Zpos = 0;} + GZFAM(PGZFAM txfp); // Implementation - virtual AMT GetAmType(void) {return TYPE_AM_ZIP;} + virtual AMT GetAmType(void) {return TYPE_AM_GZ;} virtual int GetPos(void); virtual int GetNextPos(void); virtual PTXF Duplicate(PGLOBAL g) - {return (PTXF)new(g) ZIPFAM(this);} + {return (PTXF)new(g) GZFAM(this);} // Methods virtual void Reset(void); @@ -57,14 +57,14 @@ class DllExport ZIPFAM : public TXTFAM { // Members gzFile Zfile; // Points to GZ file structure z_off_t Zpos; // Uncompressed file position - }; // end of class ZIPFAM + }; // end of class GZFAM /***********************************************************************/ /* This is the access method class declaration for optimized variable */ /* record length files compressed using the gzip library functions. */ /* The File is accessed by block (requires an opt file). */ /***********************************************************************/ -class DllExport ZBKFAM : public ZIPFAM { +class DllExport ZBKFAM : public GZFAM { public: // Constructor ZBKFAM(PDOSDEF tdp); @@ -167,4 +167,4 @@ class DllExport ZLBFAM : public BLKFAM { bool Optimized; // true when opt file is available }; // end of class ZLBFAM -#endif // __FILAMZIP_H +#endif // __FILAMGZ_H diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 910ce97f48a..e99f5f36444 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -123,7 +123,7 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_PRX = 129, /* PROXY access method type no */ TYPE_AM_XTB = 130, /* SYS table access method type */ TYPE_AM_BLK = 131, /* BLK access method type no */ - TYPE_AM_ZIP = 132, /* ZIP access method type no */ + TYPE_AM_GZ = 132, /* GZ access method type no */ TYPE_AM_ZLIB = 133, /* ZLIB access method type no */ TYPE_AM_JSON = 134, /* JSON access method type no */ TYPE_AM_JSN = 135, /* JSN access method type no */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index a62fcbf9416..30e4d49d249 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -1,7 +1,7 @@ /************* RelDef CPP Program Source Code File (.CPP) **************/ /* PROGRAM NAME: RELDEF */ /* ------------- */ -/* Version 1.5 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -43,9 +43,9 @@ #if defined(VCT_SUPPORT) #include "filamvct.h" #endif // VCT_SUPPORT -#if defined(ZIP_SUPPORT) -#include "filamzip.h" -#endif // ZIP_SUPPORT +#if defined(GZ_SUPPORT) +#include "filamgz.h" +#endif // GZ_SUPPORT #include "tabdos.h" #include "valblk.h" #include "tabmul.h" @@ -665,15 +665,15 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode) /*********************************************************************/ if (!((PTDBDOS)tdbp)->GetTxfp()) { if (cmpr) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (cmpr == 1) - txfp = new(g) ZIPFAM(defp); + txfp = new(g) GZFAM(defp); else txfp = new(g) ZLBFAM(defp); -#else // !ZIP_SUPPORT +#else // !GZ_SUPPORT strcpy(g->Message, "Compress not supported"); return NULL; -#endif // !ZIP_SUPPORT +#endif // !GZ_SUPPORT } else if (rfm == RECFM_VAR) { if (map) txfp = new(g) MAPFAM(defp); diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 98633f49d23..06dde34a27f 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -1,11 +1,11 @@ /************* TabDos C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABDOS */ /* ------------- */ -/* Version 4.9 */ +/* Version 4.9.1 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -51,9 +51,9 @@ #include "filamap.h" #include "filamfix.h" #include "filamdbf.h" -#if defined(ZIP_SUPPORT) -#include "filamzip.h" -#endif // ZIP_SUPPORT +#if defined(GZ_SUPPORT) +#include "filamgz.h" +#endif // GZ_SUPPORT #include "tabdos.h" #include "tabfix.h" #include "tabmul.h" @@ -350,28 +350,28 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) else if (map) txfp = new(g) MPXFAM(this); else if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) txfp = new(g) ZIXFAM(this); -#else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); +#else // !GZ_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; -#endif // !ZIP_SUPPORT +#endif // !GZ_SUPPORT } else txfp = new(g) FIXFAM(this); tdbp = new(g) TDBFIX(this, txfp); } else { if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (Compressed == 1) - txfp = new(g) ZIPFAM(this); + txfp = new(g) GZFAM(this); else txfp = new(g) ZLBFAM(this); -#else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); +#else // !GZ_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; -#endif // !ZIP_SUPPORT +#endif // !GZ_SUPPORT } else if (map) txfp = new(g) MAPFAM(this); else @@ -396,7 +396,7 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) if (map) { txfp = new(g) MBKFAM(this); } else if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (Compressed == 1) txfp = new(g) ZBKFAM(this); else { @@ -404,7 +404,7 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) ((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL); } // endelse #else - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; #endif } else @@ -531,13 +531,13 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) // except for ZLIB access method. if (Txfp->GetAmType() == TYPE_AM_MAP) { Txfp = new(g) MAPFAM((PDOSDEF)To_Def); -#if defined(ZIP_SUPPORT) - } else if (Txfp->GetAmType() == TYPE_AM_ZIP) { - Txfp = new(g) ZIPFAM((PDOSDEF)To_Def); +#if defined(GZ_SUPPORT) + } else if (Txfp->GetAmType() == TYPE_AM_GZ) { + Txfp = new(g) GZFAM((PDOSDEF)To_Def); } else if (Txfp->GetAmType() == TYPE_AM_ZLIB) { Txfp->Reset(); ((PZLBFAM)Txfp)->SetOptimized(false); -#endif // ZIP_SUPPORT +#endif // GZ_SUPPORT } else if (Txfp->GetAmType() == TYPE_AM_BLK) Txfp = new(g) DOSFAM((PDOSDEF)To_Def); @@ -2079,10 +2079,10 @@ bool TDBDOS::OpenDB(PGLOBAL g) /*******************************************************************/ if (Txfp->GetAmType() == TYPE_AM_MAP && Mode == MODE_DELETE) Txfp = new(g) MAPFAM((PDOSDEF)To_Def); -#if defined(ZIP_SUPPORT) - else if (Txfp->GetAmType() == TYPE_AM_ZIP) - Txfp = new(g) ZIPFAM((PDOSDEF)To_Def); -#endif // ZIP_SUPPORT +#if defined(GZ_SUPPORT) + else if (Txfp->GetAmType() == TYPE_AM_GZ) + Txfp = new(g) GZFAM((PDOSDEF)To_Def); +#endif // GZ_SUPPORT else // if (Txfp->GetAmType() != TYPE_AM_DOS) ??? Txfp = new(g) DOSFAM((PDOSDEF)To_Def); diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index c098886f14b..c70e0032f47 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -91,7 +91,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ int Maxerr; /* Maximum number of bad records (DBF) */ int ReadMode; /* Specific to DBF */ int Ending; /* Length of end of lines */ - int Teds; /* Binary table default endian setting */ + char Teds; /* Binary table default endian setting */ }; // end of DOSDEF /***********************************************************************/ diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp index 55c254f41ea..d99f7800f26 100644 --- a/storage/connect/tabfix.cpp +++ b/storage/connect/tabfix.cpp @@ -1,11 +1,11 @@ /************* TabFix C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABFIX */ /* ------------- */ -/* Version 4.9 */ +/* Version 4.9.1 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -589,9 +589,10 @@ void BINCOL::WriteColumn(PGLOBAL g) switch (Fmt) { case 'X': // Standard not converted values - if (Eds && IsTypeChar(Buf_Type)) - *(longlong *)p = Value->GetBigintValue(); - else if (Value->GetBinValue(p, Long, Status)) { + if (Eds && IsTypeChar(Buf_Type)) { + if (Status) + Value->GetValueNonAligned(p, Value->GetBigintValue()); + } else if (Value->GetBinValue(p, Long, Status)) { sprintf(g->Message, MSG(BIN_F_TOO_LONG), Name, Value->GetSize(), Long); longjmp(g->jumper[g->jump_level], 31); @@ -605,7 +606,7 @@ void BINCOL::WriteColumn(PGLOBAL g) sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name); longjmp(g->jumper[g->jump_level], 31); } else if (Status) - *(short *)p = (short)n; + Value->GetValueNonAligned(p, (short)n); break; case 'T': // Tiny integer @@ -625,7 +626,7 @@ void BINCOL::WriteColumn(PGLOBAL g) sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name); longjmp(g->jumper[g->jump_level], 31); } else if (Status) - *(int *)p = Value->GetIntValue(); + Value->GetValueNonAligned(p, (int)n); break; case 'G': // Large (great) integer @@ -636,12 +637,12 @@ void BINCOL::WriteColumn(PGLOBAL g) case 'F': // Float case 'R': // Real if (Status) - *(float *)p = (float)Value->GetFloatValue(); + Value->GetValueNonAligned(p, (float)Value->GetFloatValue()); break; case 'D': // Double if (Status) - *(double *)p = Value->GetFloatValue(); + Value->GetValueNonAligned(p, Value->GetFloatValue()); break; case 'C': // Characters diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index d21a8b977da..4a39ecd6e0f 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -1,11 +1,11 @@ /************* TabFmt C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABFMT */ /* ------------- */ -/* Version 3.9 */ +/* Version 3.9.1 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 2001 - 2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2001 - 2016 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -51,9 +51,9 @@ #include "plgdbsem.h" #include "mycat.h" #include "filamap.h" -#if defined(ZIP_SUPPORT) -#include "filamzip.h" -#endif // ZIP_SUPPORT +#if defined(GZ_SUPPORT) +#include "filamgz.h" +#endif // GZ_SUPPORT #include "tabfmt.h" #include "tabmul.h" #define NO_FUNC @@ -462,16 +462,16 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) // Should be now compatible with UNIX txfp = new(g) MAPFAM(this); } else if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (Compressed == 1) - txfp = new(g) ZIPFAM(this); + txfp = new(g) GZFAM(this); else txfp = new(g) ZLBFAM(this); -#else // !ZIP_SUPPORT +#else // !GZ_SUPPORT strcpy(g->Message, "Compress not supported"); return NULL; -#endif // !ZIP_SUPPORT +#endif // !GZ_SUPPORT } else txfp = new(g) DOSFAM(this); @@ -498,7 +498,7 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) if (map) { txfp = new(g) MBKFAM(this); } else if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (Compressed == 1) txfp = new(g) ZBKFAM(this); else { @@ -506,7 +506,7 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) ((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL); } // endelse #else - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; #endif } else diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 17260836371..5f864f0bd48 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1,6 +1,6 @@ /************* tabjson C++ Program Source Code File (.CPP) *************/ -/* PROGRAM NAME: tabjson Version 1.1 */ -/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */ +/* PROGRAM NAME: tabjson Version 1.2 */ +/* (C) Copyright to the author Olivier BERTRAND 2014 - 2016 */ /* This program are the JSON class DB execution routines. */ /***********************************************************************/ @@ -25,9 +25,9 @@ //#include "resource.h" // for IDS_COLUMNS #include "tabjson.h" #include "filamap.h" -#if defined(ZIP_SUPPORT) -#include "filamzip.h" -#endif // ZIP_SUPPORT +#if defined(GZ_SUPPORT) +#include "filamgz.h" +#endif // GZ_SUPPORT #include "tabmul.h" #include "checklvl.h" #include "resource.h" @@ -396,15 +396,15 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) (m == MODE_UPDATE || m == MODE_DELETE)); if (Compressed) { -#if defined(ZIP_SUPPORT) +#if defined(GZ_SUPPORT) if (Compressed == 1) - txfp = new(g) ZIPFAM(this); + txfp = new(g) GZFAM(this); else txfp = new(g) ZLBFAM(this); -#else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); +#else // !GZ_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; -#endif // !ZIP_SUPPORT +#endif // !GZ_SUPPORT } else if (map) txfp = new(g) MAPFAM(this); else diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 64d0e13e8c4..ced690e77c0 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -1,7 +1,7 @@ /************* Value C++ Functions Source Code File (.CPP) *************/ -/* Name: VALUE.CPP Version 2.5 */ +/* Name: VALUE.CPP Version 2.6 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2001-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2001-2016 */ /* */ /* This file contains the VALUE and derived classes family functions. */ /* These classes contain values of different types. They are used so */ @@ -792,19 +792,29 @@ uchar TYPVAL::GetTypedValue(PVBLK blk, int n) /***********************************************************************/ /* TYPVAL SetBinValue: with bytes extracted from a line. */ +/* Currently only used reading column of binary files. */ /***********************************************************************/ template void TYPVAL::SetBinValue(void *p) - { - Tval = *(TYPE *)p; - Null = false; - } // end of SetBinValue +{ +#if defined(UNALIGNED_OK) + // x86 can cast non-aligned memory directly + Tval = *(TYPE *)p; +#else + // Prevent unaligned memory access on MIPS and ArmHF platforms. + // Make use of memcpy instead of straight pointer dereferencing. + // Currently only used by WriteColumn of binary files. + // From original author: Vicentiu Ciorbaru + memcpy(&Tval, p, sizeof(TYPE)); +#endif + Null = false; +} // end of SetBinValue /***********************************************************************/ /* GetBinValue: fill a buffer with the internal binary value. */ /* This function checks whether the buffer length is enough and */ /* returns true if not. Actual filling occurs only if go is true. */ -/* Currently used by WriteColumn of binary files. */ +/* Currently only used writing column of binary files. */ /***********************************************************************/ template bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) @@ -819,7 +829,16 @@ bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) //#endif if (go) - *(TYPE *)buf = Tval; +#if defined(UNALIGNED_OK) + // x86 can cast non-aligned memory directly + *(TYPE *)buf = Tval; +#else + // Prevent unaligned memory access on MIPS and ArmHF platforms. + // Make use of memcpy instead of straight pointer dereferencing. + // Currently only used by WriteColumn of binary files. + // From original author: Vicentiu Ciorbaru + memcpy(buf, &Tval, sizeof(TYPE)); +#endif Null = false; return false; diff --git a/storage/connect/value.h b/storage/connect/value.h index c5a381e89da..a670ade4c28 100644 --- a/storage/connect/value.h +++ b/storage/connect/value.h @@ -1,7 +1,7 @@ /**************** Value H Declares Source Code File (.H) ***************/ -/* Name: VALUE.H Version 2.1 */ +/* Name: VALUE.H Version 2.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */ +/* (C) Copyright to the author Olivier BERTRAND 2001-2016 */ /* */ /* This file contains the VALUE and derived classes declares. */ /***********************************************************************/ @@ -16,6 +16,13 @@ #include "assert.h" #include "block.h" +/***********************************************************************/ +/* This should list the processors accepting unaligned numeral values.*/ +/***********************************************************************/ +#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(_M_IA64) +#define UNALIGNED_OK +#endif + /***********************************************************************/ /* Types used in some class definitions. */ /***********************************************************************/ @@ -116,27 +123,46 @@ class DllExport VALUE : public BLOCK { virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op); virtual bool FormatValue(PVAL vp, char *fmt) = 0; - /** - Set value from a non-aligned in-memory value in the machine byte order. - TYPE can be either of: - - int, short, longlong - - uint, ushort, ulonglong - - float, double - @param - a pointer to a non-aligned value of type TYPE. - */ - template - void SetValueNonAligned(const char *p) - { -#if defined(__i386__) || defined(__x86_64__) - SetValue(*((TYPE*) p)); // x86 can cast non-aligned memory directly + /** + Set value from a non-aligned in-memory value in the machine byte order. + TYPE can be either of: + - int, short, longlong + - uint, ushort, ulonglong + - float, double + @param - a pointer to a non-aligned value of type TYPE. + */ + template + void SetValueNonAligned(const char *p) + { +#if defined(UNALIGNED_OK) + SetValue(*((TYPE*)p)); // x86 can cast non-aligned memory directly #else - TYPE tmp; // a slower version for non-x86 platforms - memcpy(&tmp, p, sizeof(tmp)); - SetValue(tmp); + TYPE tmp; // a slower version for non-x86 platforms + memcpy(&tmp, p, sizeof(tmp)); + SetValue(tmp); #endif - } + } // end of SetValueNonAligned - protected: + /** + Get value from a non-aligned in-memory value in the machine byte order. + TYPE can be either of: + - int, short, longlong + - uint, ushort, ulonglong + - float, double + @params - a pointer to a non-aligned value of type TYPE, the TYPE value. + */ + template + void GetValueNonAligned(char *p, TYPE n) + { +#if defined(UNALIGNED_OK) + *(TYPE *)p = n; // x86 can cast non-aligned memory directly +#else + TYPE tmp = n; // a slower version for non-x86 platforms + memcpy(p, &tmp, sizeof(tmp)); +#endif + } // end of SetValueNonAligned + +protected: virtual bool SetConstFormat(PGLOBAL, FORMAT&) = 0; const char *GetXfmt(void); From 55b4579633ec81481823b3dfaa45674db6416a50 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 5 Dec 2016 16:28:29 -0500 Subject: [PATCH 036/124] Fix build failure. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 11613fac026..53350751d79 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2643,7 +2643,7 @@ mysql_execute_command(THD *thd) !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && !(lex->sql_command == SQLCOM_SELECT && - !all_table) && + !all_tables) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, From e156ea1b9517dd155f68f8d683704ecf5370346a Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 9 Dec 2016 12:15:41 -0500 Subject: [PATCH 037/124] Fix failing tests. --- .../suite/galera/r/galera_split_brain.result | 1 - .../r/galera_var_cluster_address.result | 36 ++++------ .../galera/r/galera_var_dirty_reads.result | 15 ++-- mysql-test/suite/galera/suite.pm | 1 + .../suite/galera/t/galera_split_brain.test | 5 +- .../galera/t/galera_var_cluster_address.test | 72 +++++++------------ .../galera/t/galera_var_dirty_reads.test | 12 +++- 7 files changed, 59 insertions(+), 83 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result index 615615040fe..6473f95735b 100644 --- a/mysql-test/suite/galera/r/galera_split_brain.result +++ b/mysql-test/suite/galera/r/galera_split_brain.result @@ -2,4 +2,3 @@ call mtr.add_suppression("WSREP: TO isolation failed for: "); Killing server ... CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -SET GLOBAL wsrep_cluster_address = ''; diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result index f8bd869f8fe..17b5a7bca37 100644 --- a/mysql-test/suite/galera/r/galera_var_cluster_address.result +++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result @@ -1,6 +1,6 @@ SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; +SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; ERROR 08S01: WSREP has not yet prepared node for application use SHOW STATUS LIKE 'wsrep_ready'; Variable_name Value @@ -20,32 +20,20 @@ VARIABLE_VALUE = 1 SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' 1 -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -VARIABLE_VALUE = 'Primary' -1 -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 2 -1 -SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1'; -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; -ERROR 08S01: WSREP has not yet prepared node for application use -SHOW STATUS LIKE 'wsrep_ready'; -Variable_name Value -wsrep_ready OFF -SHOW STATUS LIKE 'wsrep_cluster_status'; -Variable_name Value -wsrep_cluster_status non-Primary -SHOW STATUS LIKE 'wsrep_local_state'; -Variable_name Value -wsrep_local_state 0 -SHOW STATUS LIKE 'wsrep_local_state_comment'; -Variable_name Value -wsrep_local_state_comment Initialized -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' 1 SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 2 1 +CALL mtr.add_suppression("Backend not supported: foo"); +CALL mtr.add_suppression("Failed to initialize backend using 'foo"); +CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo"); +CALL mtr.add_suppression("gcs connect failed: Socket type not supported"); +CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7"); +CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)"); +CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110"); +CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)"); +CALL mtr.add_suppression("gcs connect failed: Connection timed out"); +CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7"); +# End of test diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index 6a2aa1eb5e7..c0ffb2d4860 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -18,19 +18,22 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; i 1 +# +# MDEV-11016: wsrep_node_is_ready() check is too strict +# SET @@session.wsrep_dirty_reads=OFF; SELECT 2; 2 2 -SELECT @@max_allowed_packet; -@@max_allowed_packet -4194304 SELECT 2+2 from DUAL; 2+2 4 -SELECT sysdate() from DUAL; -sysdate() -2016-10-28 23:13:06 +SET @VAR=1; +SELECT @VAR; +@VAR +1 +SELECT @@max_allowed_packet; +SELECT SYSDATE() from DUAL; SELECT * FROM t1; i 1 diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm index d6cd4273014..5b69ff26615 100644 --- a/mysql-test/suite/galera/suite.pm +++ b/mysql-test/suite/galera/suite.pm @@ -68,6 +68,7 @@ push @::global_suppressions, qr|WSREP: gcs_caused\(\) returned .*|, qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(SYNCED\). Message ignored.|, qr(WSREP: Action message in non-primary configuration from member [0-9]*), + qr(WSREP: discarding established .*), ); diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test index 22f6370241c..a85a2ad9b8d 100644 --- a/mysql-test/suite/galera/t/galera_split_brain.test +++ b/mysql-test/suite/galera/t/galera_split_brain.test @@ -25,11 +25,8 @@ CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; # Reset the master and restart the slave so that post-test checks can run -SET GLOBAL wsrep_cluster_address = ''; ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig'; ---enable_query_log +--connection node_2 --source include/start_mysqld.inc --sleep 5 --source include/wait_until_connected_again.inc diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test index 17e77a9b5af..740c38765f6 100644 --- a/mysql-test/suite/galera/t/galera_var_cluster_address.test +++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test @@ -5,12 +5,17 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + # # Set to invalid value # ---connection node_1 ---let $wsrep_cluster_address_node1 = `SELECT @@wsrep_cluster_address` +--connection node_2 +--let $wsrep_cluster_address_node2 = `SELECT @@wsrep_cluster_address` SET GLOBAL wsrep_cluster_address = 'foo://'; # With wsrep_sync_wait, this returns an error @@ -20,7 +25,7 @@ SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; --error ER_UNKNOWN_COM_ERROR -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; +SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; # Must return 'OFF' SHOW STATUS LIKE 'wsrep_ready'; @@ -32,9 +37,9 @@ SHOW STATUS LIKE 'wsrep_cluster_status'; SHOW STATUS LIKE 'wsrep_local_state'; SHOW STATUS LIKE 'wsrep_local_state_comment'; ---connection node_2 +--connection node_1 --sleep 1 -# Node #2 thinks that it is now part of a single-node primary cluster +# Node #1 thinks that it is now part of a single-node primary cluster SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; @@ -42,13 +47,10 @@ SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VA # Reset everything as it was # ---connection node_1 ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1'; ---enable_query_log - --connection node_2 -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; +--disable_query_log +--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node2'; +--enable_query_log --source include/wait_until_connected_again.inc @@ -56,40 +58,20 @@ SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -# -# Set to invalid host -# - ---connection node_1 -SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1'; - ---error ER_UNKNOWN_COM_ERROR -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; - -# Must return 'OFF' -SHOW STATUS LIKE 'wsrep_ready'; - -# Must return 'Non-primary' -SHOW STATUS LIKE 'wsrep_cluster_status'; - -# Must return 0 = 'Initialized' -SHOW STATUS LIKE 'wsrep_local_state'; -SHOW STATUS LIKE 'wsrep_local_state_comment'; - -# -# Reset everything as it was -# - ---connection node_1 ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1'; ---enable_query_log - --connection node_2 -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; ---sleep 1 +CALL mtr.add_suppression("Backend not supported: foo"); +CALL mtr.add_suppression("Failed to initialize backend using 'foo"); +CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo"); +CALL mtr.add_suppression("gcs connect failed: Socket type not supported"); +CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7"); +CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)"); +CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110"); +CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)"); +CALL mtr.add_suppression("gcs connect failed: Connection timed out"); +CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7"); ---connection node_1 -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +# Restore original auto_increment_offset values. +--source include/auto_increment_offset_restore.inc +--source include/galera_end.inc +--echo # End of test diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index 0c81779ca65..7a76a71a265 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -36,12 +36,18 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; -#Select query which does not access table should be allowed MDEV-11016 +--echo # +--echo # MDEV-11016: wsrep_node_is_ready() check is too strict +--echo # SET @@session.wsrep_dirty_reads=OFF; SELECT 2; -SELECT @@max_allowed_packet; SELECT 2+2 from DUAL; -SELECT sysdate() from DUAL; +SET @VAR=1; +SELECT @VAR; +--disable_result_log +SELECT @@max_allowed_packet; +SELECT SYSDATE() from DUAL; +--enable_result_log --disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' From 14e1f32894cdbe63a614738cfd93e9d0818dedee Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Sun, 11 Dec 2016 00:50:00 +0200 Subject: [PATCH 038/124] Follow-up for 02d153c7b9 (str2decimal: don't return a negative zero) --- mysql-test/suite/engines/iuds/r/insert_decimal.result | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/engines/iuds/r/insert_decimal.result b/mysql-test/suite/engines/iuds/r/insert_decimal.result index 50fde80d81d..eab8592c4ee 100644 --- a/mysql-test/suite/engines/iuds/r/insert_decimal.result +++ b/mysql-test/suite/engines/iuds/r/insert_decimal.result @@ -48,7 +48,6 @@ Warning 1264 Out of range value for column 'c2' at row 1 Note 1265 Data truncated for column 'c3' at row 1 insert into t2 values ("0.0","0.0","0.0",7),("-0.0","-0.0","-0.0",8),("+0.0","+0.0","+0.0",9),("01.0","01.0","01.0",10),("+01.0","+01.0","+01.0",11),("-01.0","-01.0","-01.0",12); Warnings: -Warning 1264 Out of range value for column 'c2' at row 2 Warning 1264 Out of range value for column 'c2' at row 6 insert into t2 values ("-.1","-.1","-.1",13),("+.1","+.1","+.1",14),(".1",".1",".1",15); Warnings: From d44723e62153d9fb4165d038e9448c20a3ad890b Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Mon, 12 Dec 2016 10:57:19 +0100 Subject: [PATCH 039/124] - MDEV-11295: developing handling files contained in ZIP file. A first experimental and limited implementation. modified: storage/connect/CMakeLists.txt modified: storage/connect/filamap.cpp new file: storage/connect/filamzip.cpp new file: storage/connect/filamzip.h modified: storage/connect/ha_connect.cc new file: storage/connect/ioapi.c new file: storage/connect/ioapi.h modified: storage/connect/mycat.cc modified: storage/connect/plgdbsem.h modified: storage/connect/plgdbutl.cpp modified: storage/connect/tabdos.cpp modified: storage/connect/tabdos.h modified: storage/connect/tabfmt.cpp modified: storage/connect/tabfmt.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h new file: storage/connect/tabzip.cpp new file: storage/connect/tabzip.h new file: storage/connect/unzip.c new file: storage/connect/unzip.h new file: storage/connect/zip.c --- storage/connect/CMakeLists.txt | 12 + storage/connect/filamap.cpp | 6 +- storage/connect/filamzip.cpp | 501 ++++++++ storage/connect/filamzip.h | 83 ++ storage/connect/ha_connect.cc | 27 +- storage/connect/ioapi.c | 247 ++++ storage/connect/ioapi.h | 208 ++++ storage/connect/mycat.cc | 16 +- storage/connect/plgdbsem.h | 15 +- storage/connect/plgdbutl.cpp | 14 +- storage/connect/tabdos.cpp | 36 +- storage/connect/tabdos.h | 6 +- storage/connect/tabfmt.cpp | 168 ++- storage/connect/tabfmt.h | 29 +- storage/connect/tabjson.cpp | 72 +- storage/connect/tabjson.h | 3 +- storage/connect/tabzip.cpp | 230 ++++ storage/connect/tabzip.h | 100 ++ storage/connect/unzip.c | 2125 ++++++++++++++++++++++++++++++++ storage/connect/unzip.h | 437 +++++++ storage/connect/zip.c | 2007 ++++++++++++++++++++++++++++++ storage/connect/zip.h | 362 ++++++ 22 files changed, 6579 insertions(+), 125 deletions(-) create mode 100644 storage/connect/filamzip.cpp create mode 100644 storage/connect/filamzip.h create mode 100644 storage/connect/ioapi.c create mode 100644 storage/connect/ioapi.h create mode 100644 storage/connect/tabzip.cpp create mode 100644 storage/connect/tabzip.h create mode 100644 storage/connect/unzip.c create mode 100644 storage/connect/unzip.h create mode 100644 storage/connect/zip.c create mode 100644 storage/connect/zip.h diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index f1567730b26..ce6de424421 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -279,6 +279,18 @@ IF(CONNECT_WITH_JDBC) ENDIF() ENDIF(CONNECT_WITH_JDBC) +# +# ZIP +# + +OPTION(CONNECT_WITH_ZIP "Compile CONNECT storage engine with ZIP support" ON) + +IF(CONNECT_WITH_ZIP) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} filamzip.cpp tabzip.cpp unzip.c ioapi.c zip.c + filamzip.h tabzip.h ioapi.h unzip.h zip.h) + add_definitions(-DZIP_SUPPORT -DNOCRYPT) +ENDIF(CONNECT_WITH_ZIP) + # # XMAP diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 5cf9a4d945c..3c5b3ae7592 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -87,7 +87,7 @@ int MAPFAM::GetFileLength(PGLOBAL g) { int len; - len = (To_Fb) ? To_Fb->Length : TXTFAM::GetFileLength(g); + len = (To_Fb && To_Fb->Count) ? To_Fb->Length : TXTFAM::GetFileLength(g); if (trace) htrc("Mapped file length=%d\n", len); @@ -413,7 +413,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) if (Tpos == Spos) { /*******************************************************************/ - /* First line to delete. Move of eventual preceeding lines is */ + /* First line to delete. Move of eventual preceding lines is */ /* not required here, just setting of future Spos and Tpos. */ /*******************************************************************/ Tpos = Spos = Fpos; @@ -498,7 +498,7 @@ int MAPFAM::DeleteRecords(PGLOBAL g, int irc) void MAPFAM::CloseTableFile(PGLOBAL g, bool) { PlugCloseFile(g, To_Fb); - To_Fb = NULL; // To get correct file size in Cardinality +//To_Fb = NULL; // To get correct file size in Cardinality if (trace) htrc("MAP Close: closing %s count=%d\n", diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp new file mode 100644 index 00000000000..ea8b827974b --- /dev/null +++ b/storage/connect/filamzip.cpp @@ -0,0 +1,501 @@ +/*********** File AM Zip C++ Program Source Code File (.CPP) ***********/ +/* PROGRAM NAME: FILAMZIP */ +/* ------------- */ +/* Version 1.0 */ +/* */ +/* COPYRIGHT: */ +/* ---------- */ +/* (C) Copyright to the author Olivier BERTRAND 2016 */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the ZIP file access method classes. */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the System header files. */ +/***********************************************************************/ +#include "my_global.h" +#if !defined(__WIN__) +#if defined(UNIX) +#include +#include +#else // !UNIX +#include +#endif // !UNIX +#include +#endif // !__WIN__ + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "osutil.h" +#include "filamtxt.h" +#include "tabfmt.h" +//#include "tabzip.h" +#include "filamzip.h" + +/* -------------------------- class ZIPFAM --------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) +{ + zipfile = NULL; + zfn = tdp->Zipfn; + target = tdp->Fn; +//*fn = 0; + entryopen = false; + multiple = tdp->Multiple; + + // Init the case mapping table. +#if defined(__WIN__) + for (int i = 0; i < 256; ++i) mapCaseTable[i] = toupper(i); +#else + for (int i = 0; i < 256; ++i) mapCaseTable[i] = i; +#endif +} // end of ZIPFAM standard constructor + +ZIPFAM::ZIPFAM(PZIPFAM txfp) : MAPFAM(txfp) +{ + zipfile = txfp->zipfile; + zfn = txfp->zfn; + target = txfp->target; +//strcpy(fn, txfp->fn); + finfo = txfp->finfo; + entryopen = txfp->entryopen; + multiple = txfp->multiple; + for (int i = 0; i < 256; ++i) mapCaseTable[i] = txfp->mapCaseTable[i]; +} // end of ZIPFAM copy constructor + +/***********************************************************************/ +/* This code is the copyright property of Alessandro Felice Cantatore. */ +/* http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html */ +/***********************************************************************/ +bool ZIPFAM::WildMatch(PSZ pat, PSZ str) { + PSZ s, p; + bool star = FALSE; + + loopStart: + for (s = str, p = pat; *s; ++s, ++p) { + switch (*p) { + case '?': + if (*s == '.') goto starCheck; + break; + case '*': + star = TRUE; + str = s, pat = p; + if (!*++pat) return TRUE; + goto loopStart; + default: + if (mapCaseTable[*s] != mapCaseTable[*p]) + goto starCheck; + break; + } /* endswitch */ + } /* endfor */ + if (*p == '*') ++p; + return (!*p); + + starCheck: + if (!star) return FALSE; + str++; + goto loopStart; +} // end of WildMatch + +/***********************************************************************/ +/* ZIP GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int ZIPFAM::GetFileLength(PGLOBAL g) +{ + int len = (entryopen) ? Top - Memory : 100; // not 0 to avoid ASSERT + + if (trace) + htrc("Zipped file length=%d\n", len); + + return len; +} // end of GetFileLength + +/***********************************************************************/ +/* open a zip file. */ +/* param: filename path and the filename of the zip file to open. */ +/* return: true if open, false otherwise. */ +/***********************************************************************/ +bool ZIPFAM::open(PGLOBAL g, const char *filename) +{ + if (!zipfile && !(zipfile = unzOpen64(filename))) + sprintf(g->Message, "Zipfile open error"); + + return (zipfile == NULL); +} // end of open + +/***********************************************************************/ +/* Close the zip file. */ +/***********************************************************************/ +void ZIPFAM::close() +{ + if (zipfile) { + closeEntry(); + unzClose(zipfile); + zipfile = NULL; + } // endif zipfile + +} // end of close + +/***********************************************************************/ +/* Find next entry matching target pattern. */ +/***********************************************************************/ +int ZIPFAM::findEntry(PGLOBAL g, bool next) +{ + int rc; + char fn[FILENAME_MAX]; // The current entry file name + + do { + if (next) { + rc = unzGoToNextFile(zipfile); + + if (rc == UNZ_END_OF_LIST_OF_FILE) + return RC_EF; + else if (rc != UNZ_OK) { + sprintf(g->Message, "unzGoToNextFile rc = ", rc); + return RC_FX; + } // endif rc + + } // endif next + + if (target && *target) { + rc = unzGetCurrentFileInfo(zipfile, NULL, fn, sizeof(fn), + NULL, 0, NULL, 0); + if (rc == UNZ_OK) { + if (WildMatch(target, fn)) + return RC_OK; + + } else { + sprintf(g->Message, "GetCurrentFileInfo rc = %d", rc); + return RC_FX; + } // endif rc + + } else + return RC_OK; + + next = true; + } while (true); + + strcpy(g->Message, "FindNext logical error"); + return RC_FX; +} // end of FindNext + +/***********************************************************************/ +/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ +/***********************************************************************/ +bool ZIPFAM::OpenTableFile(PGLOBAL g) +{ + char filename[_MAX_PATH]; + MODE mode = Tdbp->GetMode(); + PFBLOCK fp; + PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; + + /*********************************************************************/ + /* The file will be decompressed into virtual memory. */ + /*********************************************************************/ + if (mode == MODE_READ) { + // We used the file name relative to recorded datapath + PlugSetPath(filename, zfn, Tdbp->GetPath()); + + bool b = open(g, filename); + + if (!b) { + int rc; + + if (target && *target) { + if (!multiple) { + rc = unzLocateFile(zipfile, target, 0); + + if (rc == UNZ_END_OF_LIST_OF_FILE) { + sprintf(g->Message, "Target file %s not in %s", target, filename); + return true; + } else if (rc != UNZ_OK) { + sprintf(g->Message, "unzLocateFile rc=%d", rc); + return true; + } // endif's rc + + } else { + if ((rc = findEntry(g, false)) == RC_FX) + return true; + else if (rc == RC_NF) { + sprintf(g->Message, "No match of %s in %s", target, filename); + return true; + } // endif rc + + } // endif multiple + + } // endif target + + if (openEntry(g)) + return true; + + if (Top > Memory) { + /*******************************************************************/ + /* Link a Fblock. This make possible to automatically close it */ + /* in case of error g->jump. */ + /*******************************************************************/ + fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); + fp->Type = TYPE_FB_ZIP; + fp->Fname = PlugDup(g, filename); + fp->Next = dbuserp->Openlist; + dbuserp->Openlist = fp; + fp->Count = 1; + fp->Length = Top - Memory; + fp->Memory = Memory; + fp->Mode = mode; + fp->File = this; + fp->Handle = NULL; + } // endif fp + + To_Fb = fp; // Useful when closing + } // endif b + + } else { + strcpy(g->Message, "Only READ mode supported for ZIP files"); + return true; + } // endif mode + + return false; + } // end of OpenTableFile + +/***********************************************************************/ +/* Open target in zip file. */ +/***********************************************************************/ +bool ZIPFAM::openEntry(PGLOBAL g) +{ + int rc; + uint size; + + rc = unzGetCurrentFileInfo(zipfile, &finfo, 0, 0, 0, 0, 0, 0); + + if (rc != UNZ_OK) { + sprintf(g->Message, "unzGetCurrentFileInfo64 rc=%d", rc); + return true; + } else if ((rc = unzOpenCurrentFile(zipfile)) != UNZ_OK) { + sprintf(g->Message, "unzOpenCurrentFile rc=%d", rc); + return true; + } // endif rc + + size = finfo.uncompressed_size; + Memory = new char[size]; + + if ((rc = unzReadCurrentFile(zipfile, Memory, size)) < 0) { + sprintf(g->Message, "unzReadCurrentFile rc = ", rc); + unzCloseCurrentFile(zipfile); + free(Memory); + entryopen = false; + } else { + // The pseudo "buffer" is here the entire real buffer + Fpos = Mempos = Memory; + Top = Memory + size; + + if (trace) + htrc("Memory=%p size=%ud Top=%p\n", Memory, size, Top); + + entryopen = true; + } // endif rc + + return !entryopen; +} // end of openEntry + +/***********************************************************************/ +/* Close the zip file. */ +/***********************************************************************/ +void ZIPFAM::closeEntry() +{ + if (entryopen) { + unzCloseCurrentFile(zipfile); + entryopen = false; + } // endif entryopen + + if (Memory) { + free(Memory); + Memory = NULL; + } // endif Memory + +} // end of closeEntry + +/***********************************************************************/ +/* ReadBuffer: Read one line for a ZIP file. */ +/***********************************************************************/ +int ZIPFAM::ReadBuffer(PGLOBAL g) +{ + int rc, len; + + // Are we at the end of the memory + if (Mempos >= Top) { + if (multiple) { + closeEntry(); + + if ((rc = findEntry(g, true)) != RC_OK) + return rc; + + if (openEntry(g)) + return RC_FX; + + } else + return RC_EF; + + } // endif Mempos + +#if 0 + if (!Placed) { + /*******************************************************************/ + /* Record file position in case of UPDATE or DELETE. */ + /*******************************************************************/ + int rc; + + next: + Fpos = Mempos; + CurBlk = (int)Rows++; + + /*******************************************************************/ + /* Check whether optimization on ROWID */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + // Skip this record + if ((rc = SkipRecord(g, false)) != RC_OK) + return rc; + + goto next; + } // endswitch rc + + } else + Placed = false; +#else + // Perhaps unuseful + Fpos = Mempos; + CurBlk = (int)Rows++; + Placed = false; +#endif + + // Immediately calculate next position (Used by DeleteDB) + while (*Mempos++ != '\n'); // What about Unix ??? + + // Set caller line buffer + len = (Mempos - Fpos) - 1; + + // Don't rely on ENDING setting + if (len > 0 && *(Mempos - 2) == '\r') + len--; // Line ends by CRLF + + memcpy(Tdbp->GetLine(), Fpos, len); + Tdbp->GetLine()[len] = '\0'; + return RC_OK; +} // end of ReadBuffer + +#if 0 +/***********************************************************************/ +/* Table file close routine for MAP access method. */ +/***********************************************************************/ +void ZIPFAM::CloseTableFile(PGLOBAL g, bool) +{ + close(); +} // end of CloseTableFile +#endif // 0 + +/* -------------------------- class ZPXFAM --------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +ZPXFAM::ZPXFAM(PDOSDEF tdp) : ZIPFAM(tdp) +{ + Lrecl = tdp->GetLrecl(); +} // end of ZPXFAM standard constructor + +ZPXFAM::ZPXFAM(PZPXFAM txfp) : ZIPFAM(txfp) +{ + Lrecl = txfp->Lrecl; +} // end of ZPXFAM copy constructor + +/***********************************************************************/ +/* ReadBuffer: Read one line for a fixed ZIP file. */ +/***********************************************************************/ +int ZPXFAM::ReadBuffer(PGLOBAL g) +{ + int rc, len; + + // Are we at the end of the memory + if (Mempos >= Top) { + if (multiple) { + closeEntry(); + + if ((rc = findEntry(g, true)) != RC_OK) + return rc; + + if (openEntry(g)) + return RC_FX; + + } else + return RC_EF; + + } // endif Mempos + +#if 0 + if (!Placed) { + /*******************************************************************/ + /* Record file position in case of UPDATE or DELETE. */ + /*******************************************************************/ + int rc; + + next: + Fpos = Mempos; + CurBlk = (int)Rows++; + + /*******************************************************************/ + /* Check whether optimization on ROWID */ + /* can be done, as well as for join as for local filtering. */ + /*******************************************************************/ + switch (Tdbp->TestBlock(g)) { + case RC_EF: + return RC_EF; + case RC_NF: + // Skip this record + if ((rc = SkipRecord(g, false)) != RC_OK) + return rc; + + goto next; + } // endswitch rc + + } else + Placed = false; +#else + // Perhaps unuseful + Fpos = Mempos; + CurBlk = (int)Rows++; + Placed = false; +#endif + + // Immediately calculate next position (Used by DeleteDB) + Mempos += Lrecl; + + // Set caller line buffer + len = Lrecl; + + // Don't rely on ENDING setting + if (len > 0 && *(Mempos - 1) == '\n') + len--; // Line ends by LF + + if (len > 0 && *(Mempos - 2) == '\r') + len--; // Line ends by CRLF + + memcpy(Tdbp->GetLine(), Fpos, len); + Tdbp->GetLine()[len] = '\0'; + return RC_OK; +} // end of ReadBuffer + diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h new file mode 100644 index 00000000000..85c1f907d20 --- /dev/null +++ b/storage/connect/filamzip.h @@ -0,0 +1,83 @@ +/************** filamzip H Declares Source Code File (.H) **************/ +/* Name: filamzip.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2016 */ +/* */ +/* This file contains the ZIP file access method classes declares. */ +/***********************************************************************/ +#ifndef __FILAMZIP_H +#define __FILAMZIP_H + +#include "block.h" +#include "filamap.h" +#include "unzip.h" + +#define DLLEXPORT extern "C" + +typedef class ZIPFAM *PZIPFAM; +typedef class ZPXFAM *PZPXFAM; + +/***********************************************************************/ +/* This is the ZIP file access method. */ +/***********************************************************************/ +class DllExport ZIPFAM : public MAPFAM { +public: + // Constructor + ZIPFAM(PDOSDEF tdp); + ZIPFAM(PZIPFAM txfp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_ZIP;} + virtual PTXF Duplicate(PGLOBAL g) {return (PTXF) new(g) ZIPFAM(this);} + + // Methods + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g) {return (g) ? 10 : 1;} +//virtual int MaxBlkSize(PGLOBAL g, int s) {return s;} + virtual bool OpenTableFile(PGLOBAL g); + virtual bool DeferReading(void) {return false;} + virtual int ReadBuffer(PGLOBAL g); +//virtual int WriteBuffer(PGLOBAL g); +//virtual int DeleteRecords(PGLOBAL g, int irc); +//virtual void CloseTableFile(PGLOBAL g, bool abort); + void close(void); + +protected: + bool open(PGLOBAL g, const char *filename); + bool openEntry(PGLOBAL g); + void closeEntry(void); + bool WildMatch(PSZ pat, PSZ str); + int findEntry(PGLOBAL g, bool next); + + // Members + unzFile zipfile; // The ZIP container file + PSZ zfn; // The ZIP file name + PSZ target; // The target file name + unz_file_info finfo; // The current file info +//char fn[FILENAME_MAX]; // The current file name + bool entryopen; // True when open current entry + int multiple; // Multiple targets + char mapCaseTable[256]; +}; // end of ZIPFAM + +/***********************************************************************/ +/* This is the fixed ZIP file access method. */ +/***********************************************************************/ +class DllExport ZPXFAM : public ZIPFAM { +public: + // Constructor + ZPXFAM(PDOSDEF tdp); + ZPXFAM(PZPXFAM txfp); + + // Implementation + virtual PTXF Duplicate(PGLOBAL g) {return (PTXF) new(g) ZPXFAM(this);} + + // Methods + virtual int ReadBuffer(PGLOBAL g); + +protected: + // Members + int Lrecl; +}; // end of ZPXFAM + +#endif // __FILAMZIP_H diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 2222e51b083..b690dff24f4 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -171,9 +171,9 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.04.0008 October 20, 2016"; + char version[]= "Version 1.04.0009 December 09, 2016"; #if defined(__WIN__) - char compver[]= "Version 1.04.0008 " __DATE__ " " __TIME__; + char compver[]= "Version 1.04.0009 " __DATE__ " " __TIME__; char slash= '\\'; #else // !__WIN__ char slash= '/'; @@ -4165,7 +4165,8 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_DIR: case TAB_MAC: case TAB_WMI: - case TAB_OEM: + case TAB_ZIP: + case TAB_OEM: #ifdef NO_EMBEDDED_ACCESS_CHECKS return false; #endif @@ -5173,13 +5174,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd, char v=0, spc= ',', qch= 0; const char *fncn= "?"; const char *user, *fn, *db, *host, *pwd, *sep, *tbl, *src; - const char *col, *ocl, *rnk, *pic, *fcl, *skc; + const char *col, *ocl, *rnk, *pic, *fcl, *skc, *zfn; char *tab, *dsn, *shm, *dpath; #if defined(__WIN__) char *nsp= NULL, *cls= NULL; #endif // __WIN__ - int port= 0, hdr= 0, mxr= 0, mxe= 0, rc= 0; - int cop __attribute__((unused))= 0, lrecl= 0; +//int hdr, mxe; + int port = 0, mxr = 0, rc = 0, mul = 0, lrecl = 0; #if defined(ODBC_SUPPORT) POPARM sop= NULL; char *ucnc= NULL; @@ -5211,7 +5212,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, if (!g) return HA_ERR_INTERNAL_ERROR; - user= host= pwd= tbl= src= col= ocl= pic= fcl= skc= rnk= dsn= NULL; + user= host= pwd= tbl= src= col= ocl= pic= fcl= skc= rnk= zfn= dsn= NULL; // Get the useful create options ttp= GetTypeID(topt->type); @@ -5224,7 +5225,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, sep= topt->separator; spc= (!sep) ? ',' : *sep; qch= topt->qchar ? *topt->qchar : (signed)topt->quoted >= 0 ? '"' : 0; - hdr= (int)topt->header; + mul = (int)topt->multiple; tbl= topt->tablist; col= topt->colist; @@ -5260,11 +5261,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd, // prop = GetListOption(g, "Properties", topt->oplist, NULL); tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); #endif // JDBC_SUPPORT - mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); #if defined(PROMPT_OK) cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); #endif // PROMPT_OK - } else { +#if defined(ZIP_SUPPORT) + zfn = GetListOption(g, "Zipfile", topt->oplist, NULL); +#endif // ZIP_SUPPORT + } else { host= "localhost"; user= (ttp == TAB_ODBC ? NULL : "root"); } // endif option_list @@ -5471,7 +5474,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case TAB_XML: #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_JSON: - if (!fn) + if (!fn && !zfn && !mul) sprintf(g->Message, "Missing %s file name", topt->type); else ok= true; @@ -5585,7 +5588,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, NULL, port, fnc == FNC_COL); break; case TAB_CSV: - qrp= CSVColumns(g, dpath, fn, spc, qch, hdr, mxe, fnc == FNC_COL); + qrp = CSVColumns(g, dpath, topt, fnc == FNC_COL); break; #if defined(__WIN__) case TAB_WMI: diff --git a/storage/connect/ioapi.c b/storage/connect/ioapi.c new file mode 100644 index 00000000000..7f5c191b2af --- /dev/null +++ b/storage/connect/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/storage/connect/ioapi.h b/storage/connect/ioapi.h new file mode 100644 index 00000000000..8dcbdb06e35 --- /dev/null +++ b/storage/connect/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc index 19c9f62b5bf..497fe5e1aa8 100644 --- a/storage/connect/mycat.cc +++ b/storage/connect/mycat.cc @@ -16,7 +16,7 @@ /*************** Mycat CC Program Source Code File (.CC) ***************/ /* PROGRAM NAME: MYCAT */ /* ------------- */ -/* Version 1.4 */ +/* Version 1.5 */ /* */ /* Author: Olivier Bertrand 2012 - 2016 */ /* */ @@ -95,6 +95,9 @@ #if defined(XML_SUPPORT) #include "tabxml.h" #endif // XML_SUPPORT +#if defined(ZIP_SUPPORT) +#include "tabzip.h" +#endif // ZIP_SUPPORT #include "mycat.h" /***********************************************************************/ @@ -154,7 +157,10 @@ TABTYPE GetTypeID(const char *type) #endif : (!stricmp(type, "VIR")) ? TAB_VIR : (!stricmp(type, "JSON")) ? TAB_JSON - : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY; +#ifdef ZIP_SUPPORT + : (!stricmp(type, "ZIP")) ? TAB_ZIP +#endif + : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY; } // end of GetTypeID /***********************************************************************/ @@ -175,6 +181,7 @@ bool IsFileType(TABTYPE type) case TAB_INI: case TAB_VEC: case TAB_JSON: +// case TAB_ZIP: isfile= true; break; default: @@ -575,7 +582,10 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) #endif // PIVOT_SUPPORT case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; - default: +#if defined(ZIP_SUPPORT) + case TAB_ZIP: tdp= new(g) ZIPDEF; break; +#endif // ZIP_SUPPORT + default: sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); } // endswitch diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index e99f5f36444..cb408494319 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -1,9 +1,9 @@ /************** PlgDBSem H Declares Source Code File (.H) **************/ -/* Name: PLGDBSEM.H Version 3.6 */ +/* Name: PLGDBSEM.H Version 3.7 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2016 */ /* */ -/* This file contains the PlugDB++ application type definitions. */ +/* This file contains the CONNECT storage engine definitions. */ /***********************************************************************/ /***********************************************************************/ @@ -49,7 +49,8 @@ enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */ TYPE_FB_MAP = 23, /* Mapped file block (storage) */ TYPE_FB_HANDLE = 24, /* File block (handle) */ TYPE_FB_XML = 21, /* DOM XML file block */ - TYPE_FB_XML2 = 27}; /* libxml2 XML file block */ + TYPE_FB_XML2 = 27, /* libxml2 XML file block */ + TYPE_FB_ZIP = 28}; /* ZIP file block */ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_DOS = 1, /* Fixed column offset, variable LRECL */ @@ -78,7 +79,8 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_JCT = 24, /* Junction tables NIY */ TAB_DMY = 25, /* DMY Dummy tables NIY */ TAB_JDBC = 26, /* Table accessed via JDBC */ - TAB_NIY = 27}; /* Table not implemented yet */ + TAB_ZIP = 27, /* ZIP file info table */ + TAB_NIY = 28}; /* Table not implemented yet */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_ROWID = 1, /* ROWID type (special column) */ @@ -140,7 +142,8 @@ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ TYPE_AM_MYSQL = 192, /* MYSQL access method type no */ TYPE_AM_MYX = 193, /* MYSQL EXEC access method type */ TYPE_AM_CAT = 195, /* Catalog access method type no */ - TYPE_AM_OUT = 200}; /* Output relations (storage) */ + TYPE_AM_ZIP = 198, /* ZIP access method type no */ + TYPE_AM_OUT = 200}; /* Output relations (storage) */ enum RECFM {RECFM_NAF = -2, /* Not a file */ RECFM_OEM = -1, /* OEM file access method */ diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 13c0dfd1e18..31c040c6957 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -68,6 +68,9 @@ #include "tabcol.h" // header of XTAB and COLUMN classes #include "valblk.h" #include "rcmsg.h" +#ifdef ZIP_SUPPORT +#include "filamzip.h" +#endif // ZIP_SUPPORT /***********************************************************************/ /* DB static variables. */ @@ -934,7 +937,16 @@ int PlugCloseFile(PGLOBAL g __attribute__((unused)), PFBLOCK fp, bool all) CloseXML2File(g, fp, all); break; #endif // LIBXML2_SUPPORT - default: +#ifdef ZIP_SUPPORT + case TYPE_FB_ZIP: + ((PZIPFAM)fp->File)->close(); + fp->Memory = NULL; + fp->Mode = MODE_ANY; + fp->Count = 0; + fp->File = NULL; + break; +#endif // ZIP_SUPPORT + default: rc = RC_FX; } // endswitch Type diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 06dde34a27f..9bcac0b5f1a 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -1,7 +1,7 @@ /************* TabDos C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABDOS */ /* ------------- */ -/* Version 4.9.1 */ +/* Version 4.9.2 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -54,6 +54,9 @@ #if defined(GZ_SUPPORT) #include "filamgz.h" #endif // GZ_SUPPORT +#if defined(ZIP_SUPPORT) +#include "filamzip.h" +#endif // ZIP_SUPPORT #include "tabdos.h" #include "tabfix.h" #include "tabmul.h" @@ -93,6 +96,7 @@ DOSDEF::DOSDEF(void) Pseudo = 3; Fn = NULL; Ofn = NULL; + Zipfn = NULL; To_Indx = NULL; Recfm = RECFM_VAR; Mapped = false; @@ -126,7 +130,20 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int) : (am && (*am == 'B' || *am == 'b')) ? "B" : (am && !stricmp(am, "DBF")) ? "D" : "V"; - Desc = Fn = GetStringCatInfo(g, "Filename", NULL); + if (*dfm != 'D') + Zipfn = GetStringCatInfo(g, "Zipfile", NULL); + + if (Zipfn && Multiple) { + // Prevent Fn to default to table name + Desc = GetStringCatInfo(g, "Filename", NULL); + Fn = GetStringCatInfo(g, "Filename", "<%>"); + + if (!strcmp(Fn, "<%>")) + Fn = NULL; + + } else + Desc = Fn = GetStringCatInfo(g, "Filename", NULL); + Ofn = GetStringCatInfo(g, "Optname", Fn); GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : @@ -333,7 +350,20 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) /* Allocate table and file processing class of the proper type. */ /* Column blocks will be allocated only when needed. */ /*********************************************************************/ - if (Recfm == RECFM_DBF) { + if (Zipfn) { +#if defined(ZIP_SUPPORT) + if (Recfm == RECFM_VAR) + txfp = new(g) ZIPFAM(this); + else + txfp = new(g) ZPXFAM(this); + + tdbp = new(g) TDBDOS(this, txfp); + return tdbp; +#else // !ZIP_SUPPORT + strcpy(g->Message, "ZIP not supported"); + return NULL; +#endif // !ZIP_SUPPORT + } else if (Recfm == RECFM_DBF) { if (Catfunc == FNC_NO) { if (map) txfp = new(g) DBMFAM(this); diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index c70e0032f47..501ddbc2e0b 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -28,6 +28,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ friend class TDBFIX; friend class TXTFAM; friend class DBFBASE; + friend class ZIPFAM; public: // Constructor DOSDEF(void); @@ -58,7 +59,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ // Methods virtual int Indexable(void) - {return (!Multiple && Compressed != 1) ? 1 : 0;} + {return (!Multiple && !Zipfn && Compressed != 1) ? 1 : 0;} virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE mode); @@ -72,7 +73,8 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ // Members PSZ Fn; /* Path/Name of corresponding file */ PSZ Ofn; /* Base Path/Name of matching index files*/ - PIXDEF To_Indx; /* To index definitions blocks */ + PSZ Zipfn; /* Zip container name */ + PIXDEF To_Indx; /* To index definitions blocks */ RECFM Recfm; /* 0:VAR, 1:FIX, 2:BIN, 3:VCT, 6:DBF */ bool Mapped; /* 0: disk file, 1: memory mapped file */ bool Padded; /* true for padded table file */ diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 4a39ecd6e0f..d6649a0093b 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -1,7 +1,7 @@ /************* TabFmt C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABFMT */ /* ------------- */ -/* Version 3.9.1 */ +/* Version 3.9.2 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -54,6 +54,9 @@ #if defined(GZ_SUPPORT) #include "filamgz.h" #endif // GZ_SUPPORT +#if defined(ZIP_SUPPORT) +#include "filamzip.h" +#endif // ZIP_SUPPORT #include "tabfmt.h" #include "tabmul.h" #define NO_FUNC @@ -78,20 +81,24 @@ USETEMP UseTemp(void); /* of types (TYPE_STRING < TYPE_DOUBLE < TYPE_INT) (1 < 2 < 7). */ /* If these values are changed, this will have to be revisited. */ /***********************************************************************/ -PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, - char q, int hdr, int mxr, bool info) +PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int length[] = {6, 6, 8, 10, 10, 6}; - char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096]; + const char *fn; + char sep, q; + int rc, mxr; + bool hdr; + char *p, *colname[MAXCOL], dechar, buf[8]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL]; - FILE *infile; + PCSVDEF tdp; + PTDBCSV tdbp; PQRYRES qrp; PCOLRES crp; @@ -102,26 +109,7 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, } // endif info // num_max = atoi(p+1); // Max num of record to test -#if defined(__WIN__) - if (sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6)) - dechar = '.'; - else - dechar = ','; -#else // !__WIN__ - dechar = '.'; -#endif // !__WIN__ - - if (trace) - htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n", - SVP(fn), sep, q, hdr, mxr); - - if (!fn) { - strcpy(g->Message, MSG(MISSING_FNAME)); - return NULL; - } // endif fn - imax = hmax = nerr = 0; - mxr = MY_MAX(0, mxr); for (i = 0; i < MAXCOL; i++) { colname[i] = NULL; @@ -131,12 +119,73 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, } // endfor i /*********************************************************************/ - /* Open the input file. */ + /* Get the CSV table description block. */ /*********************************************************************/ - PlugSetPath(filename, fn, dp); + tdp = new(g) CSVDEF; +#if defined(ZIP_SUPPORT) + tdp->Zipfn = GetStringTableOption(g, topt, "Zipfile", NULL); + tdp->Multiple = GetIntegerTableOption(g, topt, "Multiple", 0); +#endif // ZIP_SUPPORT + tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); - if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r"))) - return NULL; + if (!tdp->Fn && !tdp->Zipfn && !tdp->Multiple) { + strcpy(g->Message, MSG(MISSING_FNAME)); + return NULL; + } // endif Fn + + fn = (tdp->Fn) ? tdp->Fn : "unnamed"; + + if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) + tdp->Lrecl = 4096; + + p = GetStringTableOption(g, topt, "Separator", ","); + tdp->Sep = (strlen(p) == 2 && p[0] == '\\' && p[1] == 't') ? '\t' : *p; + +#if defined(__WIN__) + if (tdp->Sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6)) + dechar = '.'; + else + dechar = ','; +#else // !__WIN__ + dechar = '.'; +#endif // !__WIN__ + + sep = tdp->Sep; + tdp->Quoted = GetIntegerTableOption(g, topt, "Quoted", -1); + p = GetStringTableOption(g, topt, "Qchar", ""); + tdp->Qot = *p; + + if (tdp->Qot && tdp->Quoted < 0) + tdp->Quoted = 0; + else if (!tdp->Qot && tdp->Quoted >= 0) + tdp->Qot = '"'; + + q = tdp->Qot; + hdr = GetBooleanTableOption(g, topt, "Header", false); + tdp->Maxerr = GetIntegerTableOption(g, topt, "Maxerr", 0); + tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false); + + if (tdp->Accept && tdp->Maxerr == 0) + tdp->Maxerr = INT_MAX32; // Accept all bad lines + + mxr = MY_MAX(0, tdp->Maxerr); + + if (trace) + htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n", + SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr); + + if (tdp->Zipfn) + tdbp = new(g) TDBCSV(tdp, new(g) ZIPFAM(tdp)); + else + tdbp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp)); + + tdbp->SetMode(MODE_READ); + + /*********************************************************************/ + /* Open the CSV file. */ + /*********************************************************************/ + if (tdbp->OpenDB(g)) + return NULL; if (hdr) { /*******************************************************************/ @@ -144,16 +193,8 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, /*******************************************************************/ phase = 0; - if (fgets(buf, sizeof(buf), infile)) { - n = strlen(buf) + 1; - buf[n - 2] = '\0'; -#if !defined(__WIN__) - // The file can be imported from Windows - if (buf[n - 3] == '\r') - buf[n - 3] = 0; -#endif // UNIX - p = (char*)PlugSubAlloc(g, NULL, n); - memcpy(p, buf, n); + if ((rc = tdbp->ReadDB(g)) == RC_OK) { + p = PlgDBDup(g, tdbp->To_Line); //skip leading blanks for (; *p == ' '; p++) ; @@ -165,10 +206,11 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, } // endif q colname[0] = p; - } else { + } else if (rc == RC_EF) { sprintf(g->Message, MSG(FILE_IS_EMPTY), fn); goto err; - } // endif's + } else + goto err; for (i = 1; *p; p++) if (phase == 1 && *p == q) { @@ -201,15 +243,8 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, /*******************************************************************/ /* Now start the reading process. Read one line. */ /*******************************************************************/ - if (fgets(buf, sizeof(buf), infile)) { - n = strlen(buf); - buf[n - 1] = '\0'; -#if !defined(__WIN__) - // The file can be imported from Windows - if (buf[n - 2] == '\r') - buf[n - 2] = 0; -#endif // UNIX - } else if (feof(infile)) { + if ((rc = tdbp->ReadDB(g)) == RC_OK) { + } else if (rc == RC_EF) { sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1); break; } else { @@ -222,7 +257,7 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, /*******************************************************************/ i = n = phase = blank = digit = dec = 0; - for (p = buf; *p; p++) + for (p = tdbp->To_Line; *p; p++) if (*p == sep) { if (phase != 1) { if (i == MAXCOL - 1) { @@ -331,7 +366,7 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, htrc("\n"); } // endif trace - fclose(infile); + tdbp->CloseDB(g); skipit: if (trace) @@ -381,7 +416,7 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, return qrp; err: - fclose(infile); + tdbp->CloseDB(g); return NULL; } // end of CSVCColumns @@ -458,7 +493,21 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) /*******************************************************************/ /* Allocate a file processing class of the proper type. */ /*******************************************************************/ - if (map) { + if (Zipfn) { +#if defined(ZIP_SUPPORT) + txfp = new(g) ZIPFAM(this); + + if (!Fmtd) + tdbp = new(g) TDBCSV(this, txfp); + else + tdbp = new(g) TDBFMT(this, txfp); + + return tdbp; +#else // !ZIP_SUPPORT + strcpy(g->Message, "ZIP not supported"); + return NULL; +#endif // !ZIP_SUPPORT + } else if (map) { // Should be now compatible with UNIX txfp = new(g) MAPFAM(this); } else if (Compressed) { @@ -1476,21 +1525,16 @@ void CSVCOL::WriteColumn(PGLOBAL g) /* TDBCCL class constructor. */ /***********************************************************************/ TDBCCL::TDBCCL(PCSVDEF tdp) : TDBCAT(tdp) - { - Fn = tdp->GetFn(); - Hdr = tdp->Header; - Mxr = tdp->Maxerr; - Qtd = tdp->Quoted; - Sep = tdp->Sep; - } // end of TDBCCL constructor +{ + Topt = tdp->GetTopt(); +} // end of TDBCCL constructor /***********************************************************************/ /* GetResult: Get the list the CSV file columns. */ /***********************************************************************/ PQRYRES TDBCCL::GetResult(PGLOBAL g) { - return CSVColumns(g, ((PTABDEF)To_Def)->GetPath(), - Fn, Sep, Qtd, Hdr, Mxr, false); + return CSVColumns(g, ((PTABDEF)To_Def)->GetPath(), Topt, false); } // end of GetResult /* ------------------------ End of TabFmt ---------------------------- */ diff --git a/storage/connect/tabfmt.h b/storage/connect/tabfmt.h index ce80a276cdc..5ce8d399a64 100644 --- a/storage/connect/tabfmt.h +++ b/storage/connect/tabfmt.h @@ -1,7 +1,7 @@ /*************** TabFmt H Declares Source Code File (.H) ***************/ -/* Name: TABFMT.H Version 2.4 */ +/* Name: TABFMT.H Version 2.5 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2001-2014 */ +/* (C) Copyright to the author Olivier BERTRAND 2001-2016 */ /* */ /* This file contains the CSV and FMT classes declares. */ /***********************************************************************/ @@ -13,8 +13,7 @@ typedef class TDBFMT *PTDBFMT; /***********************************************************************/ /* Functions used externally. */ /***********************************************************************/ -PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, - char q, int hdr, int mxr, bool info); +PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info); /***********************************************************************/ /* CSV table. */ @@ -22,7 +21,8 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, const char *fn, char sep, class DllExport CSVDEF : public DOSDEF { /* Logical table description */ friend class TDBCSV; friend class TDBCCL; - public: + friend PQRYRES CSVColumns(PGLOBAL, char *, PTOS, bool); +public: // Constructor CSVDEF(void); @@ -50,9 +50,10 @@ class DllExport CSVDEF : public DOSDEF { /* Logical table description */ /* This is the DOS/UNIX Access Method class declaration for files */ /* that are CSV files with columns separated by the Sep character. */ /***********************************************************************/ -class TDBCSV : public TDBDOS { +class DllExport TDBCSV : public TDBDOS { friend class CSVCOL; - public: + friend PQRYRES CSVColumns(PGLOBAL, char *, PTOS, bool); +public: // Constructor TDBCSV(PCSVDEF tdp, PTXF txfp); TDBCSV(PGLOBAL g, PTDBCSV tdbp); @@ -101,7 +102,7 @@ class TDBCSV : public TDBDOS { /* Class CSVCOL: CSV access method column descriptor. */ /* This A.M. is used for Comma Separated V(?) files. */ /***********************************************************************/ -class CSVCOL : public DOSCOL { +class DllExport CSVCOL : public DOSCOL { friend class TDBCSV; friend class TDBFMT; public: @@ -129,7 +130,7 @@ class CSVCOL : public DOSCOL { /* This is the DOS/UNIX Access Method class declaration for files */ /* whose record format is described by a Format keyword. */ /***********************************************************************/ -class TDBFMT : public TDBCSV { +class DllExport TDBFMT : public TDBCSV { friend class CSVCOL; //friend class FMTCOL; public: @@ -173,7 +174,7 @@ class TDBFMT : public TDBCSV { /***********************************************************************/ /* This is the class declaration for the CSV catalog table. */ /***********************************************************************/ -class TDBCCL : public TDBCAT { +class DllExport TDBCCL : public TDBCAT { public: // Constructor TDBCCL(PCSVDEF tdp); @@ -183,11 +184,7 @@ class TDBCCL : public TDBCAT { virtual PQRYRES GetResult(PGLOBAL g); // Members - char *Fn; // The CSV file (path) name - bool Hdr; // true if first line contains headers - int Mxr; // Maximum number of bad records - int Qtd; // Quoting level for quoted fields - char Sep; // Separator for standard CSV files - }; // end of class TDBCCL + PTOS Topt; +}; // end of class TDBCCL /* ------------------------- End of TabFmt.H ------------------------- */ diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 5f864f0bd48..73c6a6d85a4 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1,5 +1,5 @@ /************* tabjson C++ Program Source Code File (.CPP) *************/ -/* PROGRAM NAME: tabjson Version 1.2 */ +/* PROGRAM NAME: tabjson Version 1.3 */ /* (C) Copyright to the author Olivier BERTRAND 2014 - 2016 */ /* This program are the JSON class DB execution routines. */ /***********************************************************************/ @@ -28,6 +28,9 @@ #if defined(GZ_SUPPORT) #include "filamgz.h" #endif // GZ_SUPPORT +#if defined(ZIP_SUPPORT) +#include "filamzip.h" +#endif // ZIP_SUPPORT #include "tabmul.h" #include "checklvl.h" #include "resource.h" @@ -67,7 +70,7 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT}; static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0}; - char *fn, colname[65], fmt[129]; + char colname[65], fmt[129]; int i, j, lvl, n = 0; int ncol = sizeof(buftyp) / sizeof(int); PVAL valp; @@ -94,16 +97,21 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ - if (!(fn = GetStringTableOption(g, topt, "Filename", NULL))) { - strcpy(g->Message, MSG(MISSING_FNAME)); - return NULL; - } else { - lvl = GetIntegerTableOption(g, topt, "Level", 0); - lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; - } // endif fn + lvl = GetIntegerTableOption(g, topt, "Level", 0); + lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl; tdp = new(g) JSONDEF; - tdp->Fn = fn; +#if defined(ZIP_SUPPORT) + tdp->Zipfn = GetStringTableOption(g, topt, "Zipfile", NULL); + tdp->Multiple = GetIntegerTableOption(g, topt, "Multiple", 0); +#endif // ZIP_SUPPORT + tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); + + if (!tdp->Fn && !tdp->Zipfn && !tdp->Multiple) { + strcpy(g->Message, MSG(MISSING_FNAME)); + return NULL; + } // endif Fn + tdp->Database = SetPath(g, db); tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; @@ -114,7 +122,10 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp->Fn, tdp->Objname, tdp->Pretty, lvl); if (tdp->Pretty == 2) { - tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); + if (tdp->Zipfn) + tjsp = new(g) TDBJSON(tdp, new(g) ZIPFAM(tdp)); + else + tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); if (tjsp->MakeDocument(g)) return NULL; @@ -127,10 +138,28 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) } // endif lrecl tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); - tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); + + if (tdp->Zipfn) + tjnp = new(g) TDBJSN(tdp, new(g) ZIPFAM(tdp)); + else + tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); + tjnp->SetMode(MODE_READ); - if (tjnp->OpenDB(g)) +#if USE_G + // Allocate the parse work memory + PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); + memset(G, 0, sizeof(GLOBAL)); + G->Sarea_Size = tdp->Lrecl * 10; + G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); + PlugSubSet(G, G->Sarea, G->Sarea_Size); + G->jump_level = -1; + tjnp->SetG(G); +#else + tjnp->SetG(g); +#endif + + if (tjnp->OpenDB(g)) return NULL; switch (tjnp->ReadDB(g)) { @@ -395,7 +424,14 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) !(tmp == TMP_FORCE && (m == MODE_UPDATE || m == MODE_DELETE)); - if (Compressed) { + if (Zipfn) { +#if defined(ZIP_SUPPORT) + txfp = new(g) ZIPFAM(this); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else if (Compressed) { #if defined(GZ_SUPPORT) if (Compressed == 1) txfp = new(g) GZFAM(this); @@ -426,12 +462,16 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ((TDBJSN*)tdbp)->G = g; #endif } else { - txfp = new(g) MAPFAM(this); + if (Zipfn) + txfp = new(g) ZIPFAM(this); + else + txfp = new(g) MAPFAM(this); + tdbp = new(g) TDBJSON(this, txfp); ((TDBJSON*)tdbp)->G = g; } // endif Pretty - if (Multiple) + if (Multiple && !Zipfn) tdbp = new(g) TDBMUL(tdbp); return tdbp; diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index f7cb74c3c4d..c9d30d48f2a 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -78,7 +78,8 @@ public: virtual AMT GetAmType(void) {return TYPE_AM_JSN;} virtual bool SkipHeader(PGLOBAL g); virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBJSN(this);} - PJSON GetRow(void) {return Row;} + PJSON GetRow(void) {return Row;} + void SetG(PGLOBAL g) {G = g;} // Methods virtual PTDB CopyOne(PTABS t); diff --git a/storage/connect/tabzip.cpp b/storage/connect/tabzip.cpp new file mode 100644 index 00000000000..11f414ee154 --- /dev/null +++ b/storage/connect/tabzip.cpp @@ -0,0 +1,230 @@ +/************* TabZip C++ Program Source Code File (.CPP) **************/ +/* PROGRAM NAME: TABZIP Version 1.0 */ +/* (C) Copyright to the author Olivier BERTRAND 2016 */ +/* This program are the TABZIP class DB execution routines. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant sections of the MariaDB header file. */ +/***********************************************************************/ +#include + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* (x)table.h is header containing the TDBASE declarations. */ +/* tabzip.h is header containing the TABZIP classes declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "xtable.h" +#include "filamtxt.h" +#include "filamzip.h" +#include "resource.h" // for IDS_COLUMNS +#include "tabdos.h" +#include "tabzip.h" + +/* -------------------------- Class ZIPDEF --------------------------- */ + +/************************************************************************/ +/* DefineAM: define specific AM block values. */ +/************************************************************************/ +bool ZIPDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) +{ +//target = GetStringCatInfo(g, "Target", NULL); + return DOSDEF::DefineAM(g, "ZIP", poff); +} // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new Table Description Block. */ +/***********************************************************************/ +PTDB ZIPDEF::GetTable(PGLOBAL g, MODE m) +{ + return new(g) TDBZIP(this); +} // end of GetTable + +/* ------------------------------------------------------------------- */ + +/***********************************************************************/ +/* Implementation of the TDBZIP class. */ +/***********************************************************************/ +TDBZIP::TDBZIP(PZIPDEF tdp) : TDBASE(tdp) +{ + zipfile = NULL; + zfn = tdp->Fn; +//target = tdp->target; + nexterr = UNZ_OK; +} // end of TDBZIP standard constructor + +/***********************************************************************/ +/* Allocate ZIP column description block. */ +/***********************************************************************/ +PCOL TDBZIP::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) +{ + return new(g) ZIPCOL(cdp, this, cprec, n); +} // end of MakeCol + +/***********************************************************************/ +/* open a zip file. */ +/* param: filename path and the filename of the zip file to open. */ +/* return: true if open, false otherwise. */ +/***********************************************************************/ +bool TDBZIP::open(PGLOBAL g, const char *filename) +{ + if (!zipfile && !(zipfile = unzOpen64(filename))) + sprintf(g->Message, "Zipfile open error"); + + return (zipfile == NULL); +} // end of open + +/***********************************************************************/ +/* Close the zip file. */ +/***********************************************************************/ +void TDBZIP::close() +{ + if (zipfile) { + unzClose(zipfile); + zipfile = NULL; + } // endif zipfile + +} // end of close + +/***********************************************************************/ +/* ZIP Cardinality: returns table size in number of rows. */ +/***********************************************************************/ +int TDBZIP::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + else if (Cardinal < 0) { + if (!open(g, zfn)) { + unz_global_info64 ginfo; + int err = unzGetGlobalInfo64(zipfile, &ginfo); + + Cardinal = (err == UNZ_OK) ? ginfo.number_entry : 0; + } else + Cardinal = 0; + + } // endif Cardinal + + return Cardinal; +} // end of Cardinality + +/***********************************************************************/ +/* ZIP GetMaxSize: returns file size estimate in number of lines. */ +/***********************************************************************/ +int TDBZIP::GetMaxSize(PGLOBAL g) +{ + if (MaxSize < 0) + MaxSize = Cardinality(g); + + return MaxSize; +} // end of GetMaxSize + +/***********************************************************************/ +/* ZIP Access Method opening routine. */ +/***********************************************************************/ +bool TDBZIP::OpenDB(PGLOBAL g) +{ + if (Use == USE_OPEN) + // Table already open + return false; + + Use = USE_OPEN; // To be clean + return open(g, zfn); +} // end of OpenDB + +/***********************************************************************/ +/* ReadDB: Data Base read routine for ZIP access method. */ +/***********************************************************************/ +int TDBZIP::ReadDB(PGLOBAL g) +{ + if (nexterr == UNZ_END_OF_LIST_OF_FILE) + return RC_EF; + else if (nexterr != UNZ_OK) { + sprintf(g->Message, "unzGoToNextFile error %d", nexterr); + return RC_FX; + } // endif nexterr + + int err = unzGetCurrentFileInfo64(zipfile, &finfo, fn, + sizeof(fn), NULL, 0, NULL, 0); + + if (err != UNZ_OK) { + sprintf(g->Message, "unzGetCurrentFileInfo64 error %d", err); + return RC_FX; + } // endif err + + nexterr = unzGoToNextFile(zipfile); + return RC_OK; +} // end of ReadDB + +/***********************************************************************/ +/* WriteDB: Data Base write routine for ZIP access method. */ +/***********************************************************************/ +int TDBZIP::WriteDB(PGLOBAL g) +{ + strcpy(g->Message, "ZIP tables are read only"); + return RC_FX; +} // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for ZIP access method. */ +/***********************************************************************/ +int TDBZIP::DeleteDB(PGLOBAL g, int irc) +{ + strcpy(g->Message, "Delete not enabled for ZIP tables"); + return RC_FX; +} // end of DeleteDB + +/***********************************************************************/ +/* Data Base close routine for ZIP access method. */ +/***********************************************************************/ +void TDBZIP::CloseDB(PGLOBAL g) +{ + close(); + Use = USE_READY; // Just to be clean +} // end of CloseDB + +/* ---------------------------- ZIPCOL ------------------------------- */ + +/***********************************************************************/ +/* ZIPCOL public constructor. */ +/***********************************************************************/ +ZIPCOL::ZIPCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) + : COLBLK(cdp, tdbp, i) +{ + if (cprec) { + Next = cprec->GetNext(); + cprec->SetNext(this); + } else { + Next = tdbp->GetColumns(); + tdbp->SetColumns(this); + } // endif cprec + + Tdbz = (TDBZIP*)tdbp; + flag = cdp->GetOffset(); +} // end of ZIPCOL constructor + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void ZIPCOL::ReadColumn(PGLOBAL g) +{ + switch (flag) { + case 1: + Value->SetValue(Tdbz->finfo.compressed_size); + break; + case 2: + Value->SetValue(Tdbz->finfo.uncompressed_size); + break; + case 3: + Value->SetValue((int)Tdbz->finfo.compression_method); + break; + default: + Value->SetValue_psz((PSZ)Tdbz->fn); + } // endswitch flag + +} // end of ReadColumn + +/* -------------------------- End of tabzip -------------------------- */ diff --git a/storage/connect/tabzip.h b/storage/connect/tabzip.h new file mode 100644 index 00000000000..6f1735258e7 --- /dev/null +++ b/storage/connect/tabzip.h @@ -0,0 +1,100 @@ +/*************** tabzip H Declares Source Code File (.H) ***************/ +/* Name: tabzip.h Version 1.0 */ +/* */ +/* (C) Copyright to the author Olivier BERTRAND 2016 */ +/* */ +/* This file contains the ZIP classe declares. */ +/***********************************************************************/ +#include "osutil.h" +#include "block.h" +#include "colblk.h" +#include "xtable.h" +#include "unzip.h" + +typedef class ZIPDEF *PZIPDEF; +typedef class TDBZIP *PTDBZIP; +typedef class ZIPCOL *PZIPCOL; + +/***********************************************************************/ +/* ZIP table: display info about a ZIP file. */ +/***********************************************************************/ +class DllExport ZIPDEF : public DOSDEF { /* Table description */ + friend class TDBZIP; + friend class ZIPFAM; +public: + // Constructor + ZIPDEF(void) {} + + // Implementation + virtual const char *GetType(void) {return "ZIP";} + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE m); + +protected: + // Members + PSZ target; // The inside file to query +}; // end of ZIPDEF + +/***********************************************************************/ +/* This is the ZIP Access Method class declaration. */ +/***********************************************************************/ +class DllExport TDBZIP : public TDBASE { + friend class ZIPCOL; +public: + // Constructor + TDBZIP(PZIPDEF tdp); + + // Implementation + virtual AMT GetAmType(void) {return TYPE_AM_ZIP;} + + // Methods + virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); + virtual int Cardinality(PGLOBAL g); + virtual int GetMaxSize(PGLOBAL g); + virtual int GetRecpos(void) {return 0;} + + // Database routines + virtual bool OpenDB(PGLOBAL g); + virtual int ReadDB(PGLOBAL g); + virtual int WriteDB(PGLOBAL g); + virtual int DeleteDB(PGLOBAL g, int irc); + virtual void CloseDB(PGLOBAL g); + +protected: + bool open(PGLOBAL g, const char *filename); + void close(void); + + // Members + unzFile zipfile; // The ZIP container file + PSZ zfn; // The ZIP file name +//PSZ target; + unz_file_info64 finfo; // The current file info + char fn[FILENAME_MAX]; // The current file name + int nexterr; // Next file error +}; // end of class TDBZIP + +/***********************************************************************/ +/* Class ZIPCOL: ZIP access method column descriptor. */ +/***********************************************************************/ +class DllExport ZIPCOL : public COLBLK { + friend class TDBZIP; +public: + // Constructors + ZIPCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am = "ZIP"); + + // Implementation + virtual int GetAmType(void) { return TYPE_AM_ZIP; } + + // Methods + virtual void ReadColumn(PGLOBAL g); + +protected: + // Default constructor not to be used + ZIPCOL(void) {} + + // Members + TDBZIP *Tdbz; + int flag; +}; // end of class ZIPCOL diff --git a/storage/connect/unzip.c b/storage/connect/unzip.c new file mode 100644 index 00000000000..909350435a5 --- /dev/null +++ b/storage/connect/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/storage/connect/unzip.h b/storage/connect/unzip.h new file mode 100644 index 00000000000..2104e391507 --- /dev/null +++ b/storage/connect/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/storage/connect/zip.c b/storage/connect/zip.c new file mode 100644 index 00000000000..ea54853e858 --- /dev/null +++ b/storage/connect/zip.c @@ -0,0 +1,2007 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/storage/connect/zip.h b/storage/connect/zip.h new file mode 100644 index 00000000000..8aaebb62343 --- /dev/null +++ b/storage/connect/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ From ffdd1e9d888edc4e147c3b316a87468b000f8dd4 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Wed, 14 Dec 2016 13:57:05 +0530 Subject: [PATCH 040/124] Revert "MDEV-11016 wsrep_node_is_ready() check is too strict" This reverts commit 52ea5ad865b4f6b4b37176296a3be0a716c5109a. # Conflicts: # mysql-test/suite/galera/r/galera_var_dirty_reads.result # mysql-test/suite/galera/t/galera_var_dirty_reads.test # sql/sql_parse.cc --- .../suite/galera/r/galera_var_dirty_reads.result | 16 ---------------- .../suite/galera/t/galera_var_dirty_reads.test | 13 ------------- sql/sql_parse.cc | 4 ---- 3 files changed, 33 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index c0ffb2d4860..6d703c8cf95 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -18,22 +18,6 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; i 1 -# -# MDEV-11016: wsrep_node_is_ready() check is too strict -# -SET @@session.wsrep_dirty_reads=OFF; -SELECT 2; -2 -2 -SELECT 2+2 from DUAL; -2+2 -4 -SET @VAR=1; -SELECT @VAR; -@VAR -1 -SELECT @@max_allowed_packet; -SELECT SYSDATE() from DUAL; SELECT * FROM t1; i 1 diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index 7a76a71a265..dfd8d5ecf29 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -36,19 +36,6 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; ---echo # ---echo # MDEV-11016: wsrep_node_is_ready() check is too strict ---echo # -SET @@session.wsrep_dirty_reads=OFF; -SELECT 2; -SELECT 2+2 from DUAL; -SET @VAR=1; -SELECT @VAR; ---disable_result_log -SELECT @@max_allowed_packet; -SELECT SYSDATE() from DUAL; ---enable_result_log - --disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' --enable_query_log diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 53350751d79..4ed1b7a5323 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2635,15 +2635,11 @@ mysql_execute_command(THD *thd) /* Bail out if DB snapshot has not been installed. We however, allow SET and SHOW queries. - SHOW and SELECT queries (only if wsrep_dirty_reads is set or when it - does not access ant table) */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && lex->sql_command == SQLCOM_SELECT) && - !(lex->sql_command == SQLCOM_SELECT && - !all_tables) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, From 4c1e181ac5eac55c67705ffe29b48a5d832211be Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Wed, 14 Dec 2016 15:22:04 +0530 Subject: [PATCH 041/124] MDEV-11479 Improved wsrep_dirty_reads Tasks:- Changes in wsrep_dirty_reads variable 1.) Global + Session scope (Current: session-only) 2.) Can be set using command line. 3.) Allow all commands that do not change data (besides SELECT) 4.) Allow prepared Statements that do not change data 5.) Works with wsrep_sync_wait enabled --- mysql-test/r/mysqld--help.result | 3 + .../galera/r/galera_var_dirty_reads.result | 70 +++++++++++++++++++ .../galera/t/galera_var_dirty_reads.test | 68 ++++++++++++++++++ .../sys_vars/r/wsrep_dirty_reads_basic.result | 23 +++++- .../sys_vars/t/wsrep_dirty_reads_basic.test | 17 ++++- sql/sql_parse.cc | 9 ++- sql/sys_vars.cc | 5 +- sql/wsrep_mysqld.cc | 4 ++ sql/wsrep_mysqld.h | 1 + 9 files changed, 191 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 8ff9073b625..e911f0b8db6 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1080,6 +1080,8 @@ The following options may be given as the first argument: DBUG options to provider library --wsrep-debug To enable debug level logging --wsrep-desync To desynchronize the node from the cluster + --wsrep-dirty-reads Allow reads even when the node is not in the primary + component. --wsrep-drupal-282555-workaround To use a workaround forbad autoincrement value --wsrep-forced-binlog-format=name @@ -1454,6 +1456,7 @@ wsrep-convert-LOCK-to-trx FALSE wsrep-dbug-option wsrep-debug FALSE wsrep-desync FALSE +wsrep-dirty-reads FALSE wsrep-drupal-282555-workaround FALSE wsrep-forced-binlog-format NONE wsrep-load-data-splitting TRUE diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result index 6d703c8cf95..8a3175912c7 100644 --- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result +++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result @@ -3,6 +3,10 @@ INSERT INTO t1 VALUES(1); SELECT * FROM t1; i 1 +create user user1; +grant all privileges on *.* to user1; +create user user2; +grant all privileges on *.* to user2; SET @@global.wsrep_cluster_address = ''; SET @@session.wsrep_dirty_reads=OFF; SET SESSION wsrep_sync_wait=0; @@ -18,8 +22,74 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; i 1 +connect con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2; +SET SESSION wsrep_sync_wait=0; +set session wsrep_dirty_reads=1; +prepare stmt_show from 'select 1'; +prepare stmt_select from 'select * from t1'; +prepare stmt_insert from 'insert into t1 values(1)'; +set session wsrep_dirty_reads=0; +execute stmt_show; +ERROR 08S01: WSREP has not yet prepared node for application use +execute stmt_select; +ERROR 08S01: WSREP has not yet prepared node for application use +execute stmt_insert; +ERROR 08S01: WSREP has not yet prepared node for application use +SET wsrep_dirty_reads=ON; +select @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +1 +execute stmt_show; +1 +1 +execute stmt_select; +i +1 +execute stmt_insert; +ERROR 08S01: WSREP has not yet prepared node for application use +SET @@global.wsrep_dirty_reads=ON; +connect con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2; +select @@session.wsrep_dirty_reads; +@@session.wsrep_dirty_reads +1 +prepare stmt_show from 'select 1'; +prepare stmt_select from 'select * from t1'; +prepare stmt_insert from 'insert into t1 values(1)'; +execute stmt_show; +1 +1 +execute stmt_select; +i +1 +execute stmt_insert; +ERROR 08S01: WSREP has not yet prepared node for application use +SET SESSION wsrep_sync_wait=1; +execute stmt_show; +1 +1 +execute stmt_select; +i +1 +execute stmt_insert; +ERROR 08S01: WSREP has not yet prepared node for application use +SET SESSION wsrep_sync_wait=7; +execute stmt_show; +1 +1 +execute stmt_select; +i +1 +execute stmt_insert; +ERROR 08S01: WSREP has not yet prepared node for application use +connection node_2; +SET @@global.wsrep_dirty_reads=OFF; +connection node_1; SELECT * FROM t1; i 1 DROP TABLE t1; +drop user user1; +drop user user2; +disconnect node_2; +disconnect node_1; # End of test diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index dfd8d5ecf29..bcdb1574a3d 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -17,6 +17,11 @@ CREATE TABLE t1(i INT) ENGINE=INNODB; INSERT INTO t1 VALUES(1); SELECT * FROM t1; +create user user1; +grant all privileges on *.* to user1; +create user user2; +grant all privileges on *.* to user2; + SET @@global.wsrep_cluster_address = ''; SET @@session.wsrep_dirty_reads=OFF; @@ -36,6 +41,67 @@ SET @@session.wsrep_dirty_reads=ON; SELECT * FROM t1; +--enable_connect_log +--connect (con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2) +#Just test the session behavior +SET SESSION wsrep_sync_wait=0; + +set session wsrep_dirty_reads=1; +#Prepared statement creation should be allowed MDEV-11479 +prepare stmt_show from 'select 1'; +prepare stmt_select from 'select * from t1'; +prepare stmt_insert from 'insert into t1 values(1)'; +set session wsrep_dirty_reads=0; + +#No Preapare stmt/proceure will be allowed +--error ER_UNKNOWN_COM_ERROR +execute stmt_show; +--error ER_UNKNOWN_COM_ERROR +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert; + +SET wsrep_dirty_reads=ON; +select @@session.wsrep_dirty_reads; +#Only prepare statement which does not change data should be allowed +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert; +SET @@global.wsrep_dirty_reads=ON; + +--connect (con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2) +#Just test the session behavior +select @@session.wsrep_dirty_reads; + +prepare stmt_show from 'select 1'; +prepare stmt_select from 'select * from t1'; +prepare stmt_insert from 'insert into t1 values(1)'; + +#Only prepare statement which does not change data should be allowed +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert; + +#wsrep_dirty_read should work when wsrep_sync_wait is 1 or non zero +#because we already are disconnected , So It does not make any sense +#to wait for other nodes +SET SESSION wsrep_sync_wait=1; +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert; + +SET SESSION wsrep_sync_wait=7; +execute stmt_show; +execute stmt_select; +--error ER_UNKNOWN_COM_ERROR +execute stmt_insert; + +--connection node_2 +SET @@global.wsrep_dirty_reads=OFF; + --disable_query_log --eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved' --enable_query_log @@ -45,6 +111,8 @@ SELECT * FROM t1; SELECT * FROM t1; # Cleanup DROP TABLE t1; +drop user user1; +drop user user2; # Restore original auto_increment_offset values. --source include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result index d2a62d6136f..1968103873a 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result @@ -5,12 +5,13 @@ SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; # default SELECT @@global.wsrep_dirty_reads; -ERROR HY000: Variable 'wsrep_dirty_reads' is a SESSION variable +@@global.wsrep_dirty_reads +0 SELECT @@session.wsrep_dirty_reads; @@session.wsrep_dirty_reads 0 -# scope and valid values +# valid values for session SET @@session.wsrep_dirty_reads=OFF; SELECT @@session.wsrep_dirty_reads; @@session.wsrep_dirty_reads @@ -24,11 +25,29 @@ SELECT @@session.wsrep_dirty_reads; @@session.wsrep_dirty_reads 0 +# valid values for global +SET @@global.wsrep_dirty_reads=OFF; +SELECT @@global.wsrep_dirty_reads; +@@global.wsrep_dirty_reads +0 +SET @@global.wsrep_dirty_reads=ON; +SELECT @@global.wsrep_dirty_reads; +@@global.wsrep_dirty_reads +1 +SET @@global.wsrep_dirty_reads=default; +SELECT @@global.wsrep_dirty_reads; +@@global.wsrep_dirty_reads +0 + # invalid values SET @@session.wsrep_dirty_reads=NULL; ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL' SET @@session.wsrep_dirty_reads='junk'; ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk' +SET @@global.wsrep_dirty_reads=NULL; +ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL' +SET @@global.wsrep_dirty_reads='junk'; +ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk' # restore the initial values SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved; diff --git a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test index a47524fcfe3..ffe767a051b 100644 --- a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test +++ b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test @@ -8,12 +8,12 @@ SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads; --echo # default ---error ER_INCORRECT_GLOBAL_LOCAL_VAR + SELECT @@global.wsrep_dirty_reads; SELECT @@session.wsrep_dirty_reads; --echo ---echo # scope and valid values +--echo # valid values for session SET @@session.wsrep_dirty_reads=OFF; SELECT @@session.wsrep_dirty_reads; SET @@session.wsrep_dirty_reads=ON; @@ -21,12 +21,25 @@ SELECT @@session.wsrep_dirty_reads; SET @@session.wsrep_dirty_reads=default; SELECT @@session.wsrep_dirty_reads; +--echo +--echo # valid values for global +SET @@global.wsrep_dirty_reads=OFF; +SELECT @@global.wsrep_dirty_reads; +SET @@global.wsrep_dirty_reads=ON; +SELECT @@global.wsrep_dirty_reads; +SET @@global.wsrep_dirty_reads=default; +SELECT @@global.wsrep_dirty_reads; + --echo --echo # invalid values --error ER_WRONG_VALUE_FOR_VAR SET @@session.wsrep_dirty_reads=NULL; --error ER_WRONG_VALUE_FOR_VAR SET @@session.wsrep_dirty_reads='junk'; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_dirty_reads=NULL; +--error ER_WRONG_VALUE_FOR_VAR +SET @@global.wsrep_dirty_reads='junk'; --echo --echo # restore the initial values diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ed1b7a5323..d92ef810498 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2633,13 +2633,16 @@ mysql_execute_command(THD *thd) } /* - Bail out if DB snapshot has not been installed. We however, - allow SET and SHOW queries. + Bail out if DB snapshot has not been installed. SET and SHOW commands, + however, are always allowed. + + We additionally allow all other commands that do not change data in + case wsrep_dirty_reads is enabled. */ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready && lex->sql_command != SQLCOM_SET_OPTION && !(thd->variables.wsrep_dirty_reads && - lex->sql_command == SQLCOM_SELECT) && + !is_update_query(lex->sql_command)) && !wsrep_is_show_query(lex->sql_command)) { my_message(ER_UNKNOWN_COM_ERROR, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index af440d7ac44..93a863d6b88 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4811,8 +4811,9 @@ static Sys_var_mybool Sys_wsrep_restart_slave( GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static Sys_var_mybool Sys_wsrep_dirty_reads( - "wsrep_dirty_reads", "Do not reject SELECT queries even when the node " - "is not ready.", SESSION_ONLY(wsrep_dirty_reads), NO_CMD_LINE, + "wsrep_dirty_reads", + "Allow reads even when the node is not in the primary component.", + SESSION_VAR(wsrep_dirty_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG); #endif /* WITH_WSREP */ diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 13b72b65afe..353911dcfde 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -71,6 +71,8 @@ my_bool wsrep_restart_slave_activated = 0; // node has dropped, and slave // restart will be needed my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks +// Allow reads even if the node is not in the primary component. +bool wsrep_dirty_reads = false; /* Set during the creation of first wsrep applier and rollback threads. @@ -816,6 +818,8 @@ bool wsrep_must_sync_wait (THD* thd, uint mask) { return (thd->variables.wsrep_sync_wait & mask) && thd->variables.wsrep_on && + !(thd->variables.wsrep_dirty_reads && + !is_update_query(thd->lex->sql_command)) && !thd->in_active_multi_stmt_transaction() && thd->wsrep_conflict_state != REPLAYING && thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 57382d27e98..5ec183f7186 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -88,6 +88,7 @@ extern ulong wsrep_retry_autocommit; extern my_bool wsrep_auto_increment_control; extern my_bool wsrep_drupal_282555_workaround; extern my_bool wsrep_incremental_data_collection; +extern bool wsrep_dirty_reads; extern const char* wsrep_start_position; extern ulong wsrep_max_ws_size; extern ulong wsrep_max_ws_rows; From 952306502ebf1b26c627c5dc8b141581eeb30671 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 14 Dec 2016 14:20:23 +0100 Subject: [PATCH 042/124] - MDEV-11295: developing handling files contained in ZIP file. Enable using multiple zip files modified: storage/connect/filamzip.cpp modified: storage/connect/ha_connect.cc modified: storage/connect/ha_connect.h modified: storage/connect/mycat.h modified: storage/connect/tabdos.cpp modified: storage/connect/tabdos.h modified: storage/connect/tabfmt.cpp modified: storage/connect/tabjson.cpp --- storage/connect/filamzip.cpp | 19 +++++++++--------- storage/connect/filamzip.h | 2 +- storage/connect/ha_connect.cc | 14 ++++++------- storage/connect/ha_connect.h | 37 ++--------------------------------- storage/connect/mycat.h | 1 + storage/connect/tabdos.cpp | 23 +++++++--------------- storage/connect/tabdos.h | 7 ++++--- storage/connect/tabfmt.cpp | 26 +++++++++++------------- storage/connect/tabjson.cpp | 23 +++++++++++++--------- storage/connect/tabxml.cpp | 7 ++++++- 10 files changed, 63 insertions(+), 96 deletions(-) diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index ea8b827974b..8386e5be481 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -48,11 +48,11 @@ ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) { zipfile = NULL; - zfn = tdp->Zipfn; - target = tdp->Fn; +//zfn = tdp->Fn; + target = tdp->Entry; //*fn = 0; entryopen = false; - multiple = tdp->Multiple; + multiple = (target && !(strchr(target, '*') || strchr(target, '?'))) ? 0 : 1; // Init the case mapping table. #if defined(__WIN__) @@ -65,7 +65,7 @@ ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) ZIPFAM::ZIPFAM(PZIPFAM txfp) : MAPFAM(txfp) { zipfile = txfp->zipfile; - zfn = txfp->zfn; +//zfn = txfp->zfn; target = txfp->target; //strcpy(fn, txfp->fn); finfo = txfp->finfo; @@ -129,7 +129,7 @@ int ZIPFAM::GetFileLength(PGLOBAL g) bool ZIPFAM::open(PGLOBAL g, const char *filename) { if (!zipfile && !(zipfile = unzOpen64(filename))) - sprintf(g->Message, "Zipfile open error"); + sprintf(g->Message, "Zipfile open error on %s", filename); return (zipfile == NULL); } // end of open @@ -205,7 +205,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) /*********************************************************************/ if (mode == MODE_READ) { // We used the file name relative to recorded datapath - PlugSetPath(filename, zfn, Tdbp->GetPath()); + PlugSetPath(filename, To_File, Tdbp->GetPath()); bool b = open(g, filename); @@ -218,7 +218,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) if (rc == UNZ_END_OF_LIST_OF_FILE) { sprintf(g->Message, "Target file %s not in %s", target, filename); - return true; + return false; } else if (rc != UNZ_OK) { sprintf(g->Message, "unzLocateFile rc=%d", rc); return true; @@ -229,7 +229,7 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) return true; else if (rc == RC_NF) { sprintf(g->Message, "No match of %s in %s", target, filename); - return true; + return false; } // endif rc } // endif multiple @@ -258,7 +258,8 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) } // endif fp To_Fb = fp; // Useful when closing - } // endif b + } else + return true; } else { strcpy(g->Message, "Only READ mode supported for ZIP files"); diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index 85c1f907d20..c3c04b2b3bb 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -51,7 +51,7 @@ protected: // Members unzFile zipfile; // The ZIP container file - PSZ zfn; // The ZIP file name +//PSZ zfn; // The ZIP file name PSZ target; // The target file name unz_file_info finfo; // The current file info //char fn[FILENAME_MAX]; // The current file name diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index b690dff24f4..45ca546ad4e 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -171,9 +171,9 @@ #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.04.0009 December 09, 2016"; + char version[]= "Version 1.05.0001 December 13, 2016"; #if defined(__WIN__) - char compver[]= "Version 1.04.0009 " __DATE__ " " __TIME__; + char compver[]= "Version 1.05.0001 " __DATE__ " " __TIME__; char slash= '\\'; #else // !__WIN__ char slash= '/'; @@ -512,13 +512,13 @@ ha_create_table_option connect_table_option_list[]= HA_TOPTION_NUMBER("QUOTED", quoted, (ulonglong) -1, 0, 3, 1), HA_TOPTION_NUMBER("ENDING", ending, (ulonglong) -1, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1), -//HA_TOPTION_BOOL("COMPRESS", compressed, 0), HA_TOPTION_BOOL("MAPPED", mapped, 0), HA_TOPTION_BOOL("HUGE", huge, 0), HA_TOPTION_BOOL("SPLIT", split, 0), HA_TOPTION_BOOL("READONLY", readonly, 0), HA_TOPTION_BOOL("SEPINDEX", sepindex, 0), - HA_TOPTION_END + HA_TOPTION_BOOL("ZIPPED", zipped, 0), + HA_TOPTION_END }; @@ -532,7 +532,6 @@ ha_create_table_option connect_field_option_list[]= { HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1), HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX -//HA_FOPTION_NUMBER("DISTRIB", opt, 0, 0, 2, 1), // used for BLK_INDX HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1), HA_FOPTION_STRING("DATE_FORMAT", dateformat), HA_FOPTION_STRING("FIELD_FORMAT", fieldformat), @@ -678,7 +677,6 @@ static int connect_init_func(void *p) connect_hton= (handlerton *)p; connect_hton->state= SHOW_OPTION_YES; connect_hton->create= connect_create_handler; -//connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED | HTON_NO_PARTITION; connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED; connect_hton->table_options= connect_table_option_list; connect_hton->field_options= connect_field_option_list; @@ -1135,7 +1133,9 @@ bool GetBooleanTableOption(PGLOBAL g, PTOS options, char *opname, bool bdef) opval= options->sepindex; else if (!stricmp(opname, "Header")) opval= (options->header != 0); // Is Boolean for some table types - else if (options->oplist) + else if (!stricmp(opname, "Zipped")) + opval = options->zipped; + else if (options->oplist) if ((pv= GetListOption(g, opname, options->oplist))) opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0); diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index 60194ac0e3c..3d9ff967618 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -83,42 +83,9 @@ extern handlerton *connect_hton; These can be specified in the CREATE TABLE: CREATE TABLE ( ... ) {...here...} -*/ -#if 0 // moved to mycat.h -typedef struct ha_table_option_struct TOS, *PTOS; -struct ha_table_option_struct { - const char *type; - const char *filename; - const char *optname; - const char *tabname; - const char *tablist; - const char *dbname; - const char *separator; -//const char *connect; - const char *qchar; - const char *module; - const char *subtype; - const char *catfunc; - const char *srcdef; - const char *colist; - const char *oplist; - const char *data_charset; - ulonglong lrecl; - ulonglong elements; -//ulonglong estimate; - ulonglong multiple; - ulonglong header; - ulonglong quoted; - ulonglong ending; - ulonglong compressed; - bool mapped; - bool huge; - bool split; - bool readonly; - bool sepindex; - }; -#endif // 0 + ------ Was moved to mycat.h ------ + */ /** structure for CREATE TABLE options (field options) diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h index 05163f08f1b..663b68fd4b9 100644 --- a/storage/connect/mycat.h +++ b/storage/connect/mycat.h @@ -62,6 +62,7 @@ struct ha_table_option_struct { bool split; bool readonly; bool sepindex; + bool zipped; }; // Possible value for catalog functions diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index 9bcac0b5f1a..f47e66b014b 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -96,11 +96,12 @@ DOSDEF::DOSDEF(void) Pseudo = 3; Fn = NULL; Ofn = NULL; - Zipfn = NULL; + Entry = NULL; To_Indx = NULL; Recfm = RECFM_VAR; Mapped = false; - Padded = false; + Zipped = false; + Padded = false; Huge = false; Accept = false; Eof = false; @@ -131,20 +132,11 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int) : (am && !stricmp(am, "DBF")) ? "D" : "V"; if (*dfm != 'D') - Zipfn = GetStringCatInfo(g, "Zipfile", NULL); - - if (Zipfn && Multiple) { - // Prevent Fn to default to table name - Desc = GetStringCatInfo(g, "Filename", NULL); - Fn = GetStringCatInfo(g, "Filename", "<%>"); - - if (!strcmp(Fn, "<%>")) - Fn = NULL; - - } else - Desc = Fn = GetStringCatInfo(g, "Filename", NULL); + Zipped = GetBoolCatInfo("Zipped", false); + Desc = Fn = GetStringCatInfo(g, "Filename", NULL); Ofn = GetStringCatInfo(g, "Optname", Fn); + Entry = GetStringCatInfo(g, "Entry", NULL); GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : (toupper(*buf) == 'B') ? RECFM_BIN : @@ -350,7 +342,7 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) /* Allocate table and file processing class of the proper type. */ /* Column blocks will be allocated only when needed. */ /*********************************************************************/ - if (Zipfn) { + if (Zipped) { #if defined(ZIP_SUPPORT) if (Recfm == RECFM_VAR) txfp = new(g) ZIPFAM(this); @@ -358,7 +350,6 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) txfp = new(g) ZPXFAM(this); tdbp = new(g) TDBDOS(this, txfp); - return tdbp; #else // !ZIP_SUPPORT strcpy(g->Message, "ZIP not supported"); return NULL; diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 501ddbc2e0b..623adcfed0d 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -59,7 +59,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ // Methods virtual int Indexable(void) - {return (!Multiple && !Zipfn && Compressed != 1) ? 1 : 0;} + {return (!Multiple && !Zipped && Compressed != 1) ? 1 : 0;} virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE mode); @@ -73,11 +73,12 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ // Members PSZ Fn; /* Path/Name of corresponding file */ PSZ Ofn; /* Base Path/Name of matching index files*/ - PSZ Zipfn; /* Zip container name */ + PSZ Entry; /* Zip entry name or pattern */ PIXDEF To_Indx; /* To index definitions blocks */ RECFM Recfm; /* 0:VAR, 1:FIX, 2:BIN, 3:VCT, 6:DBF */ bool Mapped; /* 0: disk file, 1: memory mapped file */ - bool Padded; /* true for padded table file */ + bool Zipped; /* true for zipped table file */ + bool Padded; /* true for padded table file */ bool Huge; /* true for files larger than 2GB */ bool Accept; /* true if wrong lines are accepted */ bool Eof; /* true if an EOF (0xA) character exists */ diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index d6649a0093b..2c4d605e66c 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -108,6 +108,11 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info) goto skipit; } // endif info + if (GetIntegerTableOption(g, topt, "Multiple", 0)) { + strcpy(g->Message, "Cannot find column definition for multiple table"); + return NULL; + } // endif Multiple + // num_max = atoi(p+1); // Max num of record to test imax = hmax = nerr = 0; @@ -123,18 +128,16 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info) /*********************************************************************/ tdp = new(g) CSVDEF; #if defined(ZIP_SUPPORT) - tdp->Zipfn = GetStringTableOption(g, topt, "Zipfile", NULL); - tdp->Multiple = GetIntegerTableOption(g, topt, "Multiple", 0); + tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); + tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); #endif // ZIP_SUPPORT - tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); + fn = tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); - if (!tdp->Fn && !tdp->Zipfn && !tdp->Multiple) { + if (!tdp->Fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif Fn - fn = (tdp->Fn) ? tdp->Fn : "unnamed"; - if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) tdp->Lrecl = 4096; @@ -174,7 +177,7 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info) htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n", SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr); - if (tdp->Zipfn) + if (tdp->Zipped) tdbp = new(g) TDBCSV(tdp, new(g) ZIPFAM(tdp)); else tdbp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp)); @@ -493,16 +496,9 @@ PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode) /*******************************************************************/ /* Allocate a file processing class of the proper type. */ /*******************************************************************/ - if (Zipfn) { + if (Zipped) { #if defined(ZIP_SUPPORT) txfp = new(g) ZIPFAM(this); - - if (!Fmtd) - tdbp = new(g) TDBCSV(this, txfp); - else - tdbp = new(g) TDBFMT(this, txfp); - - return tdbp; #else // !ZIP_SUPPORT strcpy(g->Message, "ZIP not supported"); return NULL; diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 73c6a6d85a4..eff95445a3a 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -94,7 +94,12 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) goto skipit; } // endif info - /*********************************************************************/ + if (GetIntegerTableOption(g, topt, "Multiple", 0)) { + strcpy(g->Message, "Cannot find column definition for multiple table"); + return NULL; + } // endif Multiple + + /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ lvl = GetIntegerTableOption(g, topt, "Level", 0); @@ -102,12 +107,12 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp = new(g) JSONDEF; #if defined(ZIP_SUPPORT) - tdp->Zipfn = GetStringTableOption(g, topt, "Zipfile", NULL); - tdp->Multiple = GetIntegerTableOption(g, topt, "Multiple", 0); + tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); + tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); #endif // ZIP_SUPPORT tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); - if (!tdp->Fn && !tdp->Zipfn && !tdp->Multiple) { + if (!tdp->Fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif Fn @@ -122,7 +127,7 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp->Fn, tdp->Objname, tdp->Pretty, lvl); if (tdp->Pretty == 2) { - if (tdp->Zipfn) + if (tdp->Zipped) tjsp = new(g) TDBJSON(tdp, new(g) ZIPFAM(tdp)); else tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); @@ -139,7 +144,7 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); - if (tdp->Zipfn) + if (tdp->Zipped) tjnp = new(g) TDBJSN(tdp, new(g) ZIPFAM(tdp)); else tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); @@ -424,7 +429,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) !(tmp == TMP_FORCE && (m == MODE_UPDATE || m == MODE_DELETE)); - if (Zipfn) { + if (Zipped) { #if defined(ZIP_SUPPORT) txfp = new(g) ZIPFAM(this); #else // !ZIP_SUPPORT @@ -462,7 +467,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ((TDBJSN*)tdbp)->G = g; #endif } else { - if (Zipfn) + if (Zipped) txfp = new(g) ZIPFAM(this); else txfp = new(g) MAPFAM(this); @@ -471,7 +476,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ((TDBJSON*)tdbp)->G = g; } // endif Pretty - if (Multiple && !Zipfn) + if (Multiple) tdbp = new(g) TDBMUL(tdbp); return tdbp; diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 57d204a4286..1993b07eb7a 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -136,7 +136,12 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) goto skipit; } // endif info - /*********************************************************************/ + if (GetIntegerTableOption(g, topt, "Multiple", 0)) { + strcpy(g->Message, "Cannot find column definition for multiple table"); + return NULL; + } // endif Multiple + + /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ if (!(fn = GetStringTableOption(g, topt, "Filename", NULL))) { From 211cf9321a91b12eaef3d7968adc699085dbb54e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 16 Dec 2016 18:37:11 +0400 Subject: [PATCH 043/124] MDEV-11510 Audit plugin sometimes causes server to crash when using with MySQL. MySQL has a bug failing to handle MYSQL_THDVAR_STR(... PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_MEMALLOC) so fall back to just PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC whem MySQL started. --- plugin/server_audit/server_audit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 95150c82f25..87ba00b2d35 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -2845,6 +2845,7 @@ void __attribute__ ((constructor)) audit_plugin_so_init(void) _mysql_plugin_declarations_[0].info= mysql_v4_descriptor; use_event_data_for_disconnect= 1; } + MYSQL_SYSVAR_NAME(loc_info).flags= PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC; } memset(locinfo_ini_value, 'O', sizeof(locinfo_ini_value)-1); From e86580c3dda707788fb0ca35244cf602d7e8d50d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 15 Dec 2016 18:20:58 +0100 Subject: [PATCH 044/124] MDEV-11552 Queries executed by event scheduler are written to slow log incorrectly or not written at all because thd->update_server_status() is used to measure the query time for the slow log (not only to set protocol level flags), it needs to be called also when the server isn't going to send anything to the client. --- mysql-test/r/events_slowlog.result | 12 ++++++++++++ mysql-test/t/events_slowlog.test | 28 ++++++++++++++++++++++++++++ sql/sp_head.cc | 10 +++++----- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 mysql-test/r/events_slowlog.result create mode 100644 mysql-test/t/events_slowlog.test diff --git a/mysql-test/r/events_slowlog.result b/mysql-test/r/events_slowlog.result new file mode 100644 index 00000000000..c97fe8a2ab9 --- /dev/null +++ b/mysql-test/r/events_slowlog.result @@ -0,0 +1,12 @@ +set @event_scheduler_save= @@global.event_scheduler; +set @slow_query_log_save= @@global.slow_query_log; +set global event_scheduler= on; +set global slow_query_log= on; +set global long_query_time=0.2; +create table t1 (i int); +insert into t1 values (0); +create event ev on schedule at CURRENT_TIMESTAMP + INTERVAL 1 second do update t1 set i=1+sleep(0.5); +drop table t1; +set global event_scheduler= @event_scheduler_save; +set global slow_query_log= @slow_query_log_save; +set global long_query_time= @@session.long_query_time; diff --git a/mysql-test/t/events_slowlog.test b/mysql-test/t/events_slowlog.test new file mode 100644 index 00000000000..9679714dba3 --- /dev/null +++ b/mysql-test/t/events_slowlog.test @@ -0,0 +1,28 @@ +--source include/not_embedded.inc +# +# MDEV-11552 Queries executed by event scheduler are written to slow log incorrectly or not written at all +# +set @event_scheduler_save= @@global.event_scheduler; +set @slow_query_log_save= @@global.slow_query_log; + +set global event_scheduler= on; +set global slow_query_log= on; +set global long_query_time=0.2; + +create table t1 (i int); +insert into t1 values (0); +create event ev on schedule at CURRENT_TIMESTAMP + INTERVAL 1 second do update t1 set i=1+sleep(0.5); + +--let wait_condition= select i from t1 where i > 0 +--source include/wait_condition.inc + +--let SEARCH_FILE = `SELECT @@slow_query_log_file` +--let SEARCH_PATTERN= update t1 set i=1 +--let SEARCH_RANGE= -1000 +--source include/search_pattern_in_file.inc + +drop table t1; + +set global event_scheduler= @event_scheduler_save; +set global slow_query_log= @slow_query_log_save; +set global long_query_time= @@session.long_query_time; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 019e9d9a478..9bfa60a07d3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3146,18 +3146,18 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) thd->query_length()) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); + bool log_slow= !res && thd->enable_slow_log; - if (thd->stmt_da->is_eof()) - { - /* Finalize server status flags after executing a statement. */ + /* Finalize server status flags after executing a statement. */ + if (log_slow || thd->stmt_da->is_eof()) thd->update_server_status(); + if (thd->stmt_da->is_eof()) thd->protocol->end_statement(); - } query_cache_end_of_result(thd); - if (!res && unlikely(thd->enable_slow_log)) + if (log_slow) log_slow_statement(thd); } else From b03b38dd6515e60689adb6c9ca57d9612618e2bf Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Dec 2016 10:10:08 +0100 Subject: [PATCH 045/124] cleanup: rpl.rpl_row_mysqlbinlog some trivial simplifications. drinking the ocean, one drop at a time --- .../suite/rpl/r/rpl_row_mysqlbinlog.result | 37 ++---- .../suite/rpl/t/rpl_row_mysqlbinlog.test | 120 ++++-------------- 2 files changed, 38 insertions(+), 119 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result index 1489af830cc..19611ac52b5 100644 --- a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result +++ b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result @@ -1,14 +1,21 @@ include/master-slave.inc [connection master] - ---Setup Section -- set timestamp=1000000000; -DROP TABLE IF EXISTS t1,t2,t3; CREATE TABLE t1(word VARCHAR(20)); CREATE TABLE t2(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY); CREATE TABLE t3(c1 INT NOT NULL PRIMARY KEY, c2 LONGBLOB, c3 TIMESTAMP, c4 TEXT, c5 FLOAT); - ----Test1 check table load -- +INSERT INTO t1 VALUES ("abirvalg"); +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; +set @d1 = 'dd1'; +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); +set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); +---Test 1 check table load -- SELECT COUNT(*) from t1; COUNT(*) 351 @@ -71,9 +78,7 @@ c1 c3 c4 c5 5 2006-02-22 00:00:00 Tested in Texas 11 insert into t1 values ("Alas"); flush logs; - --- Test 1 Dump binlog to file -- - --- Test 1 delete tables, clean master and slave -- DROP TABLE t1; DROP TABLE t2; @@ -84,9 +89,7 @@ reset master; reset slave; start slave; include/wait_for_slave_to_start.inc - --- Test 1 Load from Dump binlog file -- - --- Test 1 Check Load Results -- SELECT COUNT(*) from t1; COUNT(*) @@ -148,7 +151,6 @@ c1 c3 c4 c5 3 2006-02-22 00:00:00 Tested in Texas 6.6 4 2006-02-22 00:00:00 Tested in Texas 8.8 5 2006-02-22 00:00:00 Tested in Texas 11 - --- Test 2 position test -- /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -172,7 +174,6 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; - --- Test 3 First Remote test -- /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -189,9 +190,6 @@ SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/ SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */ -/*!*/; -SET TIMESTAMP=1000000000/*!*/; CREATE TABLE t1(word VARCHAR(20)) /*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -205,7 +203,6 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; - --- Test 4 Second Remote test -- DROP TABLE t1; DROP TABLE t2; @@ -276,7 +273,6 @@ c1 c3 c4 c5 3 2006-02-22 00:00:00 Tested in Texas 6.6 4 2006-02-22 00:00:00 Tested in Texas 8.8 5 2006-02-22 00:00:00 Tested in Texas 11 - --- Test 5 LOAD DATA -- /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -287,7 +283,6 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; - --- Test 6 reading stdin -- /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -304,9 +299,6 @@ SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/ SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */ -/*!*/; -SET TIMESTAMP=1000000000/*!*/; CREATE TABLE t1(word VARCHAR(20)) /*!*/; SET TIMESTAMP=1000000000/*!*/; @@ -320,7 +312,6 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; - --- Test 7 reading stdin w/position -- /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; @@ -344,7 +335,6 @@ DELIMITER ; ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; - --- Test 8 switch internal charset -- stop slave; include/wait_for_slave_to_stop.inc @@ -380,14 +370,13 @@ HEX(f) select HEX(f) from t5; HEX(f) 835C - --- Test cleanup -- -DROP TABLE IF EXISTS t1; +DROP TABLE t1, t2, t3, t04, t05, t4, t5; CREATE TABLE t1 (a INT NOT NULL KEY, b INT); INSERT INTO t1 VALUES(1,1); SELECT * FROM t1; a b 1 1 FLUSH LOGS; -DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5; +DROP TABLE t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test index ed0f31b75be..678679f0cf1 100644 --- a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test @@ -4,43 +4,27 @@ # Purpose: To test changes to mysqlbinlog for row based bin logs # # We are using .opt file since we need small binlog size # ################################################################## -# Include Section -# Make sure that we have row based bin log -- source include/have_binlog_format_row.inc -# Embedded server doesn't support binlogging -- source include/not_embedded.inc -# This test requires the cp932 charset compiled in -- source include/have_cp932.inc -# Slow test, don't run during staging part --- source include/not_staging.inc - -- source include/master-slave.inc -# Setup Section +--echo ---Setup Section -- + # we need this for getting fixed timestamps inside of this test - ---disable_query_log -select "---Setup Section --" as ""; ---enable_query_log - set timestamp=1000000000; ---disable_warnings -DROP TABLE IF EXISTS t1,t2,t3; ---enable_warnings - -connection master; CREATE TABLE t1(word VARCHAR(20)); CREATE TABLE t2(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY); ---let $position= query_get_value(SHOW MASTER STATUS, Position, 1) +--let position= query_get_value(SHOW MASTER STATUS, Position, 1) CREATE TABLE t3(c1 INT NOT NULL PRIMARY KEY, c2 LONGBLOB, c3 TIMESTAMP, c4 TEXT, c5 FLOAT); ---let $stop_position=query_get_value(SHOW MASTER STATUS, Position, 1) ---let $stop_position1=`select $stop_position - 1` ---let $binlog_start_pos=query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1) +--let stop_position=query_get_value(SHOW MASTER STATUS, Position, 1) +--let stop_position1=`select $stop_position - 1` +--let binlog_start_pos=query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1) + # Test Section # Lets start by putting some data into the tables. ---disable_query_log INSERT INTO t1 VALUES ("abirvalg"); LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE t1; @@ -54,7 +38,8 @@ set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); set @d1 = concat(@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1,@d1); -let $count=500; +--disable_query_log +let count=500; while ($count) { INSERT INTO t2 VALUES (NULL); @@ -63,10 +48,7 @@ while ($count) } --enable_query_log - ---disable_query_log -select "---Test1 check table load --" as ""; ---enable_query_log +--echo ---Test 1 check table load -- # Lets Check the tables on the Master SELECT COUNT(*) from t1; @@ -95,34 +77,26 @@ insert into t1 values ("Alas"); flush logs; # delimiters are for easier debugging in future ---disable_query_log -select "--- Test 1 Dump binlog to file --" as ""; ---enable_query_log +--echo --- Test 1 Dump binlog to file -- # # Prepare local temporary file to recreate what we have currently. -let $MYSQLD_DATADIR= `select @@datadir;`; +let MYSQLD_DATADIR= `select @@datadir;`; --exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/master.sql --exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/master.sql # Now that we have our file, lets get rid of the current database. # Cleanup the master and the slave and try to recreate. ---disable_query_log -select "--- Test 1 delete tables, clean master and slave --" as ""; ---enable_query_log +--echo --- Test 1 delete tables, clean master and slave -- DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; sync_slave_with_master; -#we expect STOP SLAVE to produce a warning as the slave is stopped -#(the server was started with skip-slave-start) ---disable_warnings stop slave; --source include/wait_for_slave_to_stop.inc ---enable_warnings connection master; reset master; connection slave; @@ -132,15 +106,11 @@ start slave; connection master; # We should be clean at this point, now we will run in the file from above. ---disable_query_log -select "--- Test 1 Load from Dump binlog file --" as ""; ---enable_query_log +--echo --- Test 1 Load from Dump binlog file -- --exec $MYSQL -e "source $MYSQLTEST_VARDIR/tmp/master.sql" ---disable_query_log -select "--- Test 1 Check Load Results --" as ""; ---enable_query_log +--echo --- Test 1 Check Load Results -- # Lets Check the tables on the Master SELECT COUNT(*) from t1; @@ -168,28 +138,20 @@ remove_file $MYSQLTEST_VARDIR/tmp/master.sql; # this test for start-position option # By setting this position to 416, we should only get the create of t3 ---disable_query_log -select "--- Test 2 position test --" as ""; ---enable_query_log -let $MYSQLD_DATADIR= `select @@datadir;`; +--echo --- Test 2 position test -- --exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --start-position=$position --stop-position=$stop_position $MYSQLD_DATADIR/master-bin.000001 # These are tests for remote binlog. # They should return the same as previous test. ---disable_query_log -select "--- Test 3 First Remote test --" as ""; ---enable_query_log +--echo --- Test 3 First Remote test -- # This is broken now --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=$stop_position --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 ---disable_query_log -select "--- Test 4 Second Remote test --" as ""; ---enable_query_log +--echo --- Test 4 Second Remote test -- --exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql - --exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 >> $MYSQLTEST_VARDIR/tmp/remote.sql # Now that we have our file, lets get rid of the current database. @@ -201,13 +163,8 @@ DROP TABLE t3; sync_slave_with_master; -#we expect STOP SLAVE to produce a warning as the slave is stopped -#(the server was started with skip-slave-start) - ---disable_warnings stop slave; --source include/wait_for_slave_to_stop.inc ---enable_warnings connection master; reset master; connection slave; @@ -251,40 +208,26 @@ connection master; # transactions. /Matz # LOAD DATA ---disable_query_log -select "--- Test 5 LOAD DATA --" as ""; ---enable_query_log +--echo --- Test 5 LOAD DATA -- --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --stop-position=$binlog_start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # Bug#7853 (mysqlbinlog does not accept input from stdin) ---disable_query_log -select "--- Test 6 reading stdin --" as ""; ---enable_query_log -let $MYSQLD_DATADIR= `select @@datadir;`; +--echo --- Test 6 reading stdin -- --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form --stop-position=$stop_position1 - < $MYSQLD_DATADIR/master-bin.000001 ---disable_query_log -select "--- Test 7 reading stdin w/position --" as ""; ---enable_query_log +--echo --- Test 7 reading stdin w/position -- --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form --start-position=$position --stop-position=$stop_position - < $MYSQLD_DATADIR/master-bin.000001 # Bug#16217 (mysql client did not know how not switch its internal charset) ---disable_query_log -select "--- Test 8 switch internal charset --" as ""; ---enable_query_log +--echo --- Test 8 switch internal charset -- sync_slave_with_master; -#we expect STOP SLAVE to produce a warning as the slave is stopped -#(the server was started with skip-slave-start) - ---disable_warnings stop slave; --source include/wait_for_slave_to_stop.inc ---enable_warnings connection master; reset master; connection slave; @@ -297,7 +240,6 @@ create table t4 (f text character set utf8); create table t5 (f text character set cp932); --exec $MYSQL --default-character-set=utf8 test -e "insert into t4 values(_utf8'ソ')" --exec $MYSQL --default-character-set=cp932 test -e "insert into t5 values(_cp932'\');" -let $MYSQLD_DATADIR= `select @@datadir;`; flush logs; rename table t4 to t04, t5 to t05; --exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL --default-character-set=utf8 @@ -314,42 +256,30 @@ select HEX(f) from t4; select HEX(f) from t05; select HEX(f) from t5; ---disable_query_log -select "--- Test cleanup --" as ""; ---enable_query_log +--echo --- Test cleanup -- # clean up connection master; sync_slave_with_master; connection master; +DROP TABLE t1, t2, t3, t04, t05, t4, t5; # BUG#17654 also test mysqlbinlog to ensure it can read the binlog from a remote server # and ensure that the results are the same as if read from a file (the same file). ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - CREATE TABLE t1 (a INT NOT NULL KEY, b INT); - INSERT INTO t1 VALUES(1,1); - SELECT * FROM t1; - -let $MYSQLD_DATADIR= `select @@datadir;`; - FLUSH LOGS; --exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/remote.sql --exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/local.sql --diff_files $MYSQLTEST_VARDIR/tmp/local.sql $MYSQLTEST_VARDIR/tmp/remote.sql - --remove_file $MYSQLTEST_VARDIR/tmp/remote.sql - --remove_file $MYSQLTEST_VARDIR/tmp/local.sql +DROP TABLE t1; -DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5; sync_slave_with_master; # End of 4.1 tests From b2b210b891697f999a9f85037462d54f78707e3e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 16 Dec 2016 17:42:21 +0100 Subject: [PATCH 046/124] MDEV-11543 Buildbot tests fail with warnings on server shutdown after rpl.rpl_row_mysqlbinlog double the timeout for threads to die on shutdown --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8eb92cafc03..ea4fa823d29 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1462,7 +1462,7 @@ static void close_connections(void) end_slave(); /* Give threads time to die. */ - for (int i= 0; thread_count && i < 100; i++) + for (int i= 0; thread_count && i < 200; i++) my_sleep(20000); /* From c4d9dc705b781bb155aab8f04cece2b87116d3c1 Mon Sep 17 00:00:00 2001 From: iangilfillan Date: Fri, 16 Dec 2016 14:44:08 +0200 Subject: [PATCH 047/124] Typo, update limit in comment --- sql/item_subselect.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6427b0ecae4..dda9986f60f 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4352,9 +4352,9 @@ bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) result= result_sink; /* - If the subquery has blobs, or the total key lenght is bigger than + If the subquery has blobs, or the total key length is bigger than some length, or the total number of key parts is more than the - allowed maximum (currently MAX_REF_PARTS == 16), then the created + allowed maximum (currently MAX_REF_PARTS == 32), then the created index cannot be used for lookups and we can't use hash semi join. If this is the case, delete the temporary table since it will not be used, and tell the caller we failed to initialize the From 2f6fede8d5f7e98319b4b7b557bd565fdb42fac3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 19 Dec 2016 14:28:08 +0400 Subject: [PATCH 048/124] MDEV-10524 Assertion `arg1_int >= 0' failed in Item_func_additive_op::result_precision() This change is a backport from 10.0 to 5.5 for: 1. The full patch for: MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() 9adb6e991ec87b65d04929f115d9d0c899e4ab19 2. A small fragment of: MDEV-5298 Illegal mix of collations on timestamp 03f6778d61a74bdd7d09103a16473a2a5624cf66 which overrides Item_temporal_hybrid_func::cmp_type(), and adds a new line into cache_temporal_4265.result. --- mysql-test/include/ctype_numconv.inc | 26 ++++++++++- mysql-test/r/cache_temporal_4265.result | 1 + mysql-test/r/ctype_binary.result | 42 ++++++++++++++++- mysql-test/r/ctype_cp1251.result | 46 ++++++++++++++++-- mysql-test/r/ctype_latin1.result | 42 ++++++++++++++++- mysql-test/r/ctype_ucs.result | 48 +++++++++++++++++-- mysql-test/r/ctype_utf8.result | 46 ++++++++++++++++-- mysql-test/r/func_time.result | 6 +++ mysql-test/t/func_time.test | 5 ++ sql/item_func.h | 1 + sql/item_strfunc.cc | 2 +- sql/item_strfunc.h | 1 - sql/item_timefunc.cc | 29 ++++++++++-- sql/item_timefunc.h | 62 ++++++++++++++++++++----- sql/sql_const.h | 2 +- sql/sql_time.cc | 17 +++++++ sql/sql_time.h | 2 + 17 files changed, 341 insertions(+), 37 deletions(-) diff --git a/mysql-test/include/ctype_numconv.inc b/mysql-test/include/ctype_numconv.inc index 9b21e7f38c1..47b52be9cec 100644 --- a/mysql-test/include/ctype_numconv.inc +++ b/mysql-test/include/ctype_numconv.inc @@ -1743,6 +1743,11 @@ DROP TABLE t1; --echo # Bug #31384 DATE_ADD() and DATE_SUB() return binary data --echo # SELECT @@collation_connection, @@character_set_results; +SELECT + CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, + CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, + CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, + CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -1766,7 +1771,26 @@ SELECT HEX(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field1_str2, HEX(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; - + +--echo # +--echo # MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +--echo # +SELECT @@collation_connection, @@character_set_results; +SELECT + CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, + CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, + CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, + CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +CREATE TABLE t1 AS +SELECT + ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, + ADDTIME('10:01:01','10:00:00') AS addtime2, + DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, + DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + --echo # --echo # Bug#11926811 / Bug#60625 Illegal mix of collations --echo # diff --git a/mysql-test/r/cache_temporal_4265.result b/mysql-test/r/cache_temporal_4265.result index 7f215de43fb..980bb957e19 100644 --- a/mysql-test/r/cache_temporal_4265.result +++ b/mysql-test/r/cache_temporal_4265.result @@ -7,6 +7,7 @@ a 2002-03-04 Warnings: Note 1003 2000-01-01 +Note 1003 2000-01-06 set debug_dbug=''; drop table t1; create table t1 (id int not null, ut timestamp(6) not null); diff --git a/mysql-test/r/ctype_binary.result b/mysql-test/r/ctype_binary.result index e7bf1238210..3fc440b8354 100644 --- a/mysql-test/r/ctype_binary.result +++ b/mysql-test/r/ctype_binary.result @@ -2777,6 +2777,13 @@ DROP TABLE t1; SELECT @@collation_connection, @@character_set_results; @@collation_connection @@character_set_results binary binary +SELECT +CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, +CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, +CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, +CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; +field_str1 field_str2 field_date field_datetime +binary binary binary binary CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -2786,8 +2793,8 @@ DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_da SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `field_str1` varchar(19) DEFAULT NULL, - `field1_str2` varchar(19) DEFAULT NULL, + `field_str1` varbinary(19) DEFAULT NULL, + `field1_str2` varbinary(19) DEFAULT NULL, `field_date` date DEFAULT NULL, `field_datetime` datetime DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -2812,6 +2819,37 @@ HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS fie field_str1 field1_str2 field_date field_datetime 323030372D30382D30322032333A35393A3030 323030372D30382D30332031373A33323A3030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 # +# MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +# +SELECT @@collation_connection, @@character_set_results; +@@collation_connection @@character_set_results +binary binary +SELECT +CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, +CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, +CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, +CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +addtime1 addtime2 date_add1 date_add2 +binary binary binary binary +CREATE TABLE t1 AS +SELECT +ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, +ADDTIME('10:01:01','10:00:00') AS addtime2, +DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, +DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `addtime1` varbinary(26) DEFAULT NULL, + `addtime2` varbinary(26) DEFAULT NULL, + `date_add1` varbinary(19) DEFAULT NULL, + `date_add2` varbinary(19) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +addtime1 addtime2 date_add1 date_add2 +20:01:01 20:01:01 2001-01-01 10:01:11 2001-01-01 10:01:11 +DROP TABLE t1; +# # Bug#11926811 / Bug#60625 Illegal mix of collations # SELECT @@collation_connection; diff --git a/mysql-test/r/ctype_cp1251.result b/mysql-test/r/ctype_cp1251.result index 2a7d4ed1fb4..9d5dea2f286 100644 --- a/mysql-test/r/ctype_cp1251.result +++ b/mysql-test/r/ctype_cp1251.result @@ -3169,6 +3169,13 @@ DROP TABLE t1; SELECT @@collation_connection, @@character_set_results; @@collation_connection @@character_set_results cp1251_general_ci cp1251 +SELECT +CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, +CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, +CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, +CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; +field_str1 field_str2 field_date field_datetime +cp1251 cp1251 binary binary CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -3178,8 +3185,8 @@ DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_da SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `field_str1` varchar(19) DEFAULT NULL, - `field1_str2` varchar(19) DEFAULT NULL, + `field_str1` varchar(19) CHARACTER SET cp1251 DEFAULT NULL, + `field1_str2` varchar(19) CHARACTER SET cp1251 DEFAULT NULL, `field_date` date DEFAULT NULL, `field_datetime` datetime DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -3190,8 +3197,8 @@ DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE) AS field1_str2, DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY) AS field_date, DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_datetime; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def field_str1 254 19 10 Y 128 0 63 -def field1_str2 254 19 19 Y 128 0 63 +def field_str1 254 19 10 Y 0 0 51 +def field1_str2 254 19 19 Y 0 0 51 def field_date 10 10 10 Y 128 0 63 def field_datetime 12 19 19 Y 128 0 63 field_str1 field1_str2 field_date field_datetime @@ -3204,6 +3211,37 @@ HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS fie field_str1 field1_str2 field_date field_datetime 323030372D30382D30322032333A35393A3030 323030372D30382D30332031373A33323A3030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 # +# MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +# +SELECT @@collation_connection, @@character_set_results; +@@collation_connection @@character_set_results +cp1251_general_ci cp1251 +SELECT +CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, +CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, +CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, +CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +addtime1 addtime2 date_add1 date_add2 +cp1251 cp1251 cp1251 cp1251 +CREATE TABLE t1 AS +SELECT +ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, +ADDTIME('10:01:01','10:00:00') AS addtime2, +DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, +DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `addtime1` varchar(26) CHARACTER SET cp1251 DEFAULT NULL, + `addtime2` varchar(26) CHARACTER SET cp1251 DEFAULT NULL, + `date_add1` varchar(19) CHARACTER SET cp1251 DEFAULT NULL, + `date_add2` varchar(19) CHARACTER SET cp1251 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +addtime1 addtime2 date_add1 date_add2 +20:01:01 20:01:01 2001-01-01 10:01:11 2001-01-01 10:01:11 +DROP TABLE t1; +# # Bug#11926811 / Bug#60625 Illegal mix of collations # SELECT @@collation_connection; diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index dc96495b1ac..db9d03a8656 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -3351,6 +3351,13 @@ DROP TABLE t1; SELECT @@collation_connection, @@character_set_results; @@collation_connection @@character_set_results latin1_swedish_ci latin1 +SELECT +CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, +CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, +CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, +CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; +field_str1 field_str2 field_date field_datetime +latin1 latin1 binary binary CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -3372,8 +3379,8 @@ DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE) AS field1_str2, DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY) AS field_date, DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_datetime; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def field_str1 254 19 10 Y 128 0 63 -def field1_str2 254 19 19 Y 128 0 63 +def field_str1 254 19 10 Y 0 0 8 +def field1_str2 254 19 19 Y 0 0 8 def field_date 10 10 10 Y 128 0 63 def field_datetime 12 19 19 Y 128 0 63 field_str1 field1_str2 field_date field_datetime @@ -3386,6 +3393,37 @@ HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS fie field_str1 field1_str2 field_date field_datetime 323030372D30382D30322032333A35393A3030 323030372D30382D30332031373A33323A3030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 # +# MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +# +SELECT @@collation_connection, @@character_set_results; +@@collation_connection @@character_set_results +latin1_swedish_ci latin1 +SELECT +CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, +CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, +CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, +CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +addtime1 addtime2 date_add1 date_add2 +latin1 latin1 latin1 latin1 +CREATE TABLE t1 AS +SELECT +ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, +ADDTIME('10:01:01','10:00:00') AS addtime2, +DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, +DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `addtime1` varchar(26) DEFAULT NULL, + `addtime2` varchar(26) DEFAULT NULL, + `date_add1` varchar(19) DEFAULT NULL, + `date_add2` varchar(19) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +addtime1 addtime2 date_add1 date_add2 +20:01:01 20:01:01 2001-01-01 10:01:11 2001-01-01 10:01:11 +DROP TABLE t1; +# # Bug#11926811 / Bug#60625 Illegal mix of collations # SELECT @@collation_connection; diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 96e0970e4a6..c38a03f76a8 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -4167,6 +4167,13 @@ DROP TABLE t1; SELECT @@collation_connection, @@character_set_results; @@collation_connection @@character_set_results ucs2_general_ci latin1 +SELECT +CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, +CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, +CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, +CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; +field_str1 field_str2 field_date field_datetime +ucs2 ucs2 binary binary CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -4176,8 +4183,8 @@ DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_da SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `field_str1` varchar(19) DEFAULT NULL, - `field1_str2` varchar(19) DEFAULT NULL, + `field_str1` varchar(19) CHARACTER SET ucs2 DEFAULT NULL, + `field1_str2` varchar(19) CHARACTER SET ucs2 DEFAULT NULL, `field_date` date DEFAULT NULL, `field_datetime` datetime DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -4188,8 +4195,8 @@ DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE) AS field1_str2, DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY) AS field_date, DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_datetime; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def field_str1 254 19 10 Y 128 0 63 -def field1_str2 254 19 19 Y 128 0 63 +def field_str1 254 19 10 Y 0 0 8 +def field1_str2 254 19 19 Y 0 0 8 def field_date 10 10 10 Y 128 0 63 def field_datetime 12 19 19 Y 128 0 63 field_str1 field1_str2 field_date field_datetime @@ -4200,7 +4207,38 @@ HEX(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field1_str2, HEX(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; field_str1 field1_str2 field_date field_datetime -323030372D30382D30322032333A35393A3030 323030372D30382D30332031373A33323A3030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 +0032003000300037002D00300038002D00300032002000320033003A00350039003A00300030 0032003000300037002D00300038002D00300033002000310037003A00330032003A00300030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 +# +# MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +# +SELECT @@collation_connection, @@character_set_results; +@@collation_connection @@character_set_results +ucs2_general_ci latin1 +SELECT +CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, +CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, +CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, +CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +addtime1 addtime2 date_add1 date_add2 +ucs2 ucs2 ucs2 ucs2 +CREATE TABLE t1 AS +SELECT +ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, +ADDTIME('10:01:01','10:00:00') AS addtime2, +DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, +DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `addtime1` varchar(26) CHARACTER SET ucs2 DEFAULT NULL, + `addtime2` varchar(26) CHARACTER SET ucs2 DEFAULT NULL, + `date_add1` varchar(19) CHARACTER SET ucs2 DEFAULT NULL, + `date_add2` varchar(19) CHARACTER SET ucs2 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +addtime1 addtime2 date_add1 date_add2 +20:01:01 20:01:01 2001-01-01 10:01:11 2001-01-01 10:01:11 +DROP TABLE t1; # # Bug#11926811 / Bug#60625 Illegal mix of collations # diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 294c2cb2be1..74fed6a3162 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -4988,6 +4988,13 @@ DROP TABLE t1; SELECT @@collation_connection, @@character_set_results; @@collation_connection @@character_set_results utf8_general_ci utf8 +SELECT +CHARSET(DATE_SUB('2007-08-03', INTERVAL 1 MINUTE)) AS field_str1, +CHARSET(DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE)) AS field_str2, +CHARSET(DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY)) AS field_date, +CHARSET(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS field_datetime; +field_str1 field_str2 field_date field_datetime +utf8 utf8 binary binary CREATE TABLE t1 AS SELECT DATE_SUB('2007-08-03', INTERVAL 1 MINUTE) AS field_str1, @@ -4997,8 +5004,8 @@ DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_da SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `field_str1` varchar(19) DEFAULT NULL, - `field1_str2` varchar(19) DEFAULT NULL, + `field_str1` varchar(19) CHARACTER SET utf8 DEFAULT NULL, + `field1_str2` varchar(19) CHARACTER SET utf8 DEFAULT NULL, `field_date` date DEFAULT NULL, `field_datetime` datetime DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -5009,8 +5016,8 @@ DATE_SUB('2007-08-03 17:33:00', INTERVAL 1 MINUTE) AS field1_str2, DATE_SUB(DATE('2007-08-03'), INTERVAL 1 DAY) AS field_date, DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE) AS field_datetime; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def field_str1 254 19 10 Y 128 0 63 -def field1_str2 254 19 19 Y 128 0 63 +def field_str1 254 57 10 Y 0 0 33 +def field1_str2 254 57 19 Y 0 0 33 def field_date 10 10 10 Y 128 0 63 def field_datetime 12 19 19 Y 128 0 63 field_str1 field1_str2 field_date field_datetime @@ -5023,6 +5030,37 @@ HEX(DATE_SUB(CAST('2007-08-03 17:33:00' AS DATETIME), INTERVAL 1 MINUTE)) AS fie field_str1 field1_str2 field_date field_datetime 323030372D30382D30322032333A35393A3030 323030372D30382D30332031373A33323A3030 323030372D30382D3032 323030372D30382D30332031373A33323A3030 # +# MDEV-4841 Wrong character set of ADDTIME() and DATE_ADD() +# +SELECT @@collation_connection, @@character_set_results; +@@collation_connection @@character_set_results +utf8_general_ci utf8 +SELECT +CHARSET(ADDTIME(_latin1'10:01:01',_latin1'10:00:00')) AS addtime1, +CHARSET(ADDTIME('10:01:01','10:00:00')) AS addtime2, +CHARSET(DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second)) AS date_add1, +CHARSET(DATE_ADD('2001-01-01 10:01:01',interval 10 second)) AS date_add2; +addtime1 addtime2 date_add1 date_add2 +utf8 utf8 utf8 utf8 +CREATE TABLE t1 AS +SELECT +ADDTIME(_latin1'10:01:01',_latin1'10:00:00') AS addtime1, +ADDTIME('10:01:01','10:00:00') AS addtime2, +DATE_ADD(_latin1'2001-01-01 10:01:01',interval 10 second) AS date_add1, +DATE_ADD('2001-01-01 10:01:01',interval 10 second) AS date_add2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `addtime1` varchar(26) CHARACTER SET utf8 DEFAULT NULL, + `addtime2` varchar(26) CHARACTER SET utf8 DEFAULT NULL, + `date_add1` varchar(19) CHARACTER SET utf8 DEFAULT NULL, + `date_add2` varchar(19) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t1; +addtime1 addtime2 date_add1 date_add2 +20:01:01 20:01:01 2001-01-01 10:01:11 2001-01-01 10:01:11 +DROP TABLE t1; +# # Bug#11926811 / Bug#60625 Illegal mix of collations # SELECT @@collation_connection; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index ef5e3487a99..68b1e0f04ad 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -2620,3 +2620,9 @@ id date1 date2 DATE_ADD(a.date1,INTERVAL -10 DAY) TO_DAYS(a.date1)-10 17 NULL NULL NULL NULL 18 2010-10-13 2010-10-03 2010-10-03 734413 DROP TABLE t1; +# +# MDEV-10524 Assertion `arg1_int >= 0' failed in Item_func_additive_op::result_precision() +# +SELECT 1 MOD ADDTIME( '13:58:57', '00:00:01' ) + 2; +1 MOD ADDTIME( '13:58:57', '00:00:01' ) + 2 +3 diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 45214aed6e7..92e1c38cec2 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1597,3 +1597,8 @@ INSERT INTO t1 VALUES (17, NULL); INSERT INTO t1 VALUES (18, '2010-10-13'); SELECT a.id,a.date1,FROM_DAYS(TO_DAYS(a.date1)-10) as date2, DATE_ADD(a.date1,INTERVAL -10 DAY),TO_DAYS(a.date1)-10 FROM t1 a ORDER BY a.id; DROP TABLE t1; + +--echo # +--echo # MDEV-10524 Assertion `arg1_int >= 0' failed in Item_func_additive_op::result_precision() +--echo # +SELECT 1 MOD ADDTIME( '13:58:57', '00:00:01' ) + 2; diff --git a/sql/item_func.h b/sql/item_func.h index 667be3c0438..0da38e22c7f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -39,6 +39,7 @@ protected: 0 means get this number from first argument */ uint allowed_arg_cols; + String *val_str_from_val_str_ascii(String *str, String *str2); void count_only_length(Item **item, uint nitems); void count_real_length(Item **item, uint nitems); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 94370d45cef..ec9580bfabd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -70,7 +70,7 @@ size_t username_char_length= 16; Normally conversion does not happen, and val_str_ascii() is immediately returned instead. */ -String *Item_str_func::val_str_from_val_str_ascii(String *str, String *str2) +String *Item_func::val_str_from_val_str_ascii(String *str, String *str2) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 7606c281548..00ae60a7fb1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -62,7 +62,6 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref); - String *val_str_from_val_str_ascii(String *str, String *str2); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 28e93683422..420fb29f518 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1455,25 +1455,29 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval) void Item_temporal_func::fix_length_and_dec() { + uint char_length= mysql_temporal_int_part_length(field_type()); /* We set maybe_null to 1 as default as any bad argument with date or time can get us to return NULL. */ maybe_null= 1; - max_length= mysql_temporal_int_part_length(field_type()); + if (decimals) { if (decimals == NOT_FIXED_DEC) - max_length+= TIME_SECOND_PART_DIGITS + 1; + char_length+= TIME_SECOND_PART_DIGITS + 1; else { set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - max_length+= decimals + 1; + char_length+= decimals + 1; } } sql_mode= current_thd->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE); - collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + collation.set(field_type() == MYSQL_TYPE_STRING ? + default_charset() : &my_charset_numeric, + DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + fix_char_length(char_length); } String *Item_temporal_func::val_str(String *str) @@ -1483,6 +1487,23 @@ String *Item_temporal_func::val_str(String *str) } +String *Item_temporal_hybrid_func::val_str_ascii(String *str) +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + + if (get_date(<ime, 0) || + (null_value= my_TIME_to_str(<ime, str, decimals))) + return (String *) 0; + + /* Check that the returned timestamp type matches to the function type */ + DBUG_ASSERT(cached_field_type == MYSQL_TYPE_STRING || + ltime.time_type == MYSQL_TIMESTAMP_NONE || + mysql_type_to_time_type(cached_field_type) == ltime.time_type); + return str; +} + + bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { longlong value=args[0]->val_int(); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 3a03ee4b27a..0062d500835 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -506,6 +506,50 @@ public: }; +/** + Abstract class for functions returning TIME, DATE, DATETIME or string values, + whose data type depends on parameters and is set at fix_fields time. +*/ +class Item_temporal_hybrid_func: public Item_temporal_func +{ +protected: + enum_field_types cached_field_type; // TIME, DATE, DATETIME or STRING + String ascii_buf; // Conversion buffer +public: + Item_temporal_hybrid_func(Item *a,Item *b) + :Item_temporal_func(a,b) {} + enum_field_types field_type() const { return cached_field_type; } + Item_result cmp_type() const + { + return cached_field_type == MYSQL_TYPE_STRING ? + STRING_RESULT : TIME_RESULT; + } + const CHARSET_INFO *charset_for_protocol() const + { + /* + Can return TIME, DATE, DATETIME or VARCHAR depending on arguments. + Send using "binary" when TIME, DATE or DATETIME, + or using collation.collation when VARCHAR + (which is fixed from @@collation_connection in fix_length_and_dec). + */ + DBUG_ASSERT(fixed == 1); + return cached_field_type == MYSQL_TYPE_STRING ? + collation.collation : &my_charset_bin; + } + /** + Return string value in ASCII character set. + */ + String *val_str_ascii(String *str); + /** + Return string value in @@character_set_connection. + */ + String *val_str(String *str) + { + return val_str_from_val_str_ascii(str, &ascii_buf); + } +}; + + class Item_datefunc :public Item_temporal_func { public: @@ -763,17 +807,15 @@ public: }; -class Item_date_add_interval :public Item_temporal_func +class Item_date_add_interval :public Item_temporal_hybrid_func { - enum_field_types cached_field_type; public: const interval_type int_type; // keep it public const bool date_sub_interval; // keep it public Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg) - :Item_temporal_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} + :Item_temporal_hybrid_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} const char *func_name() const { return "date_add_interval"; } void fix_length_and_dec(); - enum_field_types field_type() const { return cached_field_type; } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; void print(String *str, enum_query_type query_type); @@ -911,16 +953,14 @@ public: }; -class Item_func_add_time :public Item_temporal_func +class Item_func_add_time :public Item_temporal_hybrid_func { const bool is_date; int sign; - enum_field_types cached_field_type; public: Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) - :Item_temporal_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } - enum_field_types field_type() const { return cached_field_type; } + :Item_temporal_hybrid_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } void fix_length_and_dec(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); void print(String *str, enum_query_type query_type); @@ -1019,9 +1059,8 @@ public: }; -class Item_func_str_to_date :public Item_temporal_func +class Item_func_str_to_date :public Item_temporal_hybrid_func { - enum_field_types cached_field_type; timestamp_type cached_timestamp_type; bool const_item; String subject_converter; @@ -1029,12 +1068,11 @@ class Item_func_str_to_date :public Item_temporal_func CHARSET_INFO *internal_charset; public: Item_func_str_to_date(Item *a, Item *b) - :Item_temporal_func(a, b), const_item(false), + :Item_temporal_hybrid_func(a, b), const_item(false), internal_charset(NULL) {} bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *func_name() const { return "str_to_date"; } - enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); }; diff --git a/sql/sql_const.h b/sql/sql_const.h index 9d227601a20..3c127a03826 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -54,7 +54,7 @@ #define MIN_TIME_WIDTH 10 /* -HHH:MM:SS */ #define MAX_TIME_WIDTH 16 /* -DDDDDD HH:MM:SS */ #define MAX_TIME_FULL_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ -#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */ +#define MAX_DATETIME_FULL_WIDTH 26 /* YYYY-MM-DD HH:MM:SS.###### */ #define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */ #define MAX_DATETIME_PRECISION 6 diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c5c65391758..d912a7b78d6 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -838,6 +838,23 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, } } + +/** + Convert TIME/DATE/DATETIME value to String. + @param l_time DATE value + @param OUT str String to convert to + @param dec Number of fractional digits. +*/ +bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec) +{ + if (str->alloc(MAX_DATE_STRING_REP_LENGTH)) + return true; + str->set_charset(&my_charset_numeric); + str->length(my_TIME_to_str(ltime, const_cast(str->ptr()), dec)); + return false; +} + + void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, const ErrConv *sval, diff --git a/sql/sql_time.h b/sql/sql_time.h index ad752121044..9becdcd4200 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -74,6 +74,8 @@ extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format); const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, timestamp_type type); +bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec); + /* MYSQL_TIME operations */ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval); From 19896d4b3ab459d135aee6ee67cb92bce92f9b87 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 19 Dec 2016 16:09:20 +0400 Subject: [PATCH 049/124] MDEV-10274 Bundling insert with create statement for table with unsigned Decimal primary key issues warning 1194. Flags are important for key_length calculations, so them should be set before it, not after. --- mysql-test/r/create.result | 7 +++++++ mysql-test/t/create.test | 9 +++++++++ sql/sql_table.cc | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 0164aa4b610..829b54dea49 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2498,4 +2498,11 @@ end| create table t1 as select f1(); ERROR 42S02: Table 'test.t1' doesn't exist drop function f1; +# +# MDEV-10274 Bundling insert with create statement +# for table with unsigned Decimal primary key issues warning 1194 +# +create table t1(ID decimal(2,1) unsigned NOT NULL, PRIMARY KEY (ID))engine=memory +select 2.1 ID; +drop table t1; End of 5.5 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 5c90c3e17a4..1e77dac9bc9 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -2081,4 +2081,13 @@ DELIMITER ;| create table t1 as select f1(); drop function f1; +--echo # +--echo # MDEV-10274 Bundling insert with create statement +--echo # for table with unsigned Decimal primary key issues warning 1194 +--echo # + +create table t1(ID decimal(2,1) unsigned NOT NULL, PRIMARY KEY (ID))engine=memory + select 2.1 ID; +drop table t1; + --echo End of 5.5 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7d2e67b5cfd..9bcb4c3f8cc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3167,7 +3167,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->pack_length= dup_field->pack_length; sql_field->key_length= dup_field->key_length; sql_field->decimals= dup_field->decimals; - sql_field->create_length_to_internal_length(); sql_field->unireg_check= dup_field->unireg_check; /* We're making one field from two, the result field will have @@ -3177,6 +3176,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields--; sql_field->flags= dup_field->flags; + sql_field->create_length_to_internal_length(); sql_field->interval= dup_field->interval; sql_field->vcol_info= dup_field->vcol_info; sql_field->stored_in_db= dup_field->stored_in_db; From 268bb69beaec027b9f713d13316aa78c5c292817 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 16 Dec 2016 17:08:31 +0300 Subject: [PATCH 050/124] MDEV-7691: Assertion `outer_context || !*from_field || *from_field == not_found_field' ... The bug occurred when a subquery - has a reference to outside, to grand-parent query or further up - is converted to a semi-join (i.e. merged into its parent). Then the reference to outside had form Item_ref(Item_field(...)). - Conversion to semi-join would call item->fix_after_pullout() for the outside reference. - Item_ref::fix_after_pullout would call Item_field->fix_after_pullout - The Item_field would construct a new Name_resolution_context object This process ignored the fact that the Item_field does not belong to any of the subselects being flattened. The result was crash in the next call to Item_field::fix_fields(), where we would try to use an invalid Name_resolution_context object. Fixed by not creating Name_resolution_context object if the Item_field's context does not belong to the subselect(s) that were flattened. --- mysql-test/r/subselect4.result | 39 ++++++++++++++++++++++++++++++++ mysql-test/t/subselect4.test | 41 ++++++++++++++++++++++++++++++++++ sql/item.cc | 38 +++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index c7f22cf05e5..89fb0902f53 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2410,5 +2410,44 @@ SELECT x FROM t1 WHERE id > (SELECT MAX(id) - 1000 FROM t1) ORDER BY x LIMIT 1; x 0 drop table t1; +# +# MDEV-7691: Assertion `outer_context || !*from_field || *from_field == not_found_field' ... +# +set optimizer_switch=default; +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (4),(6); +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(8); +PREPARE stmt FROM " +SELECT * FROM t2 +HAVING 0 IN ( + SELECT a FROM t1 + WHERE a IN ( + SELECT a FROM t1 + WHERE b = a + ) +) +"; +EXECUTE stmt; +b +EXECUTE stmt; +b +# Alternative test case, without HAVING +CREATE TABLE t3 (i INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (4),(6); +PREPARE stmt FROM " +SELECT * FROM t3 AS t10 +WHERE EXISTS ( + SELECT * FROM t3 AS t20 WHERE t10.i IN ( + SELECT i FROM t3 + ) +)"; +EXECUTE stmt; +i +6 +EXECUTE stmt; +i +6 +drop table t1, t2, t3; SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index b179ead39d7..7a7dd7e492e 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -1959,5 +1959,46 @@ SELECT x FROM t1 WHERE id > (SELECT MAX(id) - 1000 FROM t1) ORDER BY x LIMIT 1; drop table t1; +--echo # +--echo # MDEV-7691: Assertion `outer_context || !*from_field || *from_field == not_found_field' ... +--echo # +set optimizer_switch=default; +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (4),(6); + +CREATE TABLE t2 (b INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(8); + +PREPARE stmt FROM " +SELECT * FROM t2 +HAVING 0 IN ( + SELECT a FROM t1 + WHERE a IN ( + SELECT a FROM t1 + WHERE b = a + ) +) +"; + +EXECUTE stmt; +EXECUTE stmt; + +--echo # Alternative test case, without HAVING +CREATE TABLE t3 (i INT) ENGINE=MyISAM; +INSERT INTO t3 VALUES (4),(6); + +PREPARE stmt FROM " +SELECT * FROM t3 AS t10 +WHERE EXISTS ( + SELECT * FROM t3 AS t20 WHERE t10.i IN ( + SELECT i FROM t3 + ) +)"; + +EXECUTE stmt; +EXECUTE stmt; + +drop table t1, t2, t3; + SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; diff --git a/sql/item.cc b/sql/item.cc index 53666aaf83d..fc9eb31bf5b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2777,6 +2777,44 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) depended_from= NULL; if (context) { + bool need_change= false; + /* + Suppose there are nested selects: + + select_id=1 + select_id=2 + select_id=3 <----+ + select_id=4 -+ + select_id=5 --+ + + Suppose, pullout operation has moved anything that had select_id=4 or 5 + in to select_id=3. + + If this Item_field had a name resolution context pointing into select_lex + with id=4 or id=5, it needs a new name resolution context. + + However, it could also be that this object is a part of outer reference: + Item_ref(Item_field(field in select with select_id=1))). + - The Item_ref object has a context with select_id=5, and so needs a new + name resolution context. + - The Item_field object has a context with select_id=1, and doesn't need + a new name resolution context. + + So, the following loop walks from Item_field's current context upwards. + If we find that the select we've been pulled out to is up there, we + create the new name resolution context. Otherwise, we don't. + */ + for (Name_resolution_context *ct= context; ct; ct= ct->outer_context) + { + if (new_parent == ct->select_lex) + { + need_change= true; + break; + } + } + if (!need_change) + return; + Name_resolution_context *ctx= new Name_resolution_context(); if (context->select_lex == new_parent) { From f23b41b9b8a30e0e54a1ec7a8923057b0e57e0f5 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 16 Dec 2016 17:16:02 +0300 Subject: [PATCH 051/124] MDEV-10148: Database crashes in the query to the View Fix st_select_lex::is_merged_child_of to work across merged views or derived tables. --- mysql-test/r/subselect2.result | 35 ++++++++++++++++++++++++++++++++ mysql-test/t/subselect2.test | 37 ++++++++++++++++++++++++++++++++++ sql/sql_lex.cc | 6 ++++++ 3 files changed, 78 insertions(+) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 72ca9d33354..b6dc940d9fb 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -348,4 +348,39 @@ where t1.a = t2.a and ( t1.a = ( select min(a) from t1 ) or 0 ); a a a FRA FRA FRA drop table t1,t2,t3; +# +# MDEV-10148: Database crashes in the query to the View +# +CREATE TABLE t1 ( +key_code INT(11) NOT NULL, +value_string VARCHAR(50) NULL DEFAULT NULL, +PRIMARY KEY (key_code) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; +CREATE TABLE t2 ( +key_code INT(11) NOT NULL, +target_date DATE NULL DEFAULT NULL, +PRIMARY KEY (key_code) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; +CREATE TABLE t3 ( +now_date DATE NOT NULL, +PRIMARY KEY (now_date) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; +CREATE VIEW v1 +AS +SELECT +B.key_code, +B.target_date +FROM +t2 B INNER JOIN t3 C ON +B.target_date = C.now_date +; +SET @s = 'SELECT A.* FROM t1 A WHERE A.key_code IN (SELECT key_code FROM v1)'; +PREPARE stmt FROM @s; +EXECUTE stmt; +key_code value_string +EXECUTE stmt; +key_code value_string +DEALLOCATE PREPARE stmt; +DROP VIEW v1; +DROP TABLE t1,t2,t3; set optimizer_switch=@subselect2_test_tmp; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index b3c1322184d..f795cef648c 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -359,5 +359,42 @@ where t1.a = t2.a and ( t1.a = ( select min(a) from t1 ) or 0 ); drop table t1,t2,t3; +--echo # +--echo # MDEV-10148: Database crashes in the query to the View +--echo # +CREATE TABLE t1 ( + key_code INT(11) NOT NULL, + value_string VARCHAR(50) NULL DEFAULT NULL, + PRIMARY KEY (key_code) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; + +CREATE TABLE t2 ( + key_code INT(11) NOT NULL, + target_date DATE NULL DEFAULT NULL, + PRIMARY KEY (key_code) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; + +CREATE TABLE t3 ( + now_date DATE NOT NULL, + PRIMARY KEY (now_date) +) COLLATE='utf8_general_ci' ENGINE=InnoDB ; + +CREATE VIEW v1 +AS +SELECT + B.key_code, + B.target_date +FROM + t2 B INNER JOIN t3 C ON + B.target_date = C.now_date +; +SET @s = 'SELECT A.* FROM t1 A WHERE A.key_code IN (SELECT key_code FROM v1)'; +PREPARE stmt FROM @s; +EXECUTE stmt; #1st time -> success +EXECUTE stmt; #2nd time -> crash +DEALLOCATE PREPARE stmt; +DROP VIEW v1; +DROP TABLE t1,t2,t3; + set optimizer_switch=@subselect2_test_tmp; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f2e7b4f7c3a..fa866bc7008 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4247,6 +4247,12 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) { continue; } + + if (sl->master_unit()->derived && + sl->master_unit()->derived->is_merged_derived()) + { + continue; + } all_merged= FALSE; break; } From aaff3d6c35f51dde60907f3c0fc4b2a40bc63c38 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 20 Dec 2016 10:25:25 +0100 Subject: [PATCH 052/124] MDEV-10172: UNION query returns incorrect rows outside conditional evaluation count duplicate of UNION SELECT separately to awoid influence on lokal LIMIT clause. --- mysql-test/r/union.result | 33 ++++++++++++++++++++++++++++----- mysql-test/t/union.test | 22 +++++++++++++++++++++- sql/sql_select.cc | 13 +++++++++---- sql/sql_select.h | 5 +++-- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 40f5a77e3d0..5a6cd8907e9 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -362,7 +362,7 @@ a 2 select found_rows(); found_rows() -6 +5 SELECT SQL_CALC_FOUND_ROWS * FROM t1 UNION SELECT * FROM t2 LIMIT 100; a 1 @@ -1169,12 +1169,9 @@ a b select * from ((select * from t1 limit 1) union (select * from t1 limit 1)) a; a b 1 a -2 b select * from ((select * from t1 limit 1) union (select * from t1 limit 1) union (select * from t1 limit 1)) a; a b 1 a -2 b -3 c select * from ((((select * from t1))) union (select * from t1) union (select * from t1)) a; a b 1 a @@ -1553,7 +1550,6 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Using filesort Warnings: Note 1003 select NULL AS `a` from `test`.`t1` union select NULL AS `a` from `test`.`t1` order by `a` DROP TABLE t1; -End of 5.0 tests # # Bug#32858: Error: "Incorrect usage of UNION and INTO" does not take # subselects into account @@ -1659,6 +1655,14 @@ a 4 5 6 +(select a from t1 where false) UNION (select a from t1) limit 8; +a +10 +2 +3 +4 +5 +6 7 8 drop table t1; @@ -1955,3 +1959,22 @@ cccc bbbb dddd drop table t1; +# +# MDEV-10172: UNION query returns incorrect rows outside +# conditional evaluation +# +create table t1 (d datetime not null primary key); +insert into t1(d) values ('2016-06-01'),('2016-06-02'),('2016-06-03'),('2016-06-04'); +select * from +( +select * from t1 where d between '2016-06-02' and '2016-06-05' + union +(select * from t1 where d < '2016-06-05' order by d desc limit 1) +) onlyJun2toJun4 +order by d; +d +2016-06-02 00:00:00 +2016-06-03 00:00:00 +2016-06-04 00:00:00 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 9204ddd22e5..f4dc6a5d449 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1022,7 +1022,6 @@ ORDER BY a; DROP TABLE t1; ---echo End of 5.0 tests -- echo # -- echo # Bug#32858: Error: "Incorrect usage of UNION and INTO" does not take -- echo # subselects into account @@ -1126,6 +1125,8 @@ create table t1 (a int); insert into t1 values (10),(10),(10),(2),(3),(4),(5),(6),(7),(8),(9),(1),(10); --sorted_result select a from t1 where false UNION select a from t1 limit 8; +--sorted_result +(select a from t1 where false) UNION (select a from t1) limit 8; drop table t1; --echo # @@ -1350,3 +1351,22 @@ UNION ; drop table t1; + + +--echo # +--echo # MDEV-10172: UNION query returns incorrect rows outside +--echo # conditional evaluation +--echo # + +create table t1 (d datetime not null primary key); +insert into t1(d) values ('2016-06-01'),('2016-06-02'),('2016-06-03'),('2016-06-04'); +select * from +( + select * from t1 where d between '2016-06-02' and '2016-06-05' + union + (select * from t1 where d < '2016-06-05' order by d desc limit 1) +) onlyJun2toJun4 +order by d; +drop table t1; + +--echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8c994964d59..839665f3a9f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2871,7 +2871,7 @@ JOIN::exec() *curr_fields_list), Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); error= do_select(curr_join, curr_fields_list, NULL, procedure); - thd->limit_found_rows= curr_join->send_records; + thd->limit_found_rows= curr_join->send_records - curr_join->duplicate_rows; /* Accumulate the counts from all join iterations of all join parts. */ thd->examined_row_count+= curr_join->examined_rows; @@ -16578,7 +16578,7 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) join->join_tab[join->top_join_tab_count - 1].next_select= end_select; join_tab=join->join_tab+join->const_tables; } - join->send_records=0; + join->duplicate_rows= join->send_records=0; if (join->table_count == join->const_tables) { /* @@ -18089,7 +18089,12 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int error; /* result < 0 if row was not accepted and should not be counted */ if ((error= join->result->send_data(*join->fields))) - DBUG_RETURN(error < 0 ? NESTED_LOOP_OK : NESTED_LOOP_ERROR); + { + if (error > 0) + DBUG_RETURN(NESTED_LOOP_ERROR); + // error < 0 => duplicate row + join->duplicate_rows++; + } } if (++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) @@ -18205,7 +18210,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (error < 0) { /* Duplicate row, don't count */ - join->send_records--; + join->duplicate_rows++; error= 0; } } diff --git a/sql/sql_select.h b/sql/sql_select.h index 4650bc24c68..0623672840e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1018,7 +1018,8 @@ public: table_map outer_join; /* Bitmap of tables used in the select list items */ table_map select_list_used_tables; - ha_rows send_records,found_records,examined_rows,row_limit, select_limit; + ha_rows send_records, found_records, examined_rows, + row_limit, select_limit, duplicate_rows; /** Used to fetch no more than given amount of rows per one fetch operation of server side cursor. @@ -1272,7 +1273,7 @@ public: sort_and_group= 0; first_record= 0; do_send_rows= 1; - send_records= 0; + duplicate_rows= send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; examined_rows= 0; From e025ebcdb538ee6d191d22aee0587f5534080a4b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 20 Dec 2016 12:45:48 +0000 Subject: [PATCH 053/124] Fix pointer formatting in crash handler output. Do not use 0x%p to output thd address, use %p --- sql/signal_handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index b0c67fbfe32..81792cc30ac 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -143,7 +143,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) if (opt_stack_trace) { - my_safe_printf_stderr("Thread pointer: 0x%p\n", thd); + my_safe_printf_stderr("Thread pointer: %p\n", thd); my_safe_printf_stderr("%s", "Attempting backtrace. You can use the following " "information to find out\n" From cbd7548aff7536940cf6c619c4de4f51c1f9e0bb Mon Sep 17 00:00:00 2001 From: Ronak Jain Date: Thu, 8 Dec 2016 23:27:04 +0530 Subject: [PATCH 054/124] MDEV-11353: fixes Identical logical conditions --- sql/handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/handler.cc b/sql/handler.cc index 5fc75602039..bc71aa57fb7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3924,7 +3924,7 @@ void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info, stat_info->update_time= stats.update_time; stat_info->check_time= stats.check_time; stat_info->check_sum= 0; - if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_OLD_CHECKSUM)) + if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM)) stat_info->check_sum= checksum(); return; } From ef82fd8ca33f0ecab06ddfa11b51dd5ea9019653 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 20 Dec 2016 17:42:08 +0400 Subject: [PATCH 055/124] MDEV-11353 - Identical logical conditions Added test case. --- mysql-test/r/information_schema_part.result | 8 ++++++++ mysql-test/t/information_schema_part.test | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/mysql-test/r/information_schema_part.result b/mysql-test/r/information_schema_part.result index b34183ebdee..77959de256e 100644 --- a/mysql-test/r/information_schema_part.result +++ b/mysql-test/r/information_schema_part.result @@ -151,3 +151,11 @@ select create_options from information_schema.tables where table_schema="test"; create_options partitioned drop table t1; +# +# MDEV-11353 - Identical logical conditions +# +CREATE TABLE t1(a INT) CHECKSUM=1 SELECT 1; +SELECT CHECKSUM FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; +CHECKSUM +3036305396 +DROP TABLE t1; diff --git a/mysql-test/t/information_schema_part.test b/mysql-test/t/information_schema_part.test index f1415d12f79..ea88f364c07 100644 --- a/mysql-test/t/information_schema_part.test +++ b/mysql-test/t/information_schema_part.test @@ -131,3 +131,10 @@ drop table if exists t1; create table t1 (f1 int key) partition by key(f1) partitions 2; select create_options from information_schema.tables where table_schema="test"; drop table t1; + +--echo # +--echo # MDEV-11353 - Identical logical conditions +--echo # +CREATE TABLE t1(a INT) CHECKSUM=1 SELECT 1; +SELECT CHECKSUM FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; +DROP TABLE t1; From be430b80df0cdd4eba32df1570195721dbfd1b39 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Wed, 21 Dec 2016 09:34:37 +0530 Subject: [PATCH 056/124] MDEV-11490 Galera_3nodes test suite does not suppress Warnings. Problem:- While running individual tests of Galera_3nodes , We get warnings like '[Warning] WSREP: Could not open state file for reading: '. And because of this individual tests fails. Solution:- We change suite.pm of Galera_3nodes to supress these warnings. --- mysql-test/suite/galera_3nodes/suite.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera_3nodes/suite.pm b/mysql-test/suite/galera_3nodes/suite.pm index 39d5acbcc1b..c91e6e07d76 100644 --- a/mysql-test/suite/galera_3nodes/suite.pm +++ b/mysql-test/suite/galera_3nodes/suite.pm @@ -26,6 +26,7 @@ push @::global_suppressions, ( qr(WSREP: wsrep_sst_receive_address is set to '127.0.0.1), qr(WSREP: Could not open saved state file for reading: ), + qr(WSREP: Could not open state file for reading: ), qr(WSREP: Gap in state sequence. Need state transfer.), qr(WSREP: Failed to prepare for incremental state transfer:), qr(WSREP:.*down context.*), @@ -33,13 +34,14 @@ push @::global_suppressions, qr(WSREP: last inactive check more than .* skipping check), qr(WSREP: SQL statement was ineffective), qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.), - qr|WSREP: access file\(gvwstate.dat\) failed\(No such file or directory\)|, + qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|, qr(WSREP: Quorum: No node with complete state), qr(WSREP: Initial position was provided by configuration or SST, avoiding override), qr|WSREP: discarding established \(time wait\) .*|, qr(WSREP: There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside. Will use that one.), qr(WSREP: evs::proto.*), qr|WSREP: Ignoring possible split-brain (allowed by configuration) from view:.*|, + qr(WSREP: Member .* requested state transfer from .* but it is impossible to select State Transfer donor: Resource temporarily unavailable), qr(WSREP: Could not find peer:), qr(WSREP: Protocol violation. JOIN message sender .*), qr(WSREP: JOIN message from member [0-9]* in non-primary configuration. Ignored.), From 5e051bfa15d201228b103d7f536436a61cde8707 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 21 Dec 2016 15:39:45 +0400 Subject: [PATCH 057/124] MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) The patch b96c196f1cd5d77e524cbf952539bdd33c65ffc1 added a new call for safe_charset_converter() without a corresponding fix_fields(). In case of a sub-query the created Item remained in non-fixed state. The problem did not show up with literal derived expressions, only subselects were affected. This patch adds a corresponding fix_fields() to the previously added safe_charset_converter(). --- mysql-test/r/subselect.result | 11 +++++++++++ mysql-test/r/subselect_no_mat.result | 11 +++++++++++ mysql-test/r/subselect_no_opts.result | 11 +++++++++++ mysql-test/r/subselect_no_scache.result | 11 +++++++++++ mysql-test/r/subselect_no_semijoin.result | 11 +++++++++++ mysql-test/t/subselect.test | 10 ++++++++++ sql/item.cc | 3 ++- 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 0a599a64f80..789cfe2fdca 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -7105,3 +7105,14 @@ group by round((select 1 from t1 limit 1)); round((select 1 from t1 limit 1)) 1 drop table t1; +# +# MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +# +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +f1 f2 +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +f1 f2 +foo bar +DROP TABLE t1; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index b819b1e4ef9..c729c17f94f 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -7102,6 +7102,17 @@ group by round((select 1 from t1 limit 1)); round((select 1 from t1 limit 1)) 1 drop table t1; +# +# MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +# +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +f1 f2 +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +f1 f2 +foo bar +DROP TABLE t1; set optimizer_switch=default; select @@optimizer_switch like '%materialization=on%'; @@optimizer_switch like '%materialization=on%' diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index e1001a51658..dc308ea77e5 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -7100,4 +7100,15 @@ group by round((select 1 from t1 limit 1)); round((select 1 from t1 limit 1)) 1 drop table t1; +# +# MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +# +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +f1 f2 +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +f1 f2 +foo bar +DROP TABLE t1; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index e175e7e0072..e7c85c10f2d 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -7111,6 +7111,17 @@ group by round((select 1 from t1 limit 1)); round((select 1 from t1 limit 1)) 1 drop table t1; +# +# MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +# +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +f1 f2 +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +f1 f2 +foo bar +DROP TABLE t1; set optimizer_switch=default; select @@optimizer_switch like '%subquery_cache=on%'; @@optimizer_switch like '%subquery_cache=on%' diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index a211d498762..b6261f05098 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -7100,5 +7100,16 @@ group by round((select 1 from t1 limit 1)); round((select 1 from t1 limit 1)) 1 drop table t1; +# +# MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +# +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +f1 f2 +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +f1 f2 +foo bar +DROP TABLE t1; set @optimizer_switch_for_subselect_test=null; set @join_cache_level_for_subselect_test=NULL; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 77b6c6c5582..a8ad3ba52a5 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -5988,3 +5988,13 @@ from t1 group by round((select 1 from t1 limit 1)); drop table t1; + +--echo # +--echo # MDEV-10386 Assertion `fixed == 1' failed in virtual String* Item_func_conv_charset::val_str(String*) +--echo # + +CREATE TABLE t1 (f1 CHAR(3) CHARACTER SET utf8 NULL, f2 CHAR(3) CHARACTER SET latin1 NULL); +INSERT INTO t1 VALUES ('foo','bar'); +SELECT * FROM t1 WHERE f2 >= SOME ( SELECT f1 FROM t1 ); +SELECT * FROM t1 WHERE f2 <= SOME ( SELECT f1 FROM t1 ); +DROP TABLE t1; diff --git a/sql/item.cc b/sql/item.cc index fc9eb31bf5b..1df91dc2534 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1164,7 +1164,8 @@ Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs) if (conv == example) return this; Item_cache *cache; - if (!conv || !(cache= new Item_cache_str(conv))) + if (!conv || conv->fix_fields(current_thd, (Item **) NULL) || + !(cache= new Item_cache_str(conv))) return NULL; // Safe conversion is not possible, or OEM cache->setup(conv); cache->fixed= false; // Make Item::fix_fields() happy From 706fb790bcf9105a73f34002fe28c75032267c4b Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 22 Dec 2016 15:51:37 +0530 Subject: [PATCH 058/124] MDEV-10927: Crash When Using sort_union Optimization In file sql/filesort.cc,when merge_buffers() is called then - queue_remove(&queue,0) is called - For the function queue_remove there is assertion states that the element to be removed should have index >=1 - this is causing the assertion to fail. Fixed by removing the top element. --- mysql-test/r/index_merge_innodb.result | 29 ++++++++++++++++++++++ mysql-test/t/index_merge_innodb.test | 33 +++++++++++++++++++++++++- sql/filesort.cc | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index b93d15f7bef..00cbf35ec69 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -793,3 +793,32 @@ a b c 9 d d DROP TABLE t1; set optimizer_switch= @optimizer_switch_save; +# +# MDEV-10927: Crash When Using sort_union Optimization +# +set @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='index_merge_sort_intersection=on'; +SET SESSION sort_buffer_size = 1024; +create table t1 ( +pk int(11) NOT NULL AUTO_INCREMENT, +col1 int(11) NOT NULL, +col2 int(11) NOT NULL, +col3 int(11) NOT NULL, +key2 int(11) NOT NULL, +col4 int(11) NOT NULL, +key1 int(11) NOT NULL, +PRIMARY KEY (pk), +KEY key1 (key1), +KEY key2 (key2) +) ENGINE=InnoDB AUTO_INCREMENT=12860259 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; +create table t2(a int); +insert into t2 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t3(a int); +insert into t3 select A.a + B.a* 10 + C.a * 100 + D.a*1000 from t2 A, t2 B, t2 C, t2 D; +insert into t1 (key1, key2, col1,col2,col3,col4) +select a,a, a,a,a,a from t3; +SELECT sum(col1) FROM t1 FORCE INDEX (key1,key2) WHERE (key1 between 10 and 8191+10) or (key2= 5); +sum(col1) +33632261 +drop table t1,t2,t3; +set optimizer_switch=@tmp_optimizer_switch; diff --git a/mysql-test/t/index_merge_innodb.test b/mysql-test/t/index_merge_innodb.test index 6a1cb53dc40..fb56e44b5ae 100644 --- a/mysql-test/t/index_merge_innodb.test +++ b/mysql-test/t/index_merge_innodb.test @@ -171,6 +171,37 @@ WHERE ( tb.b != ta.b OR tb.a = ta.a ) AND ( tb.b = ta.c OR tb.b = ta.b ); DROP TABLE t1; - set optimizer_switch= @optimizer_switch_save; +--echo # +--echo # MDEV-10927: Crash When Using sort_union Optimization +--echo # + +set @tmp_optimizer_switch=@@optimizer_switch; +SET optimizer_switch='index_merge_sort_intersection=on'; +SET SESSION sort_buffer_size = 1024; + +create table t1 ( +pk int(11) NOT NULL AUTO_INCREMENT, +col1 int(11) NOT NULL, +col2 int(11) NOT NULL, +col3 int(11) NOT NULL, +key2 int(11) NOT NULL, +col4 int(11) NOT NULL, +key1 int(11) NOT NULL, +PRIMARY KEY (pk), +KEY key1 (key1), +KEY key2 (key2) +) ENGINE=InnoDB AUTO_INCREMENT=12860259 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; + +create table t2(a int); +insert into t2 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +create table t3(a int); +insert into t3 select A.a + B.a* 10 + C.a * 100 + D.a*1000 from t2 A, t2 B, t2 C, t2 D; + +insert into t1 (key1, key2, col1,col2,col3,col4) +select a,a, a,a,a,a from t3; +SELECT sum(col1) FROM t1 FORCE INDEX (key1,key2) WHERE (key1 between 10 and 8191+10) or (key2= 5); +drop table t1,t2,t3; +set optimizer_switch=@tmp_optimizer_switch; diff --git a/sql/filesort.cc b/sql/filesort.cc index 5bb5c64409a..38404b01cf7 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1411,7 +1411,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file, if (!(error= (int) read_to_buffer(from_file, buffpek, rec_length))) { - queue_remove(&queue,0); + (void) queue_remove_top(&queue); reuse_freed_buff(&queue, buffpek, rec_length); } else if (error == -1) From c8e49f2f57b7e8c9dcf3cdb108dc15e6b63b4dc4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 20 Dec 2016 15:17:59 +0100 Subject: [PATCH 059/124] move check_user/set_user from mysqld.cc to mysys --- include/my_sys.h | 4 +++ mysys/CMakeLists.txt | 4 +-- mysys/my_setuser.c | 81 ++++++++++++++++++++++++++++++++++++++++++ sql/mysqld.cc | 83 ++++++-------------------------------------- 4 files changed, 98 insertions(+), 74 deletions(-) create mode 100644 mysys/my_setuser.c diff --git a/include/my_sys.h b/include/my_sys.h index 001769a0b76..5392a94d27e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -602,8 +602,12 @@ extern void *my_memmem(const void *haystack, size_t haystacklen, #ifdef _WIN32 extern int my_access(const char *path, int amode); +#define my_check_user(A,B) (NULL) +#define my_set_user(A,B,C) (0) #else #define my_access access +struct passwd *my_check_user(const char *user, myf MyFlags); +int my_set_user(const char *user, struct passwd *user_info, myf MyFlags); #endif extern int check_if_legal_filename(const char *path); diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 06a811f0994..cb86850c2de 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -34,7 +34,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c rijndael.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c lf_alloc-pin.c lf_dynarray.c lf_hash.c - safemalloc.c my_new.cc + safemalloc.c my_new.cc my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c my_rdtsc.c my_context.c file_logger.c) @@ -44,7 +44,7 @@ IF (WIN32) ENDIF() IF(UNIX) - SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_addr_resolve.c) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_addr_resolve.c my_setuser.c) ENDIF() IF(HAVE_ALARM) diff --git a/mysys/my_setuser.c b/mysys/my_setuser.c new file mode 100644 index 00000000000..1f3e7770d4c --- /dev/null +++ b/mysys/my_setuser.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif + +struct passwd *my_check_user(const char *user, myf MyFlags) +{ + struct passwd *user_info; + uid_t user_id= geteuid(); + DBUG_ENTER("my_check_user"); + + // Don't bother if we aren't superuser + if (user_id) + { + if (user) + { + /* Don't give a warning, if real user is same as given with --user */ + user_info= getpwnam(user); + if (!user_info || user_id != user_info->pw_uid) + { + my_errno= EPERM; + if (MyFlags & MY_WME) + my_printf_error(my_errno, "One can only use the --user switch if " + "running as root", MYF(ME_JUST_WARNING|ME_NOREFRESH)); + } + } + DBUG_RETURN(NULL); + } + if (!user) + { + if (MyFlags & MY_FAE) + { + my_errno= EINVAL; + my_printf_error(my_errno, "Please consult the Knowledge Base to find " + "out how to run mysqld as root!", MYF(ME_NOREFRESH)); + } + DBUG_RETURN(NULL); + } + if (!strcmp(user,"root")) + DBUG_RETURN(NULL); + + if (!(user_info= getpwnam(user))) + { + // Allow a numeric uid to be used + int err= 0; + user_id= my_strtoll10(user, NULL, &err); + if (err || !(user_info= getpwuid(user_id))) + { + my_errno= EINVAL; + my_printf_error(my_errno, "Can't change to run as user '%s'. Please " + "check that the user exists!", MYF(ME_NOREFRESH), user); + DBUG_RETURN(NULL); + } + } + DBUG_ASSERT(user_info); + DBUG_RETURN(user_info); +} + +int my_set_user(const char *user, struct passwd *user_info, myf MyFlags) +{ + DBUG_ENTER("my_set_user"); + + DBUG_ASSERT(user_info != 0); +#ifdef HAVE_INITGROUPS + initgroups(user, user_info->pw_gid); +#endif + if (setgid(user_info->pw_gid) == -1 || setuid(user_info->pw_uid) == -1) + { + my_errno= errno; + if (MyFlags & MY_WME) + my_error(my_errno, MYF(ME_NOREFRESH)); + DBUG_RETURN(my_errno); + } + DBUG_RETURN(0); +} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ea4fa823d29..11e9176861d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -121,10 +121,7 @@ extern "C" { // Because of SCO 3.2V4.2 #include #endif #ifdef HAVE_PWD_H -#include // For getpwent -#endif -#ifdef HAVE_GRP_H -#include +#include // For struct passwd #endif #include @@ -455,9 +452,7 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; -#ifdef HAVE_INITGROUPS volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ -#endif uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_extra_port; uint mysqld_port_timeout; @@ -2001,59 +1996,18 @@ static void set_ports() static struct passwd *check_user(const char *user) { -#if !defined(__WIN__) - struct passwd *tmp_user_info; - uid_t user_id= geteuid(); + myf flags= 0; + if (global_system_variables.log_warnings) + flags|= MY_WME; + if (!opt_bootstrap && !opt_help) + flags|= MY_FAE; - // Don't bother if we aren't superuser - if (user_id) - { - if (user) - { - /* Don't give a warning, if real user is same as given with --user */ - /* purecov: begin tested */ - tmp_user_info= getpwnam(user); - if ((!tmp_user_info || user_id != tmp_user_info->pw_uid) && - global_system_variables.log_warnings) - sql_print_warning( - "One can only use the --user switch if running as root\n"); - /* purecov: end */ - } - return NULL; - } - if (!user) - { - if (!opt_bootstrap && !opt_help) - { - sql_print_error("Fatal error: Please consult the Knowledge Base " - "to find out how to run mysqld as root!\n"); - unireg_abort(1); - } - return NULL; - } - /* purecov: begin tested */ - if (!strcmp(user,"root")) - return NULL; // Avoid problem with dynamic libraries + struct passwd *tmp_user_info= my_check_user(user, MYF(flags)); - if (!(tmp_user_info= getpwnam(user))) - { - // Allow a numeric uid to be used - const char *pos; - for (pos= user; my_isdigit(mysqld_charset,*pos); pos++) ; - if (*pos) // Not numeric id - goto err; - if (!(tmp_user_info= getpwuid(atoi(user)))) - goto err; - } + if (!tmp_user_info && my_errno==EINVAL && (flags & MY_FAE)) + unireg_abort(1); return tmp_user_info; - /* purecov: end */ - -err: - sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user); - unireg_abort(1); -#endif - return NULL; } static inline void allow_coredumps() @@ -2070,10 +2024,6 @@ static inline void allow_coredumps() static void set_user(const char *user, struct passwd *user_info_arg) { - /* purecov: begin tested */ -#if !defined(__WIN__) - DBUG_ASSERT(user_info_arg != 0); -#ifdef HAVE_INITGROUPS /* We can get a SIGSEGV when calling initgroups() on some systems when NSS is configured to use LDAP and the server is statically linked. We set @@ -2081,22 +2031,11 @@ static void set_user(const char *user, struct passwd *user_info_arg) output a specific message to help the user resolve this problem. */ calling_initgroups= 1; - initgroups((char*) user, user_info_arg->pw_gid); + int res= my_set_user(user, user_info_arg, MYF(MY_WME)); calling_initgroups= 0; -#endif - if (setgid(user_info_arg->pw_gid) == -1) - { - sql_perror("setgid"); + if (res) unireg_abort(1); - } - if (setuid(user_info_arg->pw_uid) == -1) - { - sql_perror("setuid"); - unireg_abort(1); - } allow_coredumps(); -#endif - /* purecov: end */ } From 8fcdd6b0ecbb966f4479856efe93a963a7a422f7 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 20 Dec 2016 21:16:23 +0100 Subject: [PATCH 060/124] Numerous issues in mysqld_safe --- .gitignore | 1 + .../dist/Debian/mariadb-server-5.5.files.in | 1 + .../dist/Ubuntu/mariadb-server-5.5.files.in | 1 + extra/CMakeLists.txt | 3 + extra/mysqld_safe_helper.c | 77 +++++++++++++ scripts/mysqld_safe.sh | 107 +++++++----------- support-files/mysql.server.sh | 8 +- 7 files changed, 128 insertions(+), 70 deletions(-) create mode 100644 extra/mysqld_safe_helper.c diff --git a/.gitignore b/.gitignore index b780ca88de0..8b6e416ec45 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ extra/jemalloc/build/ extra/jemalloc/tmp/ extra/my_print_defaults extra/mysql_waitpid +extra/mysqld_safe_helper extra/perror extra/replace extra/resolve_stack_dump diff --git a/debian/dist/Debian/mariadb-server-5.5.files.in b/debian/dist/Debian/mariadb-server-5.5.files.in index c1ea58740e4..47a9887b075 100644 --- a/debian/dist/Debian/mariadb-server-5.5.files.in +++ b/debian/dist/Debian/mariadb-server-5.5.files.in @@ -32,6 +32,7 @@ usr/bin/mysql_zap usr/bin/mysqlbinlog usr/bin/mysqld_multi usr/bin/mysqld_safe +usr/bin/mysqld_safe_helper usr/bin/mysqlhotcopy usr/bin/perror usr/bin/replace diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.files.in b/debian/dist/Ubuntu/mariadb-server-5.5.files.in index 7f75ccc2303..5182dd76346 100644 --- a/debian/dist/Ubuntu/mariadb-server-5.5.files.in +++ b/debian/dist/Ubuntu/mariadb-server-5.5.files.in @@ -34,6 +34,7 @@ usr/bin/mysql_zap usr/bin/mysqlbinlog usr/bin/mysqld_multi usr/bin/mysqld_safe +usr/bin/mysqld_safe_helper usr/bin/mysqlhotcopy usr/bin/perror usr/bin/replace diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index f8f71b00743..7f47f878110 100644 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -82,4 +82,7 @@ IF(UNIX) MYSQL_ADD_EXECUTABLE(mysql_waitpid mysql_waitpid.c COMPONENT Client) TARGET_LINK_LIBRARIES(mysql_waitpid mysys) + + MYSQL_ADD_EXECUTABLE(mysqld_safe_helper mysqld_safe_helper.c COMPONENT Server) + TARGET_LINK_LIBRARIES(mysqld_safe_helper mysys) ENDIF() diff --git a/extra/mysqld_safe_helper.c b/extra/mysqld_safe_helper.c new file mode 100644 index 00000000000..09e507c6e1c --- /dev/null +++ b/extra/mysqld_safe_helper.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#ifdef HAVE_PWD_H +#include +#endif +#include +#include + +void my_exit(int c) +{ + my_end(0); + exit(c); +} + +void do_usage() +{ + printf("Usage:\n" + " %s log \n" + " %s exec \n", + my_progname, my_progname); + my_exit(1); +} + +void do_log(const char *logfile) +{ + FILE *f; + uchar buf[4096]; + int size; + + if (!logfile) + do_usage(); + + f= my_fopen(logfile, O_WRONLY|O_APPEND|O_CREAT, MYF(MY_WME)); + if (!f) + my_exit(1); + + while ((size= my_fread(stdin, buf, sizeof(buf), MYF(MY_WME))) > 0) + if ((int)my_fwrite(f, buf, size, MYF(MY_WME)) != size) + my_exit(1); + + my_fclose(f, MYF(0)); + my_exit(0); +} + +void do_exec(char *args[]) +{ + if (!args[0]) + do_usage(); + + my_end(0); + execvp(args[0], args); +} + +int main(int argc, char *argv[]) +{ + struct passwd *user_info; + MY_INIT(argv[0]); + + if (argc < 3) + do_usage(argv[0]); + + user_info= my_check_user(argv[1], MYF(0)); + if (user_info ? my_set_user(argv[1], user_info, MYF(MY_WME)) + : my_errno == EINVAL) + my_exit(1); + + if (strcmp(argv[2], "log") == 0) + do_log(argv[3]); + + if (strcmp(argv[2], "exec") == 0) + do_exec(argv+3); + + my_end(0); + return 1; +} diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 7cadce725d1..059263fad51 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -20,6 +20,7 @@ mysqld_ld_preload= mysqld_ld_library_path= flush_caches=0 numa_interleave=0 +unsafe_my_cnf=0 # Initial logging status: error log is not open, and not using syslog logging=init @@ -128,6 +129,18 @@ my_which () return $ret # Success } +find_in_bin() { + if test -x "$MY_BASEDIR_VERSION/bin/$1" + then + echo "$MY_BASEDIR_VERSION/bin/$1" + elif test -x "@bindir@/$1" + then + echo "@bindir@/$1" + else + echo "$1" + fi +} + log_generic () { priority="$1" shift @@ -136,7 +149,7 @@ log_generic () { echo "$msg" case $logging in init) ;; # Just echo the message, don't save it anywhere - file) echo "$msg" >> "$err_log" ;; + file) echo "$msg" | "$helper" "$user" log "$err_log" ;; syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; *) echo "Internal program error (non-fatal):" \ @@ -156,7 +169,7 @@ log_notice () { eval_log_error () { cmd="$1" case $logging in - file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;; + file) cmd="$cmd 2>&1 | "`shell_quote_string "$helper"`" $user log "`shell_quote_string "$err_log"` ;; syslog) # mysqld often prefixes its messages with a timestamp, which is # redundant when logging to syslog (which adds its own timestamp) @@ -190,6 +203,13 @@ shell_quote_string() { echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } +check_executable_location() { + if test "$unsafe_my_cnf" = 1 -a "$unrecognized_handling" != collect; then + log_error "Cannot accept $1 from a config file, when my.cnf is in the datadir" + exit 1 + fi +} + parse_arguments() { for arg do # the parameter after "=", or the whole $arg if no match @@ -200,7 +220,6 @@ parse_arguments() { optname_subst=`echo "$optname" | sed 's/_/-/g'` arg=`echo $arg | sed "s/^$optname/$optname_subst/"` case "$arg" in - --crash-script=*) CRASH_SCRIPT="$val" ;; # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*|--data=*) DATADIR="$val" ;; @@ -220,12 +239,14 @@ parse_arguments() { # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; - --ledir=*) ledir="$val" ;; - --malloc-lib=*) set_malloc_lib "$val" ;; - --mysqld=*) MYSQLD="$val" ;; + --ledir=*) check_executable_location "$arg" ; ledir="$val" ;; + --malloc-lib=*) check_executable_location "$arg"; set_malloc_lib "$val" ;; + --crash-script=*) check_executable_location "$arg"; crash_script="$val" ;; + --mysqld=*) check_executable_location "$arg"; MYSQLD="$val" ;; --mysqld-version=*) if test -n "$val" then + check_executable_location "$arg" MYSQLD="mysqld-$val" PLUGIN_VARIANT="/$val" else @@ -385,15 +406,8 @@ set_malloc_lib() { # First, try to find BASEDIR and ledir (where mysqld is) # -if echo '@pkgdatadir@' | grep '^@prefix@' > /dev/null -then - relpkgdata=`echo '@pkgdatadir@' | sed -e 's,^@prefix@,,' -e 's,^/,,' -e 's,^,./,'` -else - # pkgdatadir is not relative to prefix - relpkgdata='@pkgdatadir@' -fi - -MY_PWD=`pwd` +MY_PWD=`dirname $0` +MY_PWD=`cd "$MY_PWD"/.. && pwd` # Check for the directories we would expect from a binary release install if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" then @@ -409,16 +423,16 @@ then else ledir="$MY_BASEDIR_VERSION/bin" fi -elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld" +elif test -x "$MY_PWD/bin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are ledir="$MY_PWD/bin" # Where mysqld is # Check for the directories we would expect from a source install -elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld" +elif test -x "$MY_PWD/libexec/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are ledir="$MY_PWD/libexec" # Where mysqld is -elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/sbin/mysqld" +elif test -x "$MY_PWD/sbin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where sbin, share and var are ledir="$MY_PWD/sbin" # Where mysqld is @@ -428,6 +442,8 @@ else ledir='@libexecdir@' fi +helper=`find_in_bin mysqld_safe_helper` +print_defaults=`find_in_bin my_print_defaults` # # Second, try to find the data directory @@ -465,6 +481,7 @@ IGNORING $DATADIR/my.cnf" log_error "WARNING: Found $DATADIR/my.cnf The data directory is a deprecated location for my.cnf, please move it to $MY_BASEDIR_VERSION/my.cnf" + unsafe_my_cnf=1 MYSQL_HOME=$DATADIR else MYSQL_HOME=$MY_BASEDIR_VERSION @@ -472,34 +489,15 @@ $MY_BASEDIR_VERSION/my.cnf" fi export MYSQL_HOME - -# Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] -# and then merge with the command line arguments -if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults" -then - print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults" -elif test -x `dirname $0`/my_print_defaults -then - print_defaults="`dirname $0`/my_print_defaults" -elif test -x ./bin/my_print_defaults -then - print_defaults="./bin/my_print_defaults" -elif test -x @bindir@/my_print_defaults -then - print_defaults="@bindir@/my_print_defaults" -elif test -x @bindir@/mysql_print_defaults -then - print_defaults="@bindir@/mysql_print_defaults" -else - print_defaults="my_print_defaults" -fi - append_arg_to_args () { args="$args "`shell_quote_string "$1"` } args= +# Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] +# and then merge with the command line arguments + SET_USER=2 parse_arguments `$print_defaults $defaults --loose-verbose --mysqld` if test $SET_USER -eq 2 @@ -603,11 +601,6 @@ then log_notice "Logging to '$err_log'." logging=file - if [ ! -f "$err_log" ]; then # if error log already exists, - touch "$err_log" # we just append. otherwise, - chmod "$fmode" "$err_log" # fix the permissions here! - fi - else if [ -n "$syslog_tag" ] then @@ -620,10 +613,6 @@ else logging=syslog fi -# close stdout and stderr, everything goes to $logging now -exec 1>&- -exec 2>&- - USER_OPTION="" if test -w / -o "$USER" = "root" then @@ -631,11 +620,6 @@ then then USER_OPTION="--user=$user" fi - # Change the err log to the right user, if it is in use - if [ $want_syslog -eq 0 ]; then - touch "$err_log" - chown $user "$err_log" - fi if test -n "$open_files" then ulimit -n $open_files @@ -879,6 +863,10 @@ max_fast_restarts=5 # flag whether a usable sleep command exists have_sleep=1 +# close stdout and stderr, everything goes to $logging now +exec 1>&- +exec 2>&- + while true do rm -f "$pid_file" # Some extra safety @@ -886,13 +874,6 @@ do start_time=`date +%M%S` eval_log_error "$cmd" - - if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then - touch "$err_log" # hypothetical: log was renamed but not - chown $user "$err_log" # flushed yet. we'd recreate it with - chmod "$fmode" "$err_log" # wrong owner next time we log, so set - fi # it up correctly while we can! - end_time=`date +%M%S` if test ! -f "$pid_file" # This is removed if normal shutdown @@ -956,9 +937,9 @@ do done fi log_notice "mysqld restarted" - if test -n "$CRASH_SCRIPT" + if test -n "$crash_script" then - crash_script_output=`$CRASH_SCRIPT 2>&1` + crash_script_output=`$crash_script 2>&1` log_error "$crash_script_output" fi done diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index d4fff33af13..a4034dec385 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -157,15 +157,9 @@ parse_server_arguments() { # Get arguments from the my.cnf file, # the only group, which is read from now on is [mysqld] -if test -x ./bin/my_print_defaults -then - print_defaults="./bin/my_print_defaults" -elif test -x $bindir/my_print_defaults +if test -x $bindir/my_print_defaults then print_defaults="$bindir/my_print_defaults" -elif test -x $bindir/mysql_print_defaults -then - print_defaults="$bindir/mysql_print_defaults" else # Try to find basedir in /etc/my.cnf conf=/etc/my.cnf From 48655ce6985490fdf6c5c8be7c75b37f83f7738e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2016 12:23:48 +0100 Subject: [PATCH 061/124] test case for Bug #23303485 : HANDLE_FATAL_SIGNAL (SIG=11) IN SUBSELECT_UNION_ENGINE::NO_ROWS --- mysql-test/r/subselect2.result | 10 ++++++++++ mysql-test/t/subselect2.test | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index b6dc940d9fb..64bd86707cc 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -384,3 +384,13 @@ DEALLOCATE PREPARE stmt; DROP VIEW v1; DROP TABLE t1,t2,t3; set optimizer_switch=@subselect2_test_tmp; +create table t1 (a int); +create table t2 (a int); +create table t3(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t2 select a from t1; +insert into t3 select a from t1; +select null in (select a from t1 where a < out3.a union select a from t2 where +(select a from t3) +1 < out3.a+1) from t3 out3; +ERROR 21000: Subquery returns more than 1 row +drop table t1, t2, t3; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index f795cef648c..ae210b865a2 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -398,3 +398,16 @@ DROP TABLE t1,t2,t3; set optimizer_switch=@subselect2_test_tmp; +# +# Bug #23303485 : HANDLE_FATAL_SIGNAL (SIG=11) IN SUBSELECT_UNION_ENGINE::NO_ROWS +# +create table t1 (a int); +create table t2 (a int); +create table t3(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t2 select a from t1; +insert into t3 select a from t1; +--error ER_SUBQUERY_NO_1_ROW +select null in (select a from t1 where a < out3.a union select a from t2 where + (select a from t3) +1 < out3.a+1) from t3 out3; +drop table t1, t2, t3; From e7d7910b7a926ccc6f5b8d73d55ac511f1c03c3d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2016 11:13:07 +0100 Subject: [PATCH 062/124] add an assert and use is_supported_parser_charset() instead of direct check --- sql/sql_connect.cc | 16 +++++++--------- sql/sys_vars.cc | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 61f8b4081eb..e2e56c48b3b 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2007, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2014, SkySQL Ab. + Copyright (c) 2008, 2016, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -821,6 +821,7 @@ void update_global_user_stats(THD *thd, bool create_user, time_t now) bool thd_init_client_charset(THD *thd, uint cs_number) { + SV *gv=&global_system_variables; CHARSET_INFO *cs; /* Use server character set and collation if @@ -831,16 +832,13 @@ bool thd_init_client_charset(THD *thd, uint cs_number) */ if (!opt_character_set_client_handshake || !(cs= get_charset(cs_number, MYF(0))) || - !my_strcasecmp(&my_charset_latin1, - global_system_variables.character_set_client->name, + !my_strcasecmp(&my_charset_latin1, gv->character_set_client->name, cs->name)) { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.character_set_results= - global_system_variables.character_set_results; + DBUG_ASSERT(is_supported_parser_charset(gv->character_set_client)); + thd->variables.character_set_client= gv->character_set_client; + thd->variables.collation_connection= gv->collation_connection; + thd->variables.character_set_results= gv->character_set_results; } else { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7b898906184..35997525456 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -31,6 +31,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_class.h" // set_var.h: THD +#include "sql_parse.h" #include "sys_vars.h" #include "events.h" @@ -445,7 +446,7 @@ static bool check_cs_client(sys_var *self, THD *thd, set_var *var) return true; // Currently, UCS-2 cannot be used as a client character set - if (((CHARSET_INFO *)(var->save_result.ptr))->mbminlen > 1) + if (!is_supported_parser_charset((CHARSET_INFO *)(var->save_result.ptr))) return true; return false; From ec6d8dadc01269451332e5b24b12a5350a2a4896 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 22 Dec 2016 13:02:32 +0100 Subject: [PATCH 063/124] reduce code duplication a little --- sql/event_db_repository.cc | 15 +++++++-------- sql/sp_head.cc | 6 +----- sql/sql_parse.cc | 23 ++++++++++++++--------- sql/sql_parse.h | 1 + sql/sql_table.cc | 6 +----- sql/sql_udf.cc | 6 +----- sql/sql_yacc.yy | 12 ++---------- 7 files changed, 27 insertions(+), 42 deletions(-) diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 37dff0da714..673250ffd22 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -17,6 +17,7 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_base.h" // close_thread_tables +#include "sql_parse.h" #include "event_db_repository.h" #include "key.h" // key_copy #include "sql_db.h" // get_default_db_collation @@ -702,19 +703,17 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, restore_record(table, s->default_values); // Get default values for fields - if (system_charset_info->cset-> - numchars(system_charset_info, parse_data->dbname.str, - parse_data->dbname.str + parse_data->dbname.length) > - table->field[ET_FIELD_DB]->char_length()) + if (check_string_char_length(&parse_data->dbname, 0, + table->field[ET_FIELD_DB]->char_length(), + system_charset_info, 1)) { my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str); goto end; } - if (system_charset_info->cset-> - numchars(system_charset_info, parse_data->name.str, - parse_data->name.str + parse_data->name.length) > - table->field[ET_FIELD_NAME]->char_length()) + if (check_string_char_length(&parse_data->name, 0, + table->field[ET_FIELD_NAME]->char_length(), + system_charset_info, 1)) { my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str); goto end; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9bfa60a07d3..69364eaa43f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -488,12 +488,8 @@ check_routine_name(LEX_STRING *ident) my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; } - if (check_string_char_length(ident, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str); + if (check_ident_length(ident)) return TRUE; - } return FALSE; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a3114aba7d3..f000fe1a37d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4329,11 +4329,8 @@ create_sp_error: } case SQLCOM_SHOW_CREATE_TRIGGER: { - if (lex->spname->m_name.length > NAME_LEN) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); + if (check_ident_length(&lex->spname->m_name)) goto error; - } if (show_create_trigger(thd, lex->spname)) goto error; /* Error has been already logged. */ @@ -6019,12 +6016,9 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, LEX *lex= thd->lex; DBUG_ENTER("add_field_to_list"); - if (check_string_char_length(field_name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */ + if (check_ident_length(field_name)) DBUG_RETURN(1); /* purecov: inspected */ - } + if (type_modifier & PRI_KEY_FLAG) { Key *key; @@ -7688,6 +7682,17 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, } +bool check_ident_length(LEX_STRING *ident) +{ + if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1)) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str); + return 1; + } + return 0; +} + + /* Check if path does not contain mysql data home directory diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 4c3070d197d..66a8f6efc7d 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -75,6 +75,7 @@ bool check_string_byte_length(LEX_STRING *str, const char *err_msg, bool check_string_char_length(LEX_STRING *str, const char *err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error); +bool check_ident_length(LEX_STRING *ident); CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl); bool check_host_name(LEX_STRING *str); bool check_identifier_name(LEX_STRING *str, uint max_char_length, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9bcb4c3f8cc..2cec480d23b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3312,12 +3312,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp); DBUG_RETURN(TRUE); } - if (check_string_char_length(&key->name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str); + if (check_ident_length(&key->name)) DBUG_RETURN(TRUE); - } key_iterator2.rewind (); if (key->type != Key::FOREIGN_KEY) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 626e5569ccc..d18498de784 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -455,12 +455,8 @@ int mysql_create_function(THD *thd,udf_func *udf) my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0)); DBUG_RETURN(1); } - if (check_string_char_length(&udf->name, "", NAME_CHAR_LEN, - system_charset_info, 1)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name.str); + if (check_ident_length(&udf->name)) DBUG_RETURN(1); - } /* Turn off row binlogging of this statement and use statement-based diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7d981e03aea..35c7203ca0d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4670,12 +4670,8 @@ part_name: { partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; - if (check_string_char_length(&$1, "", NAME_CHAR_LEN, - system_charset_info, true)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + if (check_ident_length(&$1)) MYSQL_YYABORT; - } p_elem->partition_name= $1.str; } ; @@ -4971,12 +4967,8 @@ sub_part_definition: sub_name: ident_or_text { - if (check_string_char_length(&$1, "", NAME_CHAR_LEN, - system_charset_info, true)) - { - my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str); + if (check_ident_length(&$1)) MYSQL_YYABORT; - } Lex->part_info->curr_part_elem->partition_name= $1.str; } ; From e6b563f8be68d57df2a4c9b8e2b6c130855b18e4 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 23 Dec 2016 16:58:32 +0100 Subject: [PATCH 064/124] Fix some XML table type bugs: - in DOMNODELIST::DropItem if (Listp == NULL || Listp->length <= n) return true; is wrong, should be: if (Listp == NULL || Listp->length < n) return true; - Crash in discovery with libxml2 in XMLColumns because: if (!tdp->Usedom) // nl was destroyed vp->nl = vp->pn->GetChildElements(g); is executed with vp->pn uninitialized. Fixed by adding: vp->pn = node; line 264. -In discovery with libxml2 some columns are not found. Because list was not recovered properly, nodes being modified and not reallocated. Fixed lines 214 and 277. modified: storage/connect/domdoc.cpp modified: storage/connect/tabxml.cpp Add support for zipped table files modified: storage/connect/domdoc.cpp modified: storage/connect/domdoc.h modified: storage/connect/filamap.cpp modified: storage/connect/filamap.h modified: storage/connect/filamzip.cpp modified: storage/connect/filamzip.h modified: storage/connect/ha_connect.cc modified: storage/connect/libdoc.cpp modified: storage/connect/plgdbutl.cpp modified: storage/connect/plgxml.cpp modified: storage/connect/plgxml.h modified: storage/connect/tabdos.cpp modified: storage/connect/tabdos.h modified: storage/connect/tabfmt.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabxml.cpp --- storage/connect/domdoc.cpp | 40 +++- storage/connect/domdoc.h | 4 +- storage/connect/filamap.cpp | 49 ++-- storage/connect/filamap.h | 3 +- storage/connect/filamzip.cpp | 434 ++++++++++++++++++++++------------ storage/connect/filamzip.h | 96 +++++--- storage/connect/ha_connect.cc | 6 +- storage/connect/libdoc.cpp | 30 ++- storage/connect/plgdbutl.cpp | 2 +- storage/connect/plgxml.cpp | 55 ++++- storage/connect/plgxml.h | 16 +- storage/connect/tabdos.cpp | 34 ++- storage/connect/tabdos.h | 13 +- storage/connect/tabfmt.cpp | 11 +- storage/connect/tabjson.cpp | 33 ++- storage/connect/tabxml.cpp | 56 ++++- storage/connect/tabxml.h | 18 +- 17 files changed, 613 insertions(+), 287 deletions(-) diff --git a/storage/connect/domdoc.cpp b/storage/connect/domdoc.cpp index 64a0a172956..eb9660b439d 100644 --- a/storage/connect/domdoc.cpp +++ b/storage/connect/domdoc.cpp @@ -89,30 +89,43 @@ DOMDOC::DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp) /******************************************************************/ /* Initialize XML parser and check library compatibility. */ /******************************************************************/ -bool DOMDOC::Initialize(PGLOBAL g) - { - if (TestHr(g, CoInitialize(NULL))) +bool DOMDOC::Initialize(PGLOBAL g, char *entry, bool zipped) +{ + if (zipped && InitZip(g, entry)) + return true; + + if (TestHr(g, CoInitialize(NULL))) return true; if (TestHr(g, Docp.CreateInstance("msxml2.domdocument"))) return true; return MakeNSlist(g); - } // end of Initialize +} // end of Initialize /******************************************************************/ /* Parse the XML file and construct node tree in memory. */ /******************************************************************/ -bool DOMDOC::ParseFile(char *fn) - { - // Load the document +bool DOMDOC::ParseFile(PGLOBAL g, char *fn) +{ + bool b; + Docp->async = false; - if (!(bool)Docp->load((_bstr_t)fn)) + if (zip) { + // Parse an in memory document + char *xdoc = GetMemDoc(g, fn); + + b = (xdoc) ? (bool)Docp->loadXML((_bstr_t)xdoc) : false; + } else + // Load the document + b = (bool)Docp->load((_bstr_t)fn); + + if (!b) return true; return false; - } // end of ParseFile +} // end of ParseFile /******************************************************************/ /* Create or reuse an Xblock for this document. */ @@ -239,6 +252,7 @@ int DOMDOC::DumpDoc(PGLOBAL g, char *ofn) void DOMDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) { CloseXMLFile(g, xp, false); + CloseZip(); } // end of Close /* ----------------------- class DOMNODE ------------------------ */ @@ -616,13 +630,13 @@ PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np) /* Reset the pointer on the deleted item. */ /******************************************************************/ bool DOMNODELIST::DropItem(PGLOBAL g, int n) - { - if (Listp == NULL || Listp->length <= n) - return true; +{ + if (Listp == NULL || Listp->length < n) + return true; //Listp->item[n] = NULL; La proprit n'a pas de mthode 'set' return false; - } // end of DeleteItem +} // end of DeleteItem /* ----------------------- class DOMATTR ------------------------ */ diff --git a/storage/connect/domdoc.h b/storage/connect/domdoc.h index 2cffec499e2..cfec98a9422 100644 --- a/storage/connect/domdoc.h +++ b/storage/connect/domdoc.h @@ -37,8 +37,8 @@ class DOMDOC : public XMLDOCUMENT { virtual void SetNofree(bool b) {} // Only libxml2 // Methods - virtual bool Initialize(PGLOBAL g); - virtual bool ParseFile(char *fn); + virtual bool Initialize(PGLOBAL g, char *entry, bool zipped); + virtual bool ParseFile(PGLOBAL g, char *fn); virtual bool NewDoc(PGLOBAL g, char *ver); virtual void AddComment(PGLOBAL g, char *com); virtual PXNODE GetRoot(PGLOBAL g); diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp index 3c5b3ae7592..94c562a9981 100644 --- a/storage/connect/filamap.cpp +++ b/storage/connect/filamap.cpp @@ -319,11 +319,13 @@ int MAPFAM::SkipRecord(PGLOBAL g, bool header) /***********************************************************************/ int MAPFAM::ReadBuffer(PGLOBAL g) { - int len; + int rc, len; // Are we at the end of the memory - if (Mempos >= Top) - return RC_EF; + if (Mempos >= Top) + if ((rc = GetNext(g)) != RC_OK) + return rc; + if (!Placed) { /*******************************************************************/ @@ -341,8 +343,10 @@ int MAPFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ switch (Tdbp->TestBlock(g)) { case RC_EF: - return RC_EF; - case RC_NF: + if ((rc = GetNext(g)) != RC_OK) + return rc; + + case RC_NF: // Skip this record if ((rc = SkipRecord(g, false)) != RC_OK) return rc; @@ -569,7 +573,7 @@ int MBKFAM::GetRowID(void) /***********************************************************************/ int MBKFAM::ReadBuffer(PGLOBAL g) { - int len; + int rc, len; /*********************************************************************/ /* Sequential block reading when Placed is not true. */ @@ -577,8 +581,10 @@ int MBKFAM::ReadBuffer(PGLOBAL g) if (Placed) { Placed = false; } else if (Mempos >= Top) { // Are we at the end of the memory - return RC_EF; - } else if (++CurNum < Nrec) { + if ((rc = GetNext(g)) != RC_OK) + return rc; + + } else if (++CurNum < Nrec) { Fpos = Mempos; } else { /*******************************************************************/ @@ -588,7 +594,8 @@ int MBKFAM::ReadBuffer(PGLOBAL g) next: if (++CurBlk >= Block) - return RC_EF; + if ((rc = GetNext(g)) != RC_OK) + return rc; /*******************************************************************/ /* Before reading a new block, check whether block optimization */ @@ -596,8 +603,11 @@ int MBKFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ switch (Tdbp->TestBlock(g)) { case RC_EF: - return RC_EF; - case RC_NF: + if ((rc = GetNext(g)) != RC_OK) + return rc; + + break; + case RC_NF: goto next; } // endswitch rc @@ -697,14 +707,18 @@ int MPXFAM::InitDelete(PGLOBAL, int fpos, int) /***********************************************************************/ int MPXFAM::ReadBuffer(PGLOBAL g) { + int rc; + /*********************************************************************/ /* Sequential block reading when Placed is not true. */ /*********************************************************************/ if (Placed) { Placed = false; } else if (Mempos >= Top) { // Are we at the end of the memory - return RC_EF; - } else if (++CurNum < Nrec) { + if ((rc = GetNext(g)) != RC_OK) + return rc; + + } else if (++CurNum < Nrec) { Fpos = Mempos; } else { /*******************************************************************/ @@ -714,7 +728,7 @@ int MPXFAM::ReadBuffer(PGLOBAL g) next: if (++CurBlk >= Block) - return RC_EF; + return GetNext(g); /*******************************************************************/ /* Before reading a new block, check whether block optimization */ @@ -722,8 +736,11 @@ int MPXFAM::ReadBuffer(PGLOBAL g) /*******************************************************************/ switch (Tdbp->TestBlock(g)) { case RC_EF: - return RC_EF; - case RC_NF: + if ((rc = GetNext(g)) != RC_OK) + return rc; + + break; + case RC_NF: goto next; } // endswitch rc diff --git a/storage/connect/filamap.h b/storage/connect/filamap.h index b9c8ad965fd..774eb8b91b3 100644 --- a/storage/connect/filamap.h +++ b/storage/connect/filamap.h @@ -41,7 +41,8 @@ class DllExport MAPFAM : public TXTFAM { virtual int SkipRecord(PGLOBAL g, bool header); virtual bool OpenTableFile(PGLOBAL g); virtual bool DeferReading(void) {return false;} - virtual int ReadBuffer(PGLOBAL g); + virtual int GetNext(PGLOBAL g) {return RC_EF;} + virtual int ReadBuffer(PGLOBAL g); virtual int WriteBuffer(PGLOBAL g); virtual int DeleteRecords(PGLOBAL g, int irc); virtual void CloseTableFile(PGLOBAL g, bool abort); diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 8386e5be481..65013e170e4 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -40,19 +40,21 @@ //#include "tabzip.h" #include "filamzip.h" -/* -------------------------- class ZIPFAM --------------------------- */ +/* -------------------------- class ZIPUTIL -------------------------- */ /***********************************************************************/ /* Constructors. */ /***********************************************************************/ -ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) +ZIPUTIL::ZIPUTIL(PSZ tgt, bool mul) { zipfile = NULL; -//zfn = tdp->Fn; - target = tdp->Entry; -//*fn = 0; + target = tgt; + fp = NULL; + memory = NULL; + size = 0; entryopen = false; - multiple = (target && !(strchr(target, '*') || strchr(target, '?'))) ? 0 : 1; + multiple = mul; + memset(fn, 0, sizeof(fn)); // Init the case mapping table. #if defined(__WIN__) @@ -60,29 +62,30 @@ ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) #else for (int i = 0; i < 256; ++i) mapCaseTable[i] = i; #endif -} // end of ZIPFAM standard constructor +} // end of ZIPUTIL standard constructor -ZIPFAM::ZIPFAM(PZIPFAM txfp) : MAPFAM(txfp) +#if 0 +ZIPUTIL::ZIPUTIL(PZIPUTIL zutp) { - zipfile = txfp->zipfile; -//zfn = txfp->zfn; - target = txfp->target; -//strcpy(fn, txfp->fn); - finfo = txfp->finfo; - entryopen = txfp->entryopen; - multiple = txfp->multiple; - for (int i = 0; i < 256; ++i) mapCaseTable[i] = txfp->mapCaseTable[i]; -} // end of ZIPFAM copy constructor + zipfile = zutp->zipfile; + target = zutp->target; + fp = zutp->fp; + finfo = zutp->finfo; + entryopen = zutp->entryopen; + multiple = zutp->multiple; + for (int i = 0; i < 256; ++i) mapCaseTable[i] = zutp->mapCaseTable[i]; +} // end of ZIPUTIL copy constructor +#endif // 0 /***********************************************************************/ /* This code is the copyright property of Alessandro Felice Cantatore. */ /* http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html */ /***********************************************************************/ -bool ZIPFAM::WildMatch(PSZ pat, PSZ str) { +bool ZIPUTIL::WildMatch(PSZ pat, PSZ str) { PSZ s, p; bool star = FALSE; - loopStart: +loopStart: for (s = str, p = pat; *s; ++s, ++p) { switch (*p) { case '?': @@ -102,31 +105,18 @@ bool ZIPFAM::WildMatch(PSZ pat, PSZ str) { if (*p == '*') ++p; return (!*p); - starCheck: +starCheck: if (!star) return FALSE; str++; goto loopStart; } // end of WildMatch -/***********************************************************************/ -/* ZIP GetFileLength: returns file size in number of bytes. */ -/***********************************************************************/ -int ZIPFAM::GetFileLength(PGLOBAL g) -{ - int len = (entryopen) ? Top - Memory : 100; // not 0 to avoid ASSERT - - if (trace) - htrc("Zipped file length=%d\n", len); - - return len; -} // end of GetFileLength - /***********************************************************************/ /* open a zip file. */ /* param: filename path and the filename of the zip file to open. */ /* return: true if open, false otherwise. */ /***********************************************************************/ -bool ZIPFAM::open(PGLOBAL g, const char *filename) +bool ZIPUTIL::open(PGLOBAL g, char *filename) { if (!zipfile && !(zipfile = unzOpen64(filename))) sprintf(g->Message, "Zipfile open error on %s", filename); @@ -137,7 +127,7 @@ bool ZIPFAM::open(PGLOBAL g, const char *filename) /***********************************************************************/ /* Close the zip file. */ /***********************************************************************/ -void ZIPFAM::close() +void ZIPUTIL::close() { if (zipfile) { closeEntry(); @@ -150,10 +140,9 @@ void ZIPFAM::close() /***********************************************************************/ /* Find next entry matching target pattern. */ /***********************************************************************/ -int ZIPFAM::findEntry(PGLOBAL g, bool next) +int ZIPUTIL::findEntry(PGLOBAL g, bool next) { int rc; - char fn[FILENAME_MAX]; // The current entry file name do { if (next) { @@ -188,37 +177,53 @@ int ZIPFAM::findEntry(PGLOBAL g, bool next) strcpy(g->Message, "FindNext logical error"); return RC_FX; -} // end of FindNext +} // end of FindEntry + + +/***********************************************************************/ +/* Get the next used entry. */ +/***********************************************************************/ +int ZIPUTIL::nextEntry(PGLOBAL g) +{ + if (multiple) { + int rc; + + closeEntry(); + + if ((rc = findEntry(g, true)) != RC_OK) + return rc; + + if (openEntry(g)) + return RC_FX; + + return RC_OK; + } else + return RC_EF; + +} // end of nextEntry + /***********************************************************************/ /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ /***********************************************************************/ -bool ZIPFAM::OpenTableFile(PGLOBAL g) +bool ZIPUTIL::OpenTable(PGLOBAL g, MODE mode, char *fn) { - char filename[_MAX_PATH]; - MODE mode = Tdbp->GetMode(); - PFBLOCK fp; - PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; - /*********************************************************************/ /* The file will be decompressed into virtual memory. */ /*********************************************************************/ - if (mode == MODE_READ) { - // We used the file name relative to recorded datapath - PlugSetPath(filename, To_File, Tdbp->GetPath()); - - bool b = open(g, filename); + if (mode == MODE_READ || mode == MODE_ANY) { + bool b = open(g, fn); if (!b) { int rc; - + if (target && *target) { if (!multiple) { rc = unzLocateFile(zipfile, target, 0); if (rc == UNZ_END_OF_LIST_OF_FILE) { - sprintf(g->Message, "Target file %s not in %s", target, filename); - return false; + sprintf(g->Message, "Target file %s not in %s", target, fn); + return true; } else if (rc != UNZ_OK) { sprintf(g->Message, "unzLocateFile rc=%d", rc); return true; @@ -227,9 +232,9 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) } else { if ((rc = findEntry(g, false)) == RC_FX) return true; - else if (rc == RC_NF) { - sprintf(g->Message, "No match of %s in %s", target, filename); - return false; + else if (rc == RC_EF) { + sprintf(g->Message, "No match of %s in %s", target, fn); + return true; } // endif rc } // endif multiple @@ -239,25 +244,26 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) if (openEntry(g)) return true; - if (Top > Memory) { + if (size > 0) { /*******************************************************************/ /* Link a Fblock. This make possible to automatically close it */ /* in case of error g->jump. */ /*******************************************************************/ + PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; + fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); fp->Type = TYPE_FB_ZIP; - fp->Fname = PlugDup(g, filename); + fp->Fname = PlugDup(g, fn); fp->Next = dbuserp->Openlist; dbuserp->Openlist = fp; fp->Count = 1; - fp->Length = Top - Memory; - fp->Memory = Memory; + fp->Length = size; + fp->Memory = memory; fp->Mode = mode; fp->File = this; fp->Handle = NULL; } // endif fp - To_Fb = fp; // Useful when closing } else return true; @@ -267,65 +273,161 @@ bool ZIPFAM::OpenTableFile(PGLOBAL g) } // endif mode return false; - } // end of OpenTableFile +} // end of OpenTableFile /***********************************************************************/ /* Open target in zip file. */ /***********************************************************************/ -bool ZIPFAM::openEntry(PGLOBAL g) +bool ZIPUTIL::openEntry(PGLOBAL g) { - int rc; - uint size; + int rc; - rc = unzGetCurrentFileInfo(zipfile, &finfo, 0, 0, 0, 0, 0, 0); + rc = unzGetCurrentFileInfo(zipfile, &finfo, fn, sizeof(fn), + NULL, 0, NULL, 0); if (rc != UNZ_OK) { sprintf(g->Message, "unzGetCurrentFileInfo64 rc=%d", rc); return true; } else if ((rc = unzOpenCurrentFile(zipfile)) != UNZ_OK) { - sprintf(g->Message, "unzOpenCurrentFile rc=%d", rc); + sprintf(g->Message, "unzOpen fn=%s rc=%d", fn, rc); return true; } // endif rc size = finfo.uncompressed_size; - Memory = new char[size]; + memory = new char[size + 1]; - if ((rc = unzReadCurrentFile(zipfile, Memory, size)) < 0) { + if ((rc = unzReadCurrentFile(zipfile, memory, size)) < 0) { sprintf(g->Message, "unzReadCurrentFile rc = ", rc); unzCloseCurrentFile(zipfile); - free(Memory); + free(memory); + memory = NULL; entryopen = false; } else { - // The pseudo "buffer" is here the entire real buffer - Fpos = Mempos = Memory; - Top = Memory + size; - - if (trace) - htrc("Memory=%p size=%ud Top=%p\n", Memory, size, Top); - + memory[size] = 0; // Required by some table types (XML) entryopen = true; } // endif rc + if (trace) + htrc("Openning entry%s %s\n", fn, (entryopen) ? "oked" : "failed"); + return !entryopen; } // end of openEntry /***********************************************************************/ /* Close the zip file. */ /***********************************************************************/ -void ZIPFAM::closeEntry() +void ZIPUTIL::closeEntry() { if (entryopen) { unzCloseCurrentFile(zipfile); entryopen = false; } // endif entryopen - if (Memory) { - free(Memory); - Memory = NULL; - } // endif Memory + if (memory) { + free(memory); + memory = NULL; + } // endif memory } // end of closeEntry +/* -------------------------- class ZIPFAM --------------------------- */ + +/***********************************************************************/ +/* Constructors. */ +/***********************************************************************/ +ZIPFAM::ZIPFAM(PDOSDEF tdp) : MAPFAM(tdp) +{ + zutp = NULL; + target = tdp->GetEntry(); + mul = tdp->GetMul(); +} // end of ZIPFAM standard constructor + +ZIPFAM::ZIPFAM(PZIPFAM txfp) : MAPFAM(txfp) +{ + zutp = txfp->zutp; + target = txfp->target; + mul = txfp->mul; +} // end of ZIPFAM copy constructor + +ZIPFAM::ZIPFAM(PDOSDEF tdp, PZPXFAM txfp) : MAPFAM(tdp) +{ + zutp = txfp->zutp; + target = txfp->target; + mul = txfp->mul; +} // end of ZIPFAM constructor used in ResetTableOpt + +/***********************************************************************/ +/* ZIP GetFileLength: returns file size in number of bytes. */ +/***********************************************************************/ +int ZIPFAM::GetFileLength(PGLOBAL g) +{ + int len = (zutp && zutp->entryopen) ? Top - Memory + : TXTFAM::GetFileLength(g) * 3; + + if (trace) + htrc("Zipped file length=%d\n", len); + + return len; +} // end of GetFileLength + +/***********************************************************************/ +/* ZIP Cardinality: return the number of rows if possible. */ +/***********************************************************************/ +int ZIPFAM::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + + int card = -1; + int len = GetFileLength(g); + + card = (len / (int)Lrecl) * 2; // Estimated ??? + return card; +} // end of Cardinality + +/***********************************************************************/ +/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ +/***********************************************************************/ +bool ZIPFAM::OpenTableFile(PGLOBAL g) +{ + char filename[_MAX_PATH]; + MODE mode = Tdbp->GetMode(); + + /*********************************************************************/ + /* Allocate the ZIP utility class. */ + /*********************************************************************/ + zutp = new(g) ZIPUTIL(target, mul); + + // We used the file name relative to recorded datapath + PlugSetPath(filename, To_File, Tdbp->GetPath()); + + if (!zutp->OpenTable(g, mode, filename)) { + // The pseudo "buffer" is here the entire real buffer + Fpos = Mempos = Memory = zutp->memory; + Top = Memory + zutp->size; + To_Fb = zutp->fp; // Useful when closing + } else + return true; + + return false; + } // end of OpenTableFile + +/***********************************************************************/ +/* GetNext: go to next entry. */ +/***********************************************************************/ +int ZIPFAM::GetNext(PGLOBAL g) +{ + int rc = zutp->nextEntry(g); + + if (rc != RC_OK) + return rc; + + Mempos = Memory = zutp->memory; + Top = Memory + zutp->size; + return RC_OK; +} // end of GetNext + +#if 0 /***********************************************************************/ /* ReadBuffer: Read one line for a ZIP file. */ /***********************************************************************/ @@ -335,19 +437,12 @@ int ZIPFAM::ReadBuffer(PGLOBAL g) // Are we at the end of the memory if (Mempos >= Top) { - if (multiple) { - closeEntry(); + if ((rc = zutp->nextEntry(g)) != RC_OK) + return rc; - if ((rc = findEntry(g, true)) != RC_OK) - return rc; - - if (openEntry(g)) - return RC_FX; - - } else - return RC_EF; - - } // endif Mempos + Mempos = Memory = zutp->memory; + Top = Memory + zutp->size; + } // endif Mempos #if 0 if (!Placed) { @@ -399,7 +494,6 @@ int ZIPFAM::ReadBuffer(PGLOBAL g) return RC_OK; } // end of ReadBuffer -#if 0 /***********************************************************************/ /* Table file close routine for MAP access method. */ /***********************************************************************/ @@ -414,89 +508,115 @@ void ZIPFAM::CloseTableFile(PGLOBAL g, bool) /***********************************************************************/ /* Constructors. */ /***********************************************************************/ -ZPXFAM::ZPXFAM(PDOSDEF tdp) : ZIPFAM(tdp) +ZPXFAM::ZPXFAM(PDOSDEF tdp) : MPXFAM(tdp) { - Lrecl = tdp->GetLrecl(); + zutp = NULL; + target = tdp->GetEntry(); + mul = tdp->GetMul(); + //Lrecl = tdp->GetLrecl(); } // end of ZPXFAM standard constructor -ZPXFAM::ZPXFAM(PZPXFAM txfp) : ZIPFAM(txfp) +ZPXFAM::ZPXFAM(PZPXFAM txfp) : MPXFAM(txfp) { - Lrecl = txfp->Lrecl; + zutp = txfp->zutp; + target = txfp->target; + mul = txfp->mul; +//Lrecl = txfp->Lrecl; } // end of ZPXFAM copy constructor /***********************************************************************/ -/* ReadBuffer: Read one line for a fixed ZIP file. */ +/* ZIP GetFileLength: returns file size in number of bytes. */ /***********************************************************************/ -int ZPXFAM::ReadBuffer(PGLOBAL g) +int ZPXFAM::GetFileLength(PGLOBAL g) { - int rc, len; + int len; - // Are we at the end of the memory - if (Mempos >= Top) { - if (multiple) { - closeEntry(); + if (!zutp && OpenTableFile(g)) + return 0; - if ((rc = findEntry(g, true)) != RC_OK) - return rc; + if (zutp->entryopen) + len = zutp->size; + else + len = 0; - if (openEntry(g)) - return RC_FX; + return len; +} // end of GetFileLength +/***********************************************************************/ +/* ZIP Cardinality: return the number of rows if possible. */ +/***********************************************************************/ +int ZPXFAM::Cardinality(PGLOBAL g) +{ + if (!g) + return 1; + + int card = -1; + int len = GetFileLength(g); + + if (!(len % Lrecl)) + card = len / (int)Lrecl; // Fixed length file + else + sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl); + + // Set number of blocks for later use + Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0; + return card; +} // end of Cardinality + +/***********************************************************************/ +/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ +/***********************************************************************/ +bool ZPXFAM::OpenTableFile(PGLOBAL g) +{ + // May have been already opened in GetFileLength + if (!zutp || !zutp->zipfile) { + char filename[_MAX_PATH]; + MODE mode = Tdbp->GetMode(); + + /*********************************************************************/ + /* Allocate the ZIP utility class. */ + /*********************************************************************/ + if (!zutp) + zutp = new(g)ZIPUTIL(target, mul); + + // We used the file name relative to recorded datapath + PlugSetPath(filename, To_File, Tdbp->GetPath()); + + if (!zutp->OpenTable(g, mode, filename)) { + // The pseudo "buffer" is here the entire real buffer + Memory = zutp->memory; + Fpos = Mempos = Memory + Headlen; + Top = Memory + zutp->size; + To_Fb = zutp->fp; // Useful when closing } else - return RC_EF; - - } // endif Mempos - -#if 0 - if (!Placed) { - /*******************************************************************/ - /* Record file position in case of UPDATE or DELETE. */ - /*******************************************************************/ - int rc; - - next: - Fpos = Mempos; - CurBlk = (int)Rows++; - - /*******************************************************************/ - /* Check whether optimization on ROWID */ - /* can be done, as well as for join as for local filtering. */ - /*******************************************************************/ - switch (Tdbp->TestBlock(g)) { - case RC_EF: - return RC_EF; - case RC_NF: - // Skip this record - if ((rc = SkipRecord(g, false)) != RC_OK) - return rc; - - goto next; - } // endswitch rc + return true; } else - Placed = false; -#else - // Perhaps unuseful - Fpos = Mempos; - CurBlk = (int)Rows++; - Placed = false; -#endif + Reset(); - // Immediately calculate next position (Used by DeleteDB) - Mempos += Lrecl; + return false; +} // end of OpenTableFile - // Set caller line buffer - len = Lrecl; +/***********************************************************************/ +/* GetNext: go to next entry. */ +/***********************************************************************/ +int ZPXFAM::GetNext(PGLOBAL g) +{ + int rc = zutp->nextEntry(g); - // Don't rely on ENDING setting - if (len > 0 && *(Mempos - 1) == '\n') - len--; // Line ends by LF + if (rc != RC_OK) + return rc; - if (len > 0 && *(Mempos - 2) == '\r') - len--; // Line ends by CRLF + int len = zutp->size; - memcpy(Tdbp->GetLine(), Fpos, len); - Tdbp->GetLine()[len] = '\0'; + if (len % Lrecl) { + sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl); + return RC_FX; + } // endif size + + Memory = zutp->memory; + Top = Memory + len; + Rewind(); return RC_OK; -} // end of ReadBuffer +} // end of GetNext diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h index c3c04b2b3bb..9312fb2f70e 100644 --- a/storage/connect/filamzip.h +++ b/storage/connect/filamzip.h @@ -18,66 +18,100 @@ typedef class ZIPFAM *PZIPFAM; typedef class ZPXFAM *PZPXFAM; /***********************************************************************/ -/* This is the ZIP file access method. */ +/* This is the ZIP utility fonctions class. */ /***********************************************************************/ -class DllExport ZIPFAM : public MAPFAM { +class DllExport ZIPUTIL : public BLOCK { public: // Constructor - ZIPFAM(PDOSDEF tdp); - ZIPFAM(PZIPFAM txfp); + ZIPUTIL(PSZ tgt, bool mul); +//ZIPUTIL(ZIPUTIL *zutp); // Implementation - virtual AMT GetAmType(void) {return TYPE_AM_ZIP;} - virtual PTXF Duplicate(PGLOBAL g) {return (PTXF) new(g) ZIPFAM(this);} +//PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)ZIPFAM(this); } // Methods - virtual int GetFileLength(PGLOBAL g); - virtual int Cardinality(PGLOBAL g) {return (g) ? 10 : 1;} -//virtual int MaxBlkSize(PGLOBAL g, int s) {return s;} - virtual bool OpenTableFile(PGLOBAL g); - virtual bool DeferReading(void) {return false;} - virtual int ReadBuffer(PGLOBAL g); -//virtual int WriteBuffer(PGLOBAL g); -//virtual int DeleteRecords(PGLOBAL g, int irc); -//virtual void CloseTableFile(PGLOBAL g, bool abort); - void close(void); - -protected: - bool open(PGLOBAL g, const char *filename); + virtual bool OpenTable(PGLOBAL g, MODE mode, char *fn); + bool open(PGLOBAL g, char *fn); bool openEntry(PGLOBAL g); + void close(void); void closeEntry(void); bool WildMatch(PSZ pat, PSZ str); int findEntry(PGLOBAL g, bool next); + int nextEntry(PGLOBAL g); // Members - unzFile zipfile; // The ZIP container file -//PSZ zfn; // The ZIP file name - PSZ target; // The target file name - unz_file_info finfo; // The current file info -//char fn[FILENAME_MAX]; // The current file name - bool entryopen; // True when open current entry - int multiple; // Multiple targets + unzFile zipfile; // The ZIP container file + PSZ target; // The target file name + unz_file_info finfo; // The current file info + PFBLOCK fp; + char *memory; + uint size; + int multiple; // Multiple targets + bool entryopen; // True when open current entry + char fn[FILENAME_MAX]; // The current entry file name char mapCaseTable[256]; }; // end of ZIPFAM +/***********************************************************************/ +/* This is the ZIP file access method. */ +/***********************************************************************/ +class DllExport ZIPFAM : public MAPFAM { + friend class ZPXFAM; +public: + // Constructors + ZIPFAM(PDOSDEF tdp); + ZIPFAM(PZIPFAM txfp); + ZIPFAM(PDOSDEF tdp, PZPXFAM txfp); + + // Implementation + virtual AMT GetAmType(void) { return TYPE_AM_ZIP; } + virtual PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)ZIPFAM(this); } + + // Methods + virtual int Cardinality(PGLOBAL g); + virtual int GetFileLength(PGLOBAL g); +//virtual int MaxBlkSize(PGLOBAL g, int s) {return s;} + virtual bool OpenTableFile(PGLOBAL g); + virtual bool DeferReading(void) { return false; } + virtual int GetNext(PGLOBAL g); +//virtual int ReadBuffer(PGLOBAL g); +//virtual int WriteBuffer(PGLOBAL g); +//virtual int DeleteRecords(PGLOBAL g, int irc); +//virtual void CloseTableFile(PGLOBAL g, bool abort); + +protected: + // Members + ZIPUTIL *zutp; + PSZ target; + bool mul; +}; // end of ZIPFAM + /***********************************************************************/ /* This is the fixed ZIP file access method. */ /***********************************************************************/ -class DllExport ZPXFAM : public ZIPFAM { +class DllExport ZPXFAM : public MPXFAM { + friend class ZIPFAM; public: - // Constructor + // Constructors ZPXFAM(PDOSDEF tdp); ZPXFAM(PZPXFAM txfp); // Implementation - virtual PTXF Duplicate(PGLOBAL g) {return (PTXF) new(g) ZPXFAM(this);} + virtual AMT GetAmType(void) { return TYPE_AM_ZIP; } + virtual PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)ZPXFAM(this); } // Methods - virtual int ReadBuffer(PGLOBAL g); + virtual int GetFileLength(PGLOBAL g); + virtual int Cardinality(PGLOBAL g); + virtual bool OpenTableFile(PGLOBAL g); + virtual int GetNext(PGLOBAL g); +//virtual int ReadBuffer(PGLOBAL g); protected: // Members - int Lrecl; + ZIPUTIL *zutp; + PSZ target; + bool mul; }; // end of ZPXFAM #endif // __FILAMZIP_H diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 45ca546ad4e..6590902bcd4 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1242,8 +1242,10 @@ char *ha_connect::GetStringOption(char *opname, char *sdef) if (opval && (!stricmp(opname, "connect") || !stricmp(opname, "tabname") - || !stricmp(opname, "filename"))) - opval = GetRealString(opval); + || !stricmp(opname, "filename") + || !stricmp(opname, "optname") + || !stricmp(opname, "entry"))) + opval = GetRealString(opval); if (!opval) { if (sdef && !strcmp(sdef, "*")) { diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp index c2882fc0d7c..2470d37c353 100644 --- a/storage/connect/libdoc.cpp +++ b/storage/connect/libdoc.cpp @@ -1,6 +1,6 @@ /******************************************************************/ /* Implementation of XML document processing using libxml2 */ -/* Author: Olivier Bertrand 2007-2015 */ +/* Author: Olivier Bertrand 2007-2016 */ /******************************************************************/ #include "my_global.h" #include @@ -68,8 +68,8 @@ class LIBXMLDOC : public XMLDOCUMENT { virtual void SetNofree(bool b) {Nofreelist = b;} // Methods - virtual bool Initialize(PGLOBAL g); - virtual bool ParseFile(char *fn); + virtual bool Initialize(PGLOBAL g, char *entry, bool zipped); + virtual bool ParseFile(PGLOBAL g, char *fn); virtual bool NewDoc(PGLOBAL g, char *ver); virtual void AddComment(PGLOBAL g, char *com); virtual PXNODE GetRoot(PGLOBAL g); @@ -373,22 +373,33 @@ LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp) /******************************************************************/ /* Initialize XML parser and check library compatibility. */ /******************************************************************/ -bool LIBXMLDOC::Initialize(PGLOBAL g) - { +bool LIBXMLDOC::Initialize(PGLOBAL g, char *entry, bool zipped) +{ + if (zipped && InitZip(g, entry)) + return true; + int n = xmlKeepBlanksDefault(1); return MakeNSlist(g); - } // end of Initialize +} // end of Initialize /******************************************************************/ /* Parse the XML file and construct node tree in memory. */ /******************************************************************/ -bool LIBXMLDOC::ParseFile(char *fn) +bool LIBXMLDOC::ParseFile(PGLOBAL g, char *fn) { if (trace) htrc("ParseFile\n"); - if ((Docp = xmlParseFile(fn))) { - if (Docp->encoding) + if (zip) { + // Parse an in memory document + char *xdoc = GetMemDoc(g, fn); + + Docp = (xdoc) ? xmlParseDoc((const xmlChar *)xdoc) : NULL; + } else + Docp = xmlParseFile(fn); + + if (Docp) { + if (Docp->encoding) Encoding = (char*)Docp->encoding; return false; @@ -609,6 +620,7 @@ void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) } // endif xp CloseXML2File(g, xp, false); + CloseZip(); } // end of Close /******************************************************************/ diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 31c040c6957..83975c6d8fa 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -939,7 +939,7 @@ int PlugCloseFile(PGLOBAL g __attribute__((unused)), PFBLOCK fp, bool all) #endif // LIBXML2_SUPPORT #ifdef ZIP_SUPPORT case TYPE_FB_ZIP: - ((PZIPFAM)fp->File)->close(); + ((ZIPUTIL*)fp->File)->close(); fp->Memory = NULL; fp->Mode = MODE_ANY; fp->Count = 0; diff --git a/storage/connect/plgxml.cpp b/storage/connect/plgxml.cpp index 3061a6d697e..71b72621b06 100644 --- a/storage/connect/plgxml.cpp +++ b/storage/connect/plgxml.cpp @@ -30,19 +30,51 @@ PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf, /* XMLDOCUMENT constructor. */ /******************************************************************/ XMLDOCUMENT::XMLDOCUMENT(char *nsl, char *nsdf, char *enc) - { - Namespaces = NULL; +{ +#if defined(ZIP_SUPPORT) + zip = NULL; +#else // !ZIP_SUPPORT + zip = false; +#endif // !ZIP_SUPPORT + Namespaces = NULL; Encoding = enc; Nslist = nsl; DefNs = nsdf; - } // end of XMLDOCUMENT constructor +} // end of XMLDOCUMENT constructor + +/******************************************************************/ +/* Initialize zipped file processing. */ +/******************************************************************/ +bool XMLDOCUMENT::InitZip(PGLOBAL g, char *entry) +{ +#if defined(ZIP_SUPPORT) + bool mul = (entry) ? strchr(entry, '*') || strchr(entry, '?') : false; + zip = new(g) ZIPUTIL(entry, mul); + return zip == NULL; +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return true; +#endif // !ZIP_SUPPORT +} // end of InitZip + +/******************************************************************/ +/* Make the namespace structure list. */ +/******************************************************************/ +char* XMLDOCUMENT::GetMemDoc(PGLOBAL g, char *fn) +{ +#if defined(ZIP_SUPPORT) + return (zip->OpenTable(g, MODE_ANY, fn)) ? NULL : zip->memory; +#else // !ZIP_SUPPORT + return NULL; +#endif // !ZIP_SUPPORT +} // end of GetMemDoc /******************************************************************/ /* Make the namespace structure list. */ /******************************************************************/ bool XMLDOCUMENT::MakeNSlist(PGLOBAL g) - { - char *prefix, *href, *next = Nslist; +{ + char *prefix, *href, *next = Nslist; PNS nsp, *ppns = &Namespaces; while (next) { @@ -83,6 +115,19 @@ bool XMLDOCUMENT::MakeNSlist(PGLOBAL g) return false; } // end of MakeNSlist +/******************************************************************/ +/* Close ZIP file. */ +/******************************************************************/ +void XMLDOCUMENT::CloseZip(void) +{ +#if defined(ZIP_SUPPORT) + if (zip) { + zip->close(); + zip = NULL; + } // endif zip +#endif // ZIP_SUPPORT +} // end of CloseZip + /******************************************************************/ /* XMLNODE constructor. */ /******************************************************************/ diff --git a/storage/connect/plgxml.h b/storage/connect/plgxml.h index b8e914e0bf1..db7dfa6bda5 100644 --- a/storage/connect/plgxml.h +++ b/storage/connect/plgxml.h @@ -1,3 +1,7 @@ +#if defined(ZIP_SUPPORT) +#include "filamzip.h" +#endif // ZIP_SUPPORT + /******************************************************************/ /* Dual XML implementation base classes defines. */ /******************************************************************/ @@ -72,8 +76,8 @@ class XMLDOCUMENT : public BLOCK { virtual void SetNofree(bool b) = 0; // Methods - virtual bool Initialize(PGLOBAL) = 0; - virtual bool ParseFile(char *) = 0; + virtual bool Initialize(PGLOBAL, char *, bool) = 0; + virtual bool ParseFile(PGLOBAL, char *) = 0; virtual bool NewDoc(PGLOBAL, char *) = 0; virtual void AddComment(PGLOBAL, char *) = 0; virtual PXNODE GetRoot(PGLOBAL) = 0; @@ -91,8 +95,16 @@ class XMLDOCUMENT : public BLOCK { // Utility bool MakeNSlist(PGLOBAL g); + bool InitZip(PGLOBAL g, char *entry); + char *GetMemDoc(PGLOBAL g, char *fn); + void CloseZip(void); // Members +#if defined(ZIP_SUPPORT) + ZIPUTIL *zip; /* Used for zipped file */ +#else // !ZIP_SUPPORT + bool zip; /* Always false */ +#endif // !ZIP_SUPPORT PNS Namespaces; /* To the namespaces */ char *Encoding; /* The document encoding */ char *Nslist; /* Namespace list */ diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp index f47e66b014b..16cc6c33b44 100644 --- a/storage/connect/tabdos.cpp +++ b/storage/connect/tabdos.cpp @@ -101,6 +101,7 @@ DOSDEF::DOSDEF(void) Recfm = RECFM_VAR; Mapped = false; Zipped = false; + Mulentries = false; Padded = false; Huge = false; Accept = false; @@ -131,12 +132,13 @@ bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int) : (am && (*am == 'B' || *am == 'b')) ? "B" : (am && !stricmp(am, "DBF")) ? "D" : "V"; - if (*dfm != 'D') - Zipped = GetBoolCatInfo("Zipped", false); + if ((Zipped = GetBoolCatInfo("Zipped", false))) + Mulentries = ((Entry = GetStringCatInfo(g, "Entry", NULL))) + ? strchr(Entry, '*') || strchr(Entry, '?') + : GetBoolCatInfo("Mulentries", false); Desc = Fn = GetStringCatInfo(g, "Filename", NULL); Ofn = GetStringCatInfo(g, "Optname", Fn); - Entry = GetStringCatInfo(g, "Entry", NULL); GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf)); Recfm = (toupper(*buf) == 'F') ? RECFM_FIX : (toupper(*buf) == 'B') ? RECFM_BIN : @@ -344,14 +346,16 @@ PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode) /*********************************************************************/ if (Zipped) { #if defined(ZIP_SUPPORT) - if (Recfm == RECFM_VAR) - txfp = new(g) ZIPFAM(this); - else - txfp = new(g) ZPXFAM(this); + if (Recfm == RECFM_VAR) { + txfp = new(g)ZIPFAM(this); + tdbp = new(g)TDBDOS(this, txfp); + } else { + txfp = new(g)ZPXFAM(this); + tdbp = new(g)TDBFIX(this, txfp); + } // endif Recfm - tdbp = new(g) TDBDOS(this, txfp); #else // !ZIP_SUPPORT - strcpy(g->Message, "ZIP not supported"); + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); return NULL; #endif // !ZIP_SUPPORT } else if (Recfm == RECFM_DBF) { @@ -559,7 +563,7 @@ int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox) Txfp->Reset(); ((PZLBFAM)Txfp)->SetOptimized(false); #endif // GZ_SUPPORT - } else if (Txfp->GetAmType() == TYPE_AM_BLK) + } else if (Txfp->GetAmType() == TYPE_AM_BLK) Txfp = new(g) DOSFAM((PDOSDEF)To_Def); Txfp->SetTdbp(this); @@ -630,7 +634,12 @@ int TDBDOS::MakeBlockValues(PGLOBAL g) defp->SetOptimized(0); // Estimate the number of needed blocks - block = (int)((MaxSize + (int)nrec - 1) / (int)nrec); + if ((block = (int)((MaxSize + (int)nrec - 1) / (int)nrec)) < 2) { + // This may be wrong to do in some cases + defp->RemoveOptValues(g); + strcpy(g->Message, MSG(TABLE_NOT_OPT)); + return RC_INFO; // Not to be optimized + } // endif block // We have to use local variables because Txfp->CurBlk is set // to Rows+1 by unblocked variable length table access methods. @@ -973,13 +982,14 @@ bool TDBDOS::GetBlockValues(PGLOBAL g) PCOLDEF cdp; PDOSDEF defp = (PDOSDEF)To_Def; PCATLG cat = defp->GetCat(); + PDBUSER dup = PlgGetUser(g); #if 0 if (Mode == MODE_INSERT && Txfp->GetAmType() == TYPE_AM_DOS) return false; #endif // __WIN__ - if (defp->Optimized) + if (defp->Optimized || !(dup->Check & CHK_OPT)) return false; // Already done or to be redone if (Ftype == RECFM_VAR || defp->Compressed == 2) { diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h index 623adcfed0d..4c8eb438a26 100644 --- a/storage/connect/tabdos.h +++ b/storage/connect/tabdos.h @@ -28,7 +28,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ friend class TDBFIX; friend class TXTFAM; friend class DBFBASE; - friend class ZIPFAM; + friend class ZIPUTIL; public: // Constructor DOSDEF(void); @@ -41,7 +41,9 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ virtual bool IsHuge(void) {return Huge;} PSZ GetFn(void) {return Fn;} PSZ GetOfn(void) {return Ofn;} - void SetBlock(int block) {Block = block;} + PSZ GetEntry(void) {return Entry;} + bool GetMul(void) {return Mulentries;} + void SetBlock(int block) {Block = block;} int GetBlock(void) {return Block;} int GetLast(void) {return Last;} void SetLast(int last) {Last = last;} @@ -58,9 +60,9 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ int *GetTo_Pos(void) {return To_Pos;} // Methods - virtual int Indexable(void) - {return (!Multiple && !Zipped && Compressed != 1) ? 1 : 0;} - virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf); + virtual int Indexable(void) + {return (!Multiple && !Mulentries && Compressed != 1) ? 1 : 0;} + virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf); virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); virtual PTDB GetTable(PGLOBAL g, MODE mode); bool InvalidateIndex(PGLOBAL g); @@ -78,6 +80,7 @@ class DllExport DOSDEF : public TABDEF { /* Logical table description */ RECFM Recfm; /* 0:VAR, 1:FIX, 2:BIN, 3:VCT, 6:DBF */ bool Mapped; /* 0: disk file, 1: memory mapped file */ bool Zipped; /* true for zipped table file */ + bool Mulentries; /* true for multiple entries */ bool Padded; /* true for padded table file */ bool Huge; /* true for files larger than 2GB */ bool Accept; /* true if wrong lines are accepted */ diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 2c4d605e66c..b24375443f6 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -177,9 +177,14 @@ PQRYRES CSVColumns(PGLOBAL g, char *dp, PTOS topt, bool info) htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n", SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr); - if (tdp->Zipped) - tdbp = new(g) TDBCSV(tdp, new(g) ZIPFAM(tdp)); - else + if (tdp->Zipped) { +#if defined(ZIP_SUPPORT) + tdbp = new(g)TDBCSV(tdp, new(g)ZIPFAM(tdp)); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else tdbp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp)); tdbp->SetMode(MODE_READ); diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index eff95445a3a..1b9ce8b64c9 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -127,9 +127,14 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp->Fn, tdp->Objname, tdp->Pretty, lvl); if (tdp->Pretty == 2) { - if (tdp->Zipped) - tjsp = new(g) TDBJSON(tdp, new(g) ZIPFAM(tdp)); - else + if (tdp->Zipped) { +#if defined(ZIP_SUPPORT) + tjsp = new(g) TDBJSON(tdp, new(g) ZIPFAM(tdp)); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); if (tjsp->MakeDocument(g)) @@ -144,9 +149,14 @@ PQRYRES JSONColumns(PGLOBAL g, char *db, PTOS topt, bool info) tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); - if (tdp->Zipped) - tjnp = new(g) TDBJSN(tdp, new(g) ZIPFAM(tdp)); - else + if (tdp->Zipped) { +#if defined(ZIP_SUPPORT) + tjnp = new(g)TDBJSN(tdp, new(g)ZIPFAM(tdp)); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); tjnp->SetMode(MODE_READ); @@ -467,9 +477,14 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) ((TDBJSN*)tdbp)->G = g; #endif } else { - if (Zipped) - txfp = new(g) ZIPFAM(this); - else + if (Zipped) { +#if defined(ZIP_SUPPORT) + txfp = new(g)ZIPFAM(this); +#else // !ZIP_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; +#endif // !ZIP_SUPPORT + } else txfp = new(g) MAPFAM(this); tdbp = new(g) TDBJSON(this, txfp); diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index 1993b07eb7a..3b8229fcf51 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -1,9 +1,9 @@ /************* Tabxml C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABXML */ /* ------------- */ -/* Version 2.8 */ +/* Version 2.9 */ /* */ -/* Author Olivier BERTRAND 2007 - 2015 */ +/* Author Olivier BERTRAND 2007 - 2016 */ /* */ /* This program are the XML tables classes using MS-DOM or libxml2. */ /***********************************************************************/ @@ -159,6 +159,8 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) tdp->Fn = fn; tdp->Database = SetPath(g, db); tdp->Tabname = tab; + tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); + tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); if (!(op = GetStringTableOption(g, topt, "Xmlsup", NULL))) #if defined(__WIN__) @@ -209,7 +211,8 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) while (true) { if (!vp->atp && - !(node = (vp->nl) ? vp->nl->GetItem(g, vp->k++, node) : NULL)) + !(node = (vp->nl) ? vp->nl->GetItem(g, vp->k++, tdp->Usedom ? node : NULL) + : NULL)) if (j) { vp = lvlp[--j]; @@ -259,7 +262,8 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) if (j < lvl && ok) { vp = lvlp[j+1]; vp->k = 0; - vp->atp = node->GetAttribute(g, NULL); + vp->pn = node; + vp->atp = node->GetAttribute(g, NULL); vp->nl = node->GetChildElements(g); if (tdp->Usedom && vp->nl->GetLength() == 1) { @@ -270,7 +274,7 @@ PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info) if (vp->atp || vp->b) { if (!vp->atp) - node = vp->nl->GetItem(g, vp->k++, node); + node = vp->nl->GetItem(g, vp->k++, tdp->Usedom ? node : NULL); strncat(fmt, colname, XLEN(fmt)); strncat(fmt, "/", XLEN(fmt)); @@ -429,11 +433,14 @@ XMLDEF::XMLDEF(void) DefNs = NULL; Attrib = NULL; Hdattr = NULL; + Entry = NULL; Coltype = 1; Limit = 0; Header = 0; Xpand = false; Usedom = false; + Zipped = false; + Mulentries = false; } // end of XMLDEF constructor /***********************************************************************/ @@ -512,7 +519,14 @@ bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) // Get eventual table node attribute Attrib = GetStringCatInfo(g, "Attribute", NULL); Hdattr = GetStringCatInfo(g, "HeadAttr", NULL); - return false; + + // Specific for zipped files + if ((Zipped = GetBoolCatInfo("Zipped", false))) + Mulentries = ((Entry = GetStringCatInfo(g, "Entry", NULL))) + ? strchr(Entry, '*') || strchr(Entry, '?') + : GetBoolCatInfo("Mulentries", false); + + return false; } // end of DefineAM /***********************************************************************/ @@ -552,6 +566,7 @@ TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp) Xfile = tdp->Fn; Enc = tdp->Encoding; Tabname = tdp->Tabname; +#if 0 // why all these? Rowname = (tdp->Rowname) ? tdp->Rowname : NULL; Colname = (tdp->Colname) ? tdp->Colname : NULL; Mulnode = (tdp->Mulnode) ? tdp->Mulnode : NULL; @@ -560,10 +575,22 @@ TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp) DefNs = (tdp->DefNs) ? tdp->DefNs : NULL; Attrib = (tdp->Attrib) ? tdp->Attrib : NULL; Hdattr = (tdp->Hdattr) ? tdp->Hdattr : NULL; - Coltype = tdp->Coltype; +#endif // 0 + Rowname = tdp->Rowname; + Colname = tdp->Colname; + Mulnode = tdp->Mulnode; + XmlDB = tdp->XmlDB; + Nslist = tdp->Nslist; + DefNs = tdp->DefNs; + Attrib = tdp->Attrib; + Hdattr = tdp->Hdattr; + Entry = tdp->Entry; + Coltype = tdp->Coltype; Limit = tdp->Limit; Xpand = tdp->Xpand; - Changed = false; + Zipped = tdp->Zipped; + Mulentries = tdp->Mulentries; + Changed = false; Checked = false; NextSame = false; NewRow = false; @@ -605,10 +632,13 @@ TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp) DefNs = tdbp->DefNs; Attrib = tdbp->Attrib; Hdattr = tdbp->Hdattr; - Coltype = tdbp->Coltype; + Entry = tdbp->Entry; + Coltype = tdbp->Coltype; Limit = tdbp->Limit; Xpand = tdbp->Xpand; - Changed = tdbp->Changed; + Zipped = tdbp->Zipped; + Mulentries = tdbp->Mulentries; + Changed = tdbp->Changed; Checked = tdbp->Checked; NextSame = tdbp->NextSame; NewRow = tdbp->NewRow; @@ -686,7 +716,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) /*********************************************************************/ /* Firstly we check whether this file have been already loaded. */ /*********************************************************************/ - if (Mode == MODE_READ || Mode == MODE_ANY) + if ((Mode == MODE_READ || Mode == MODE_ANY) && !Zipped) for (fp = dup->Openlist; fp; fp = fp->Next) if (fp->Type == type && fp->Length && fp->Count) if (!stricmp(fp->Fname, filename)) @@ -708,7 +738,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) return RC_FX; // Initialize the implementation - if (Docp->Initialize(g)) { + if (Docp->Initialize(g, Entry, Zipped)) { sprintf(g->Message, MSG(INIT_FAILED), (Usedom) ? "DOM" : "libxml2"); return RC_FX; } // endif init @@ -717,7 +747,7 @@ int TDBXML::LoadTableFile(PGLOBAL g, char *filename) htrc("TDBXML: parsing %s rc=%d\n", filename, rc); // Parse the XML file - if (Docp->ParseFile(filename)) { + if (Docp->ParseFile(g, filename)) { // Does the file exist? int h= global_open(g, MSGID_NONE, filename, _O_RDONLY); diff --git a/storage/connect/tabxml.h b/storage/connect/tabxml.h index 7ba3166881d..6c586d79dec 100644 --- a/storage/connect/tabxml.h +++ b/storage/connect/tabxml.h @@ -1,7 +1,7 @@ /*************** Tabxml H Declares Source Code File (.H) ***************/ -/* Name: TABXML.H Version 1.6 */ +/* Name: TABXML.H Version 1.7 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2007-2015 */ +/* (C) Copyright to the author Olivier BERTRAND 2007-2016 */ /* */ /* This file contains the XML table classes declares. */ /***********************************************************************/ @@ -42,12 +42,15 @@ class DllExport XMLDEF : public TABDEF { /* Logical table description */ char *DefNs; /* Dummy name of default namespace */ char *Attrib; /* Table node attributes */ char *Hdattr; /* Header node attributes */ - int Coltype; /* Default column type */ + char *Entry; /* Zip entry name or pattern */ + int Coltype; /* Default column type */ int Limit; /* Limit of multiple values */ int Header; /* n first rows are header rows */ bool Xpand; /* Put multiple tags in several rows */ bool Usedom; /* True: DOM, False: libxml2 */ - }; // end of XMLDEF + bool Zipped; /* True: Zipped XML file(s) */ + bool Mulentries; /* True: multiple entries in zip file*/ +}; // end of XMLDEF #if defined(INCLUDE_TDBXML) /***********************************************************************/ @@ -122,7 +125,9 @@ class DllExport TDBXML : public TDBASE { bool Bufdone; // True when column buffers allocated bool Nodedone; // True when column nodes allocated bool Void; // True if the file does not exist - char *Xfile; // The XML file + bool Zipped; // True if Zipped XML file(s) + bool Mulentries; // True if multiple entries in zip file + char *Xfile; // The XML file char *Enc; // New XML table file encoding char *Tabname; // Name of Table node char *Rowname; // Name of first level nodes @@ -133,7 +138,8 @@ class DllExport TDBXML : public TDBASE { char *DefNs; // Dummy name of default namespace char *Attrib; // Table node attribut(s) char *Hdattr; // Header node attribut(s) - int Coltype; // Default column type + char *Entry; // Zip entry name or pattern + int Coltype; // Default column type int Limit; // Limit of multiple values int Header; // n first rows are header rows int Multiple; // If multiple files From 2718225b2626eeb8df9ab71547a81e43104d52ab Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Sat, 24 Dec 2016 09:47:55 -0500 Subject: [PATCH 065/124] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4f1ecb3a197..bc0b19220b6 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=54 +MYSQL_VERSION_PATCH=55 MYSQL_VERSION_EXTRA= From 43147681503299ccdf31e23e84dd39aeff52b2df Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 25 Dec 2016 12:32:05 +0100 Subject: [PATCH 066/124] Modified version number --- storage/connect/ha_connect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 6590902bcd4..33f02d8338c 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -6955,7 +6955,7 @@ maria_declare_plugin(connect) 0x0104, /* version number (1.04) */ NULL, /* status variables */ connect_system_variables, /* system variables */ - "1.04.0008", /* string version */ + "1.05.0001", /* string version */ MariaDB_PLUGIN_MATURITY_GAMMA /* maturity */ } maria_declare_plugin_end; From 11544334a277508fb984c0a5bba8faa6b97a2762 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 27 Dec 2016 14:13:32 +0530 Subject: [PATCH 067/124] MDEV-11636 Extra persistent columns on slave always gets NULL in RBR Problem:- In replication if slave has extra persistent column then these column are not computed while applying write-set from master. Solution:- While applying row events from server, we will generate values for extra persistent columns. --- .../rpl/r/rpl_alter_extra_persistent.result | 220 ++++++++++++++++++ .../rpl/t/rpl_alter_extra_persistent.test | 106 +++++++++ sql/rpl_record.cc | 31 +++ sql/rpl_record.h | 1 + 4 files changed, 358 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_alter_extra_persistent.result create mode 100644 mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test diff --git a/mysql-test/suite/rpl/r/rpl_alter_extra_persistent.result b/mysql-test/suite/rpl/r/rpl_alter_extra_persistent.result new file mode 100644 index 00000000000..84915073d87 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_alter_extra_persistent.result @@ -0,0 +1,220 @@ +include/master-slave.inc +[connection master] +connection master; +create table t1(a int primary key); +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +insert into t1 values(4); +connection slave; +select * from t1 order by a; +a +1 +2 +3 +4 +alter table t1 add column z1 int as(a+1) virtual, add column z2 int as (a+2) persistent; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +connection master; +insert into t1 values(5); +insert into t1 values(6); +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +5 6 7 +6 7 8 +#UPDATE query +connection master; +update t1 set a = a+10; +select * from t1 order by a; +a +11 +12 +13 +14 +15 +16 +connection slave; +select * from t1 order by a; +a z1 z2 +11 12 13 +12 13 14 +13 14 15 +14 15 16 +15 16 17 +16 17 18 +connection master; +update t1 set a = a-10; +select * from t1 order by a; +a +1 +2 +3 +4 +5 +6 +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +5 6 7 +6 7 8 +#DELETE quert +connection master; +delete from t1 where a > 2 and a < 4; +select * from t1 order by a; +a +1 +2 +4 +5 +6 +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +4 5 6 +5 6 7 +6 7 8 +#REPLACE query +connection master; +replace into t1 values(1); +replace into t1 values(3); +replace into t1 values(1); +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +5 6 7 +6 7 8 +#SELECT query +connection master; +select * from t1 where a > 2 and a < 4; +a +3 +connection slave; +select * from t1 where a > 2 and a < 4; +a z1 z2 +3 4 5 +#UPDATE with SELECT query +connection master; +update t1 set a = a + 10 where a > 2 and a < 4; +select * from t1 order by a; +a +1 +2 +4 +5 +6 +13 +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +4 5 6 +5 6 7 +6 7 8 +13 14 15 +connection master; +update t1 set a = a - 10 where a = 13; +select * from t1 order by a; +a +1 +2 +3 +4 +5 +6 +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +5 6 7 +6 7 8 +#Break Unique Constraint +alter table t1 add column z4 int as (a % 6) persistent unique; +connection master; +#entering duplicate value for slave persistent column +insert into t1 values(7); +select * from t1 order by a; +a +1 +2 +3 +4 +5 +6 +7 +connection slave; +include/wait_for_slave_sql_error.inc [errno=1062] +connection slave; +connection slave; +select * from t1 order by a; +a z1 z2 z4 +1 2 3 1 +2 3 4 2 +3 4 5 3 +4 5 6 4 +5 6 7 5 +6 7 8 0 +alter table t1 drop column z4; +start slave; +include/wait_for_slave_sql_to_start.inc +connection slave; +connection slave; +connection master; +connection slave; +select * from t1 order by a; +a z1 z2 +1 2 3 +2 3 4 +3 4 5 +4 5 6 +5 6 7 +6 7 8 +7 8 9 +connection master; +select * from t1 order by a; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +include/rpl_end.inc +connection server_2; +connection server_2; +connection server_2; +connection server_2; +connection server_1; +connection server_1; +connection server_1; +connection server_2; +connection server_1; +connection server_2; +connection server_2; +connection server_1; +connection server_1; diff --git a/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test b/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test new file mode 100644 index 00000000000..3b2fff1cb13 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_alter_extra_persistent.test @@ -0,0 +1,106 @@ +--source include/master-slave.inc +--source include/have_binlog_format_row.inc + +--enable_connect_log +--connection master +create table t1(a int primary key); +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +insert into t1 values(4); + +--sync_slave_with_master +select * from t1 order by a; +alter table t1 add column z1 int as(a+1) virtual, add column z2 int as (a+2) persistent; +select * from t1 order by a; + +--connection master +insert into t1 values(5); +insert into t1 values(6); + +--sync_slave_with_master +select * from t1 order by a; + + +--echo #UPDATE query + +--connection master +update t1 set a = a+10; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--connection master +update t1 set a = a-10; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #DELETE quert +--connection master +delete from t1 where a > 2 and a < 4; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #REPLACE query +--connection master +replace into t1 values(1); +replace into t1 values(3); +replace into t1 values(1); + +--sync_slave_with_master +select * from t1 order by a; + +--echo #SELECT query +--connection master +select * from t1 where a > 2 and a < 4; + +--connection slave +select * from t1 where a > 2 and a < 4; + +--echo #UPDATE with SELECT query +--connection master +update t1 set a = a + 10 where a > 2 and a < 4; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--connection master +update t1 set a = a - 10 where a = 13; +select * from t1 order by a; + +--sync_slave_with_master +select * from t1 order by a; + +--echo #Break Unique Constraint +alter table t1 add column z4 int as (a % 6) persistent unique; + +--connection master + +--echo #entering duplicate value for slave persistent column +insert into t1 values(7); +select * from t1 order by a; + +--connection slave +--let $slave_sql_errno= 1062 +--source include/wait_for_slave_sql_error.inc +select * from t1 order by a; +alter table t1 drop column z4; +start slave; + +--source include/wait_for_slave_sql_to_start.inc + +--connection master +--sync_slave_with_master +select * from t1 order by a; + +--connection master +select * from t1 order by a; +drop table t1; + +--source include/rpl_end.inc diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index df8036c40d8..21b8a8028a6 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -407,6 +407,12 @@ unpack_row(rpl_group_info *rgi, } } + /* + Add Extra slave persistent columns + */ + if ((error= fill_extra_persistent_columns(table, cols->n_bits))) + DBUG_RETURN(error); + /* We should now have read all the null bytes, otherwise something is really wrong. @@ -479,5 +485,30 @@ int prepare_record(TABLE *const table, const uint skip, const bool check) DBUG_RETURN(0); } +/** + Fills @c table->record[0] with computed values of extra persistent column which are present on slave but not on master. + @param table Table whose record[0] buffer is prepared. + @param master_cols No of columns on master + @returns 0 on success + */ +int fill_extra_persistent_columns(TABLE *table, int master_cols) +{ + int error= 0; + Field **vfield_ptr, *vfield; + if (!table->vfield) + return 0; + for (vfield_ptr= table->vfield; *vfield_ptr; ++vfield_ptr) + { + vfield= *vfield_ptr; + if (vfield->field_index >= master_cols && vfield->stored_in_db) + { + /*Set bitmap for writing*/ + bitmap_set_bit(table->vcol_set, vfield->field_index); + error= vfield->vcol_info->expr_item->save_in_field(vfield,0); + bitmap_clear_bit(table->vcol_set, vfield->field_index); + } + } + return error; +} #endif // HAVE_REPLICATION diff --git a/sql/rpl_record.h b/sql/rpl_record.h index c10eb8225b0..be69716d9d5 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -38,6 +38,7 @@ int unpack_row(rpl_group_info *rgi, // Fill table's record[0] with default values. int prepare_record(TABLE *const table, const uint skip, const bool check); +int fill_extra_persistent_columns(TABLE *table, int master_cols); #endif #endif From 0912fbbce179cba38bd41de797ba5934e63dbaad Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Wed, 4 Jan 2017 03:33:39 +0200 Subject: [PATCH 068/124] MDEV-11719 main.subselect_no_exists_to_in failed in buildbot main.log_slow might leave mysql.slow_log table non-empty, and tests which later use it might fail. Make sure that the table is properly truncated --- mysql-test/r/log_slow.result | 2 +- mysql-test/t/log_slow.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/log_slow.result b/mysql-test/r/log_slow.result index 89846dc698c..b396de8a3d8 100644 --- a/mysql-test/r/log_slow.result +++ b/mysql-test/r/log_slow.result @@ -67,9 +67,9 @@ sleep(0.5) select count(*) FROM mysql.slow_log; count(*) 1 -truncate mysql.slow_log; set @@long_query_time=default; set global slow_query_log= @org_slow_query_log; set @@log_slow_filter=default; set @@log_slow_verbosity=default; set global log_output= default; +truncate mysql.slow_log; diff --git a/mysql-test/t/log_slow.test b/mysql-test/t/log_slow.test index 8d5a09d7a94..56e35bd5a20 100644 --- a/mysql-test/t/log_slow.test +++ b/mysql-test/t/log_slow.test @@ -50,7 +50,6 @@ set global slow_query_log=1; set global log_output='TABLE'; select sleep(0.5); select count(*) FROM mysql.slow_log; -truncate mysql.slow_log; # Reset used variables set @@long_query_time=default; @@ -58,3 +57,4 @@ set global slow_query_log= @org_slow_query_log; set @@log_slow_filter=default; set @@log_slow_verbosity=default; set global log_output= default; +truncate mysql.slow_log; From e5d7fc967ede53407a65bfde3faec3181e35f19f Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Wed, 4 Jan 2017 13:03:30 +0200 Subject: [PATCH 069/124] MDEV-10100 main.pool_of_threads fails sporadically in buildbot Backport the fix to 5.5, because it fails there too The patch fixes two test failures: - on slow builders, sometimes a connection attempt which should fail due to the exceeded number of thread_pool_max_threads actually succeeds; - on even slow builders, MTR sometimes cannot establish the initial connection, and check-testcase fails prior to the test start The problem with check-testcase was caused by connect-timeout=2 which was set for all clients in the test config file. On slow builders it might be not enough. There is no way to override it for the pre-test check, so it needed to be substantially increased or removed. The other problem was caused by a race condition between sleeps that the test performs in existing connections and the connect timeout for the connection attempt which was expected to fail. If sleeps finished before the connect-timeout was exceeded, it would allow the connection to succeed. To solve each problem without making the other one worse, connect-timeout should be configured dynamically during the test. Due to the nature of the test (all connections must be busy at the moment when we need to change the timeout, and cannot execute SET GLOBAL ...), it needs to be done independently from the server. The solution: - recognize 'connect_timeout' as a connection option in mysqltest's "connect" command; - remove connect-timeout from the test configuration file; - use the new connect_timeout option for those connections which are expected to fail; - re-arrange the test flow to allow running a huge SLEEP without affecting the test execution time (because it would be interrupted after the main test flow is finished). The test is still subject to false negatives, e.g. if the connection fails due to timeout rather than due to the exceeded number of allowed threads, or if the connection on extra port succeeds due to a race condition and not because the special logic for the extra port. But those false negatives have always been possible there on slow builders, they should not be critical because faster builders should catch such failures if they appear. Conflicts: client/mysqltest.cc mysql-test/r/pool_of_threads.result mysql-test/t/pool_of_threads.test --- client/mysqltest.cc | 8 +++++ mysql-test/r/pool_of_threads.result | 21 +++++++------ mysql-test/t/pool_of_threads.cnf | 3 -- mysql-test/t/pool_of_threads.test | 46 ++++++++++++++++------------- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 5daa0e72270..d9fa9bc0bef 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -5900,6 +5900,7 @@ void do_connect(struct st_command *command) my_bool con_ssl= 0, con_compress= 0; my_bool con_pipe= 0; my_bool con_shm __attribute__ ((unused))= 0; + int connect_timeout= 0; struct st_connection* con_slot; static DYNAMIC_STRING ds_connection_name; @@ -5996,6 +5997,9 @@ void do_connect(struct st_command *command) con_pipe= 1; else if (length == 3 && !strncmp(con_options, "SHM", 3)) con_shm= 1; + else if (strncasecmp(con_options, "connect_timeout=", + sizeof("connect_timeout=")-1) == 0) + connect_timeout= atoi(con_options + sizeof("connect_timeout=")-1); else die("Illegal option to connect: %.*s", (int) (end - con_options), con_options); @@ -6066,6 +6070,10 @@ void do_connect(struct st_command *command) if (opt_protocol) mysql_options(con_slot->mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); + if (connect_timeout) + mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, + (char*)&connect_timeout); + #ifdef HAVE_SMEM if (con_shm) { diff --git a/mysql-test/r/pool_of_threads.result b/mysql-test/r/pool_of_threads.result index 7acb45121d6..f153ebc48f4 100644 --- a/mysql-test/r/pool_of_threads.result +++ b/mysql-test/r/pool_of_threads.result @@ -2157,23 +2157,22 @@ Warnings: Warning 1052 Column 'kundentyp' in group statement is ambiguous drop table t1; SET optimizer_switch=@save_optimizer_switch; -SELECT sleep(5); -SELECT sleep(5); +SELECT sleep(50); +SELECT sleep(50); # -- Success: more than --thread_pool_max_threads normal connections not possible -sleep(5) -0 -sleep(5) -0 -SELECT sleep(5); -SELECT sleep(5); SELECT 'Connection on extra port ok'; Connection on extra port ok Connection on extra port ok +SELECT sleep(5.5); SELECT 'Connection on extra port 2 ok'; Connection on extra port 2 ok Connection on extra port 2 ok # -- Success: more than --extra-max-connections + 1 normal connections not possible -sleep(5) -0 -sleep(5) +KILL QUERY ; +KILL QUERY ; +sleep(50) +1 +sleep(50) +1 +sleep(5.5) 0 diff --git a/mysql-test/t/pool_of_threads.cnf b/mysql-test/t/pool_of_threads.cnf index c03e1da6450..f6651c878de 100644 --- a/mysql-test/t/pool_of_threads.cnf +++ b/mysql-test/t/pool_of_threads.cnf @@ -7,8 +7,5 @@ loose-thread_pool_max_threads= 2 extra-port= @ENV.MASTER_EXTRA_PORT extra-max-connections=1 -[client] -connect-timeout= 2 - [ENV] MASTER_EXTRA_PORT= @OPT.port diff --git a/mysql-test/t/pool_of_threads.test b/mysql-test/t/pool_of_threads.test index 4600128ff43..f13a096985c 100644 --- a/mysql-test/t/pool_of_threads.test +++ b/mysql-test/t/pool_of_threads.test @@ -15,20 +15,26 @@ SET optimizer_switch=@save_optimizer_switch; # connections on the extra port. # First set two connections running, and check that extra connection -# on normal port fails due to--thread-pool-max_threads=2 +# on normal port fails due to --thread-pool-max-threads=2. +# We can afford using a really long sleep, because we won't wait +# till it ends, we'll interrupt it as soon as we don't need it anymore + connection default; -send SELECT sleep(5); +--let $con1_id= `SELECT CONNECTION_ID()` + +send SELECT sleep(50); --sleep 1 connect(con2,localhost,root,,); -connection con2; -send SELECT sleep(5); +--let $con2_id= `SELECT CONNECTION_ID()` + +send SELECT sleep(50); --sleep 0.5 --disable_abort_on_error --disable_result_log --disable_query_log -connect(con3,localhost,root,,); +connect(con3,localhost,root,,,,,connect_timeout=2); --enable_query_log --enable_result_log --enable_abort_on_error @@ -42,24 +48,15 @@ if ($error) --echo # -- Success: more than --thread_pool_max_threads normal connections not possible } -connection default; ---reap -connection con2; ---reap - -# Now try again, but this time use the extra port to successfully connect. - -connection default; -send SELECT sleep(5); - -connection con2; -send SELECT sleep(5); ---sleep 1 - connect(extracon,127.0.0.1,root,,test,$MASTER_EXTRA_PORT,); connection extracon; SELECT 'Connection on extra port ok'; +# Here, sleep just for slightly longer than 5 sec to trigger MDEV-4566 +# (abort in interruptible wait connection check). +send SELECT sleep(5.5); + + connect(extracon2,127.0.0.1,root,,test,$MASTER_EXTRA_PORT,); connection extracon2; SELECT 'Connection on extra port 2 ok'; @@ -67,7 +64,7 @@ SELECT 'Connection on extra port 2 ok'; --disable_abort_on_error --disable_result_log --disable_query_log -connect(extracon3,127.0.0.1,root,,test,$MASTER_EXTRA_PORT,); +connect(extracon3,127.0.0.1,root,,test,$MASTER_EXTRA_PORT,,connect_timeout=2); --enable_query_log --enable_result_log --enable_abort_on_error @@ -81,7 +78,16 @@ if ($error) --echo # -- Success: more than --extra-max-connections + 1 normal connections not possible } +connection extracon2; +--replace_result $con1_id +eval KILL QUERY $con1_id; +--replace_result $con2_id +eval KILL QUERY $con2_id; + connection default; --reap connection con2; --reap + +connection extracon; +--reap From f4d12c1d3fd79db8d30a7de3de3b851d2fa0a397 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 4 Jan 2017 13:36:55 +0100 Subject: [PATCH 070/124] MDEV-11676 Starting service with mysqld_safe_helper fails in SELINUX "enforcing" mode correct the error message in case of setuid/setgid failures --- mysys/my_setuser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysys/my_setuser.c b/mysys/my_setuser.c index 1f3e7770d4c..14ab04dd10f 100644 --- a/mysys/my_setuser.c +++ b/mysys/my_setuser.c @@ -74,7 +74,8 @@ int my_set_user(const char *user, struct passwd *user_info, myf MyFlags) { my_errno= errno; if (MyFlags & MY_WME) - my_error(my_errno, MYF(ME_NOREFRESH)); + my_printf_error(errno, "Cannot change uid/gid (errno: %d)", MYF(ME_NOREFRESH), + errno); DBUG_RETURN(my_errno); } DBUG_RETURN(0); From f1ee011a6cbda1069a6ec9b5e2428451a64861fd Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Wed, 4 Jan 2017 23:05:22 +0200 Subject: [PATCH 071/124] MDEV-11722 main.join_cache fails in buildbot on very slow builders The guilty part of the test checks for performance degradation on a query with numerous joins on an empty table. The test expects the query to take less than 1 second, and fails if it is not so (which can happen on very slow builders). The solution is to add more JOINs to the query. On a fixed server, it should not have any noticeable impact on the query execution, while on the unfixed version the query would take several times longer (e.g. 6.5 sec vs 1.5 sec). Thus, we can increase the margin for the error, and make the test fail when the query takes longer than 5 seconds. --- mysql-test/r/join_cache.result | 16 ++++++++++++---- mysql-test/t/join_cache.test | 10 ++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result index 8a2bdcec8a2..cc64393f975 100644 --- a/mysql-test/r/join_cache.result +++ b/mysql-test/r/join_cache.result @@ -5702,11 +5702,13 @@ LEFT JOIN t2 c1 ON c1.parent_id = t.id AND c1.col2 = "val" LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; id col1 -select timestampdiff(second, @init_time, now()) <= 1; -timestampdiff(second, @init_time, now()) <= 1 +select timestampdiff(second, @init_time, now()) <= 5; +timestampdiff(second, @init_time, now()) <= 5 1 set join_cache_level=2; set @init_time:=now(); @@ -5738,11 +5740,13 @@ LEFT JOIN t2 c1 ON c1.parent_id = t.id AND c1.col2 = "val" LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; id col1 -select timestampdiff(second, @init_time, now()) <= 1; -timestampdiff(second, @init_time, now()) <= 1 +select timestampdiff(second, @init_time, now()) <= 5; +timestampdiff(second, @init_time, now()) <= 5 1 EXPLAIN SELECT t.* @@ -5773,6 +5777,8 @@ LEFT JOIN t2 c1 ON c1.parent_id = t.id AND c1.col2 = "val" LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; id select_type table type possible_keys key key_len ref rows Extra @@ -5802,6 +5808,8 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE c23 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE c24 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) 1 SIMPLE c25 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE c26 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) +1 SIMPLE c27 ALL NULL NULL NULL NULL 1 Using where; Using join buffer (incremental, BNL join) set join_buffer_size=default; set join_cache_level = default; DROP TABLE t1,t2; diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test index 1d22de86799..77e8fce0d27 100644 --- a/mysql-test/t/join_cache.test +++ b/mysql-test/t/join_cache.test @@ -3709,9 +3709,11 @@ FROM LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; -select timestampdiff(second, @init_time, now()) <= 1; +select timestampdiff(second, @init_time, now()) <= 5; set join_cache_level=2; @@ -3744,9 +3746,11 @@ FROM LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; -select timestampdiff(second, @init_time, now()) <= 1; +select timestampdiff(second, @init_time, now()) <= 5; EXPLAIN SELECT t.* @@ -3777,6 +3781,8 @@ FROM LEFT JOIN t2 c23 ON c23.parent_id = t.id AND c23.col2 = "val" LEFT JOIN t2 c24 ON c24.parent_id = t.id AND c24.col2 = "val" LEFT JOIN t2 c25 ON c25.parent_id = t.id AND c25.col2 = "val" + LEFT JOIN t2 c26 ON c26.parent_id = t.id AND c26.col2 = "val" + LEFT JOIN t2 c27 ON c27.parent_id = t.id AND c27.col2 = "val" ORDER BY col1; From 5302ef2c955d98bf3b1fb1f94c036d904c8af922 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Sun, 1 Jan 2017 23:13:04 +0200 Subject: [PATCH 072/124] MDEV-11700 funcs_2.innodb_charset fails in buldbot on valgrind builder with timeout When the test is run as a part of the suite with valgrind, only allow it to be executed if --big-test is set. If the test is run by specifying its name explicitly, it will still be executed, even with valgrind without big-test, MTR has special logic for that --- mysql-test/suite/funcs_2/t/innodb_charset.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/funcs_2/t/innodb_charset.test b/mysql-test/suite/funcs_2/t/innodb_charset.test index b77bacfc01c..da4dea44ad7 100644 --- a/mysql-test/suite/funcs_2/t/innodb_charset.test +++ b/mysql-test/suite/funcs_2/t/innodb_charset.test @@ -6,6 +6,7 @@ # Checking of other prerequisites is in charset_master.test # ################################################################################ +--source include/no_valgrind_without_big.inc --source include/have_innodb.inc let $engine_type= InnoDB; From 9e528d4fdeab83fcc75ec788da939937ce27b98d Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Thu, 5 Jan 2017 17:38:55 +0200 Subject: [PATCH 073/124] MDEV-11727 Sequences of tests fail with valgrind warnings in buildbot The warning is "blocks are still reachable in loss record", happens in malloc / _dl_close_worker. Suppression added --- mysql-test/valgrind.supp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index b86cbd23408..154031feb0d 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -923,6 +923,14 @@ fun:backtrace } +{ + memory leak in mysqld_exit + Memcheck:Leak + fun:malloc + fun:_dl_close_worker + fun:_dl_close +} + # # Bug in Glibc 2.9: http://sourceware.org/bugzilla/show_bug.cgi?id=10391 # Fixed in latest Glibc, but suppressed here for running tests on hosts From ae1b3d1991b679bb38095711de27934d7683deda Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 5 Jan 2017 13:54:31 -0800 Subject: [PATCH 074/124] Fixed bug mdev-10705. The fix for bug mdev-5104 did not take into account that for any call of setup_order the size of ref_array must be big enough. This patch fixes this problem. --- mysql-test/r/order_by.result | 11 +++++++++++ mysql-test/t/order_by.test | 10 ++++++++++ sql/sql_select.cc | 7 ++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 6ce12651dba..94a38ca7827 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -2050,4 +2050,15 @@ t2 A, t2 B where A.b = B.b order by A.col2, B.col2 limit 10, 1000000; drop table t1,t2,t3; +# +# mdev-10705 : long order by list that can be skipped +# +SELECT 1 +UNION +( SELECT 2 +ORDER BY NULL, @a0 := 3, @a1 := 3, @a2 := 3, @a3 := 3, @a4 := 3, +@a5 := 3, @a6 := 3, @a7 := 3, @a8 := 3, @a9 := 3, @a10 := 3 ); +1 +1 +2 End of 5.5 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 2ebf8ba5af1..c96d5c2996a 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1746,6 +1746,16 @@ order by A.col2, B.col2 limit 10, 1000000; drop table t1,t2,t3; +--echo # +--echo # mdev-10705 : long order by list that can be skipped +--echo # + +SELECT 1 +UNION +( SELECT 2 + ORDER BY NULL, @a0 := 3, @a1 := 3, @a2 := 3, @a3 := 3, @a4 := 3, + @a5 := 3, @a6 := 3, @a7 := 3, @a8 := 3, @a9 := 3, @a10 := 3 ); + --echo End of 5.5 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c406fab5a3a..2c65c59ad7e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -714,10 +714,15 @@ JOIN::prepare(Item ***rref_pointer_array, if (mixed_implicit_grouping && tbl->table) tbl->table->maybe_null= 1; } + + uint real_og_num= og_num; + if (skip_order_by && + select_lex != select_lex->master_unit()->global_parameters) + real_og_num+= select_lex->order_list.elements; if ((wild_num && setup_wild(thd, tables_list, fields_list, &all_fields, wild_num)) || - select_lex->setup_ref_array(thd, og_num) || + select_lex->setup_ref_array(thd, real_og_num) || setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ, &all_fields, 1) || setup_without_group(thd, (*rref_pointer_array), tables_list, From 6ac84d9824ec384c4489b68b8087369aef147ff9 Mon Sep 17 00:00:00 2001 From: vicentiu Date: Sat, 7 Jan 2017 14:24:42 +0200 Subject: [PATCH 075/124] 5.6.35 --- storage/innobase/dict/dict0stats.cc | 13 +++- storage/innobase/fts/fts0opt.cc | 7 +- storage/innobase/handler/ha_innodb.cc | 38 +++++++++++ storage/innobase/handler/handler0alter.cc | 79 +++++++++++++---------- storage/innobase/include/os0thread.h | 13 +++- storage/innobase/include/srv0srv.h | 1 + storage/innobase/mach/mach0data.cc | 57 ++++++++++++---- storage/innobase/os/os0thread.cc | 32 ++++++++- storage/innobase/row/row0ftsort.cc | 2 +- storage/innobase/row/row0merge.cc | 7 ++ storage/innobase/row/row0mysql.cc | 2 + storage/innobase/srv/srv0srv.cc | 1 + 12 files changed, 190 insertions(+), 62 deletions(-) diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 9aa63caa579..b0ba98308be 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2009, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1095,7 +1095,8 @@ dict_stats_analyze_index_level( them away) which brings non-determinism. We skip only leaf-level delete marks because delete marks on non-leaf level do not make sense. */ - if (level == 0 && + + if (level == 0 && srv_stats_include_delete_marked? 0: rec_get_deleted_flag( rec, page_is_comp(btr_pcur_get_page(&pcur)))) { @@ -1281,8 +1282,12 @@ enum page_scan_method_t { the given page and count the number of distinct ones, also ignore delete marked records */ - QUIT_ON_FIRST_NON_BORING/* quit when the first record that differs + QUIT_ON_FIRST_NON_BORING,/* quit when the first record that differs from its right neighbor is found */ + COUNT_ALL_NON_BORING_INCLUDE_DEL_MARKED/* scan all records on + the given page and count the number of + distinct ones, include delete marked + records */ }; /* @} */ @@ -1558,6 +1563,8 @@ dict_stats_analyze_index_below_cur( offsets_rec = dict_stats_scan_page( &rec, offsets1, offsets2, index, page, n_prefix, + srv_stats_include_delete_marked ? + COUNT_ALL_NON_BORING_INCLUDE_DEL_MARKED: COUNT_ALL_NON_BORING_AND_SKIP_DEL_MARKED, n_diff, n_external_pages); diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 0d45a195c95..19098dc00ef 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -578,9 +578,6 @@ fts_zip_read_word( fts_zip_t* zip, /*!< in: Zip state + data */ fts_string_t* word) /*!< out: uncompressed word */ { -#ifdef UNIV_DEBUG - ulint i; -#endif short len = 0; void* null = NULL; byte* ptr = word->f_str; @@ -655,10 +652,9 @@ fts_zip_read_word( } } -#ifdef UNIV_DEBUG /* All blocks must be freed at end of inflate. */ if (zip->status != Z_OK) { - for (i = 0; i < ib_vector_size(zip->blocks); ++i) { + for (ulint i = 0; i < ib_vector_size(zip->blocks); ++i) { if (ib_vector_getp(zip->blocks, i)) { ut_free(ib_vector_getp(zip->blocks, i)); ib_vector_set(zip->blocks, i, &null); @@ -669,7 +665,6 @@ fts_zip_read_word( if (ptr != NULL) { ut_ad(word->f_len == strlen((char*) ptr)); } -#endif /* UNIV_DEBUG */ return(zip->status == Z_OK || zip->status == Z_STREAM_END ? ptr : NULL); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index be5e74e1617..41c767a4bfc 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13359,6 +13359,37 @@ ha_innobase::get_auto_increment( ulonglong col_max_value = innobase_get_int_col_max_value( table->next_number_field); + /** The following logic is needed to avoid duplicate key error + for autoincrement column. + + (1) InnoDB gives the current autoincrement value with respect + to increment and offset value. + + (2) Basically it does compute_next_insert_id() logic inside InnoDB + to avoid the current auto increment value changed by handler layer. + + (3) It is restricted only for insert operations. */ + + if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE + && autoinc < col_max_value) { + + ulonglong prev_auto_inc = autoinc; + + autoinc = ((autoinc - 1) + increment - offset)/ increment; + + autoinc = autoinc * increment + offset; + + /* If autoinc exceeds the col_max_value then reset + to old autoinc value. Because in case of non-strict + sql mode, boundary value is not considered as error. */ + + if (autoinc >= col_max_value) { + autoinc = prev_auto_inc; + } + + ut_ad(autoinc > 0); + } + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -15880,6 +15911,12 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, "Disable with --skip-innodb-doublewrite.", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(stats_include_delete_marked, + srv_stats_include_delete_marked, + PLUGIN_VAR_OPCMDARG, + "Scan delete marked records for persistent stat", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, PLUGIN_VAR_RQCMDARG, "Number of IOPs the server can do. Tunes the background IO rate", @@ -16681,6 +16718,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(data_file_path), MYSQL_SYSVAR(data_home_dir), MYSQL_SYSVAR(doublewrite), + MYSQL_SYSVAR(stats_include_delete_marked), MYSQL_SYSVAR(api_enable_binlog), MYSQL_SYSVAR(api_enable_mdl), MYSQL_SYSVAR(api_disable_rowlock), diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 2261754a4f5..e772208ed72 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1709,6 +1709,7 @@ innobase_fts_check_doc_id_index_in_def( return(FTS_NOT_EXIST_DOC_ID_INDEX); } + /*******************************************************************//** Create an index table where indexes are ordered as follows: @@ -1775,26 +1776,11 @@ innobase_create_key_defs( (only prefix/part of the column is indexed), MySQL will treat the index as a PRIMARY KEY unless the table already has one. */ - if (n_add > 0 && !new_primary && got_default_clust - && (key_info[*add].flags & HA_NOSAME) - && !(key_info[*add].flags & HA_KEY_HAS_PART_KEY_SEG)) { - uint key_part = key_info[*add].user_defined_key_parts; + ut_ad(altered_table->s->primary_key == 0 + || altered_table->s->primary_key == MAX_KEY); - new_primary = true; - - while (key_part--) { - const uint maybe_null - = key_info[*add].key_part[key_part].key_type - & FIELDFLAG_MAYBE_NULL; - DBUG_ASSERT(!maybe_null - == !key_info[*add].key_part[key_part]. - field->real_maybe_null()); - - if (maybe_null) { - new_primary = false; - break; - } - } + if (got_default_clust && !new_primary) { + new_primary = (altered_table->s->primary_key != MAX_KEY); } const bool rebuild = new_primary || add_fts_doc_id @@ -1812,8 +1798,14 @@ innobase_create_key_defs( ulint primary_key_number; if (new_primary) { - DBUG_ASSERT(n_add > 0); - primary_key_number = *add; + if (n_add == 0) { + DBUG_ASSERT(got_default_clust); + DBUG_ASSERT(altered_table->s->primary_key + == 0); + primary_key_number = 0; + } else { + primary_key_number = *add; + } } else if (got_default_clust) { /* Create the GEN_CLUST_INDEX */ index_def_t* index = indexdef++; @@ -2900,6 +2892,8 @@ prepare_inplace_alter_table_dict( ctx->add_cols = add_cols; } else { DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info)); + DBUG_ASSERT(old_table->s->primary_key + == altered_table->s->primary_key); if (!ctx->new_table->fts && innobase_fulltext_exist(altered_table)) { @@ -3892,6 +3886,27 @@ found_col: add_fts_doc_id_idx)); } +/** Get the name of an erroneous key. +@param[in] error_key_num InnoDB number of the erroneus key +@param[in] ha_alter_info changes that were being performed +@param[in] table InnoDB table +@return the name of the erroneous key */ +static +const char* +get_error_key_name( + ulint error_key_num, + const Alter_inplace_info* ha_alter_info, + const dict_table_t* table) +{ + if (error_key_num == ULINT_UNDEFINED) { + return(FTS_DOC_ID_INDEX_NAME); + } else if (ha_alter_info->key_count == 0) { + return(dict_table_get_first_index(table)->name); + } else { + return(ha_alter_info->key_info_buffer[error_key_num].name); + } +} + /** Alter the table structure in-place with operations specified using Alter_inplace_info. The level of concurrency allowed during this operation depends @@ -4009,17 +4024,13 @@ oom: case DB_ONLINE_LOG_TOO_BIG: DBUG_ASSERT(ctx->online); my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), - (prebuilt->trx->error_key_num == ULINT_UNDEFINED) - ? FTS_DOC_ID_INDEX_NAME - : ha_alter_info->key_info_buffer[ - prebuilt->trx->error_key_num].name); + get_error_key_name(prebuilt->trx->error_key_num, + ha_alter_info, prebuilt->table)); break; case DB_INDEX_CORRUPT: my_error(ER_INDEX_CORRUPT, MYF(0), - (prebuilt->trx->error_key_num == ULINT_UNDEFINED) - ? FTS_DOC_ID_INDEX_NAME - : ha_alter_info->key_info_buffer[ - prebuilt->trx->error_key_num].name); + get_error_key_name(prebuilt->trx->error_key_num, + ha_alter_info, prebuilt->table)); break; default: my_error_innodb(error, @@ -4829,7 +4840,6 @@ innobase_update_foreign_cache( "Foreign key constraints for table '%s'" " are loaded with charset check off", user_table->name); - } } @@ -4929,14 +4939,13 @@ commit_try_rebuild( DBUG_RETURN(true); case DB_ONLINE_LOG_TOO_BIG: my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), - ha_alter_info->key_info_buffer[0].name); + get_error_key_name(err_key, ha_alter_info, + rebuilt_table)); DBUG_RETURN(true); case DB_INDEX_CORRUPT: my_error(ER_INDEX_CORRUPT, MYF(0), - (err_key == ULINT_UNDEFINED) - ? FTS_DOC_ID_INDEX_NAME - : ha_alter_info->key_info_buffer[err_key] - .name); + get_error_key_name(err_key, ha_alter_info, + rebuilt_table)); DBUG_RETURN(true); default: my_error_innodb(error, table_name, user_table->flags); diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h index 9a1ada8fa0d..54f3d7554bf 100644 --- a/storage/innobase/include/os0thread.h +++ b/storage/innobase/include/os0thread.h @@ -117,14 +117,25 @@ os_thread_create_func( os_thread_id_t* thread_id); /*!< out: id of the created thread, or NULL */ +/** Waits until the specified thread completes and joins it. +Its return value is ignored. +@param[in,out] thread thread to join */ +UNIV_INTERN +void +os_thread_join( + os_thread_t thread); + /*****************************************************************//** Exits the current thread. */ UNIV_INTERN void os_thread_exit( /*===========*/ - void* exit_value) /*!< in: exit value; in Windows this void* + void* exit_value, /*!< in: exit value; in Windows this void* is cast as a DWORD */ + bool detach = true) /*!< in: if true, the thread will be detached + right before exiting. If false, another thread + is responsible for joining this thread. */ UNIV_COLD MY_ATTRIBUTE((noreturn)); /*****************************************************************//** Returns the thread identifier of current thread. diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index aaea21b264b..042ced75d10 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -347,6 +347,7 @@ extern unsigned long long srv_stats_transient_sample_pages; extern my_bool srv_stats_persistent; extern unsigned long long srv_stats_persistent_sample_pages; extern my_bool srv_stats_auto_recalc; +extern my_bool srv_stats_include_delete_marked; extern ibool srv_use_doublewrite_buf; extern ulong srv_doublewrite_batch_size; diff --git a/storage/innobase/mach/mach0data.cc b/storage/innobase/mach/mach0data.cc index df68aab8a18..feeedb01609 100644 --- a/storage/innobase/mach/mach0data.cc +++ b/storage/innobase/mach/mach0data.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -55,8 +55,22 @@ mach_parse_compressed( if (flag < 0x80UL) { *val = flag; return(ptr + 1); + } - } else if (flag < 0xC0UL) { + /* Workaround GCC bug + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673: + the compiler moves mach_read_from_4 right to the beginning of the + function, causing and out-of-bounds read if we are reading a short + integer close to the end of buffer. */ +#if defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__clang__) +#define DEPLOY_FENCE +#endif + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xC0UL) { if (end_ptr < ptr + 2) { return(NULL); } @@ -64,8 +78,13 @@ mach_parse_compressed( *val = mach_read_from_2(ptr) & 0x7FFFUL; return(ptr + 2); + } - } else if (flag < 0xE0UL) { +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xE0UL) { if (end_ptr < ptr + 3) { return(NULL); } @@ -73,7 +92,13 @@ mach_parse_compressed( *val = mach_read_from_3(ptr) & 0x3FFFFFUL; return(ptr + 3); - } else if (flag < 0xF0UL) { + } + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + + if (flag < 0xF0UL) { if (end_ptr < ptr + 4) { return(NULL); } @@ -81,14 +106,20 @@ mach_parse_compressed( *val = mach_read_from_4(ptr) & 0x1FFFFFFFUL; return(ptr + 4); - } else { - ut_ad(flag == 0xF0UL); - - if (end_ptr < ptr + 5) { - return(NULL); - } - - *val = mach_read_from_4(ptr + 1); - return(ptr + 5); } + +#ifdef DEPLOY_FENCE + __atomic_thread_fence(__ATOMIC_ACQUIRE); +#endif + +#undef DEPLOY_FENCE + + ut_ad(flag == 0xF0UL); + + if (end_ptr < ptr + 5) { + return(NULL); + } + + *val = mach_read_from_4(ptr + 1); + return(ptr + 5); } diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc index 772336215c9..d6f897ca46a 100644 --- a/storage/innobase/os/os0thread.cc +++ b/storage/innobase/os/os0thread.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -191,14 +191,38 @@ os_thread_create_func( #endif } +/** Waits until the specified thread completes and joins it. +Its return value is ignored. +@param[in,out] thread thread to join */ +UNIV_INTERN +void +os_thread_join( + os_thread_t thread) +{ +#ifdef __WIN__ + /* Do nothing. */ +#else +#ifdef UNIV_DEBUG + const int ret = +#endif /* UNIV_DEBUG */ + pthread_join(thread, NULL); + + /* Waiting on already-quit threads is allowed. */ + ut_ad(ret == 0 || ret == ESRCH); +#endif /* __WIN__ */ +} + /*****************************************************************//** Exits the current thread. */ UNIV_INTERN void os_thread_exit( /*===========*/ - void* exit_value) /*!< in: exit value; in Windows this void* + void* exit_value, /*!< in: exit value; in Windows this void* is cast as a DWORD */ + bool detach) /*!< in: if true, the thread will be detached + right before exiting. If false, another thread + is responsible for joining this thread. */ { #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Thread exits, id %lu\n", @@ -216,7 +240,9 @@ os_thread_exit( #ifdef __WIN__ ExitThread((DWORD) exit_value); #else - pthread_detach(pthread_self()); + if (detach) { + pthread_detach(pthread_self()); + } pthread_exit(exit_value); #endif } diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 4fd3a51040a..7d3fcf675ec 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -957,7 +957,7 @@ fts_parallel_merge( CloseHandle(psort_info->thread_hdl); #endif /*__WIN__ */ - os_thread_exit(NULL); + os_thread_exit(NULL, false); OS_THREAD_DUMMY_RETURN; } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index c094be8a23b..f8bea67906c 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -3774,6 +3774,13 @@ wait_again: " exited when creating FTS" " index '%s'", indexes[i]->name); + } else { + for (j = 0; j < FTS_NUM_AUX_INDEX; + j++) { + + os_thread_join(merge_info[j] + .thread_hdl); + } } } else { /* This cannot report duplicates; an diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 11bef1064d6..09c20911ec9 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1362,6 +1362,8 @@ run_again: row_ins_step(thr); + DEBUG_SYNC_C("ib_after_row_insert_step"); + err = trx->error_state; if (err != DB_SUCCESS) { diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 7a7783b962c..a67f3a776c5 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -340,6 +340,7 @@ this many index pages, there are 2 ways to calculate statistics: table/index are not found in the innodb database */ UNIV_INTERN unsigned long long srv_stats_transient_sample_pages = 8; UNIV_INTERN my_bool srv_stats_persistent = TRUE; +UNIV_INTERN my_bool srv_stats_include_delete_marked = FALSE; UNIV_INTERN unsigned long long srv_stats_persistent_sample_pages = 20; UNIV_INTERN my_bool srv_stats_auto_recalc = TRUE; From c33db2cdc0ab70a874060d58710895f6dac3dea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Sat, 7 Jan 2017 15:53:37 +0200 Subject: [PATCH 076/124] 5.6.35 --- storage/perfschema/pfs.cc | 34 ++++-- storage/perfschema/pfs_digest.cc | 122 ++++++++++++--------- storage/perfschema/pfs_digest.h | 5 +- storage/perfschema/pfs_lock.h | 14 ++- storage/perfschema/table_esms_by_digest.cc | 22 ++-- 5 files changed, 131 insertions(+), 66 deletions(-) diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index cf0fa82ba3f..3bbc0a4602e 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -2560,10 +2560,7 @@ start_table_io_wait_v1(PSI_table_locker_state *state, if (! pfs_table->m_io_enabled) return NULL; - PFS_thread *pfs_thread= pfs_table->m_thread_owner; - - DBUG_ASSERT(pfs_thread == - my_pthread_getspecific_ptr(PFS_thread*, THR_PFS)); + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); register uint flags; ulonglong timer_start= 0; @@ -2666,7 +2663,7 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, if (! pfs_table->m_lock_enabled) return NULL; - PFS_thread *pfs_thread= pfs_table->m_thread_owner; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); PFS_TL_LOCK_TYPE lock_type; @@ -3068,7 +3065,12 @@ start_socket_wait_v1(PSI_socket_locker_state *state, if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= pfs_socket->m_thread_owner; + /* + Do not use pfs_socket->m_thread_owner here, + as different threads may use concurrently the same socket, + for example during a KILL. + */ + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); if (unlikely(pfs_thread == NULL)) return NULL; @@ -3436,6 +3438,8 @@ static void end_idle_wait_v1(PSI_idle_locker* locker) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } @@ -3517,6 +3521,8 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } } @@ -3596,6 +3602,8 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } } @@ -3668,6 +3676,8 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } } @@ -3732,6 +3742,8 @@ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } } @@ -3826,6 +3838,8 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } @@ -3895,6 +3909,8 @@ static void end_table_lock_wait_v1(PSI_table_locker* locker) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } @@ -4143,6 +4159,8 @@ static void end_file_wait_v1(PSI_file_locker *locker, if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } } @@ -5070,6 +5088,8 @@ static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count) if (flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); } } diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc index 1053bd59571..5886c379b2f 100644 --- a/storage/perfschema/pfs_digest.cc +++ b/storage/perfschema/pfs_digest.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -45,7 +45,7 @@ bool flag_statements_digest= true; Current index in Stat array where new record is to be inserted. index 0 is reserved for "all else" case when entire array is full. */ -volatile uint32 digest_index; +volatile uint32 PFS_ALIGNED digest_monotonic_index; bool digest_full= false; LF_HASH digest_hash; @@ -63,7 +63,7 @@ int init_digest(const PFS_global_param *param) */ digest_max= param->m_digest_sizing; digest_lost= 0; - digest_index= 1; + PFS_atomic::store_u32(& digest_monotonic_index, 1); digest_full= false; if (digest_max == 0) @@ -105,6 +105,9 @@ int init_digest(const PFS_global_param *param) + index * pfs_max_digest_length, pfs_max_digest_length); } + /* Set record[0] as allocated. */ + statements_digest_stat_array[0].m_lock.set_allocated(); + return 0; } @@ -207,9 +210,10 @@ find_or_create_digest(PFS_thread *thread, memcpy(hash_key.m_schema_name, schema_name, schema_name_length); int res; - ulong safe_index; uint retry_count= 0; const uint retry_max= 3; + size_t safe_index; + size_t attempts= 0; PFS_statements_digest_stat **entry; PFS_statements_digest_stat *pfs= NULL; @@ -245,55 +249,70 @@ search: return & pfs->m_stat; } - safe_index= PFS_atomic::add_u32(& digest_index, 1); - if (safe_index >= digest_max) + while (++attempts <= digest_max) { - /* The digest array is now full. */ - digest_full= true; - pfs= &statements_digest_stat_array[0]; - - if (pfs->m_first_seen == 0) - pfs->m_first_seen= now; - pfs->m_last_seen= now; - return & pfs->m_stat; - } - - /* Add a new record in digest stat array. */ - pfs= &statements_digest_stat_array[safe_index]; - - /* Copy digest hash/LF Hash search key. */ - memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key)); - - /* - Copy digest storage to statement_digest_stat_array so that it could be - used later to generate digest text. - */ - pfs->m_digest_storage.copy(digest_storage); - - pfs->m_first_seen= now; - pfs->m_last_seen= now; - - res= lf_hash_insert(&digest_hash, pins, &pfs); - if (likely(res == 0)) - { - return & pfs->m_stat; - } - - if (res > 0) - { - /* Duplicate insert by another thread */ - if (++retry_count > retry_max) + safe_index= PFS_atomic::add_u32(& digest_monotonic_index, 1) % digest_max; + if (safe_index == 0) { - /* Avoid infinite loops */ - digest_lost++; - return NULL; + /* Record [0] is reserved. */ + safe_index= 1; + } + + /* Add a new record in digest stat array. */ + pfs= &statements_digest_stat_array[safe_index]; + + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + /* Copy digest hash/LF Hash search key. */ + memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key)); + + /* + Copy digest storage to statement_digest_stat_array so that it could be + used later to generate digest text. + */ + pfs->m_digest_storage.copy(digest_storage); + + pfs->m_first_seen= now; + pfs->m_last_seen= now; + + res= lf_hash_insert(&digest_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return & pfs->m_stat; + } + + pfs->m_lock.dirty_to_free(); + + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) + { + /* Avoid infinite loops */ + digest_lost++; + return NULL; + } + goto search; + } + + /* OOM in lf_hash_insert */ + digest_lost++; + return NULL; + } } - goto search; } - /* OOM in lf_hash_insert */ - digest_lost++; - return NULL; + /* The digest array is now full. */ + digest_full= true; + pfs= &statements_digest_stat_array[0]; + + if (pfs->m_first_seen == 0) + pfs->m_first_seen= now; + pfs->m_last_seen= now; + return & pfs->m_stat; } void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key) @@ -320,10 +339,12 @@ void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key) void PFS_statements_digest_stat::reset_data(unsigned char *token_array, uint length) { + m_lock.set_dirty(); m_digest_storage.reset(token_array, length); m_stat.reset(); m_first_seen= 0; m_last_seen= 0; + m_lock.dirty_to_free(); } void PFS_statements_digest_stat::reset_index(PFS_thread *thread) @@ -351,11 +372,14 @@ void reset_esms_by_digest() statements_digest_stat_array[index].reset_data(statements_digest_token_array + index * pfs_max_digest_length, pfs_max_digest_length); } + /* Mark record[0] as allocated again. */ + statements_digest_stat_array[0].m_lock.set_allocated(); + /* Reset index which indicates where the next calculated digest information to be inserted in statements_digest_stat_array. */ - digest_index= 1; + PFS_atomic::store_u32(& digest_monotonic_index, 1); digest_full= false; } diff --git a/storage/perfschema/pfs_digest.h b/storage/perfschema/pfs_digest.h index 76d6c33d984..429a9f4250a 100644 --- a/storage/perfschema/pfs_digest.h +++ b/storage/perfschema/pfs_digest.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -44,6 +44,9 @@ struct PFS_digest_key /** A statement digest stat record. */ struct PFS_ALIGNED PFS_statements_digest_stat { + /** Internal lock. */ + pfs_lock m_lock; + /** Digest Schema + MD5 Hash. */ PFS_digest_key m_digest_key; diff --git a/storage/perfschema/pfs_lock.h b/storage/perfschema/pfs_lock.h index c429d934702..339a893c833 100644 --- a/storage/perfschema/pfs_lock.h +++ b/storage/perfschema/pfs_lock.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -155,6 +155,18 @@ struct pfs_lock PFS_atomic::store_u32(&m_version_state, new_val); } + /** + Initialize a lock to dirty. + */ + void set_dirty(void) + { + /* Do not set the version to 0, read the previous value. */ + uint32 copy= PFS_atomic::load_u32(&m_version_state); + /* Increment the version, set the DIRTY state */ + uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_DIRTY; + PFS_atomic::store_u32(&m_version_state, new_val); + } + /** Execute a dirty to free transition. This transition should be executed by the writer that owns the record. diff --git a/storage/perfschema/table_esms_by_digest.cc b/storage/perfschema/table_esms_by_digest.cc index 99e24316cbb..002a7f0104b 100644 --- a/storage/perfschema/table_esms_by_digest.cc +++ b/storage/perfschema/table_esms_by_digest.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. 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 @@ -238,11 +238,14 @@ int table_esms_by_digest::rnd_next(void) m_pos.next()) { digest_stat= &statements_digest_stat_array[m_pos.m_index]; - if (digest_stat->m_first_seen != 0) + if (digest_stat->m_lock.is_populated()) { - make_row(digest_stat); - m_next_pos.set_after(&m_pos); - return 0; + if (digest_stat->m_first_seen != 0) + { + make_row(digest_stat); + m_next_pos.set_after(&m_pos); + return 0; + } } } @@ -260,10 +263,13 @@ table_esms_by_digest::rnd_pos(const void *pos) set_position(pos); digest_stat= &statements_digest_stat_array[m_pos.m_index]; - if (digest_stat->m_first_seen != 0) + if (digest_stat->m_lock.is_populated()) { - make_row(digest_stat); - return 0; + if (digest_stat->m_first_seen != 0) + { + make_row(digest_stat); + return 0; + } } return HA_ERR_RECORD_DELETED; From 3e63fde52eb42ff23a9b260ed42b18284628ea42 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 9 Jan 2017 14:19:02 +0400 Subject: [PATCH 077/124] Adding LOAD DATA tests for MDEV-11079 and MDEV-11631 c3cf7f47f0f4a1ec314001aaf0c3d9c1c1f62097 reverted the patch for BUG#24487120. After merging the reverting patch from MySQL to MariaDB the problems described in MDEV-11079 and MDEV-11631 disappeared. Adding test cases only. --- mysql-test/r/loaddata.result | 18 ++++++++++++++++++ mysql-test/std_data/loaddata/mdev-11079.txt | 1 + mysql-test/std_data/loaddata/mdev-11631.txt | 1 + mysql-test/t/loaddata.test | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 mysql-test/std_data/loaddata/mdev-11079.txt create mode 100644 mysql-test/std_data/loaddata/mdev-11631.txt diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 8ccc1a3da3d..ce26abea66d 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -532,3 +532,21 @@ FIELDS TERMINATED BY 't' LINES TERMINATED BY ''; Got one of the listed errors SET @@sql_mode= @old_mode; DROP TABLE t1; +# +# MDEV-11079 Regression: LOAD DATA INFILE lost BLOB support using utf8 load files +# +CREATE TABLE t1 (a mediumblob NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +LOAD DATA INFILE '../../std_data/loaddata/mdev-11079.txt' INTO TABLE t1 CHARSET utf8 FIELDS TERMINATED BY ';' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n'; +SELECT HEX(a) FROM t1; +HEX(a) +25AAABAC +DROP TABLE t1; +# +# MDEV-11631 LOAD DATA INFILE fails to load data with an escape character followed by a multi-byte character +# +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8); +LOAD DATA INFILE '../../std_data/loaddata/mdev-11631.txt' INTO TABLE t1 CHARACTER SET utf8; +SELECT HEX(a) FROM t1; +HEX(a) +C3A4 +DROP TABLE t1; diff --git a/mysql-test/std_data/loaddata/mdev-11079.txt b/mysql-test/std_data/loaddata/mdev-11079.txt new file mode 100644 index 00000000000..a792f984d5f --- /dev/null +++ b/mysql-test/std_data/loaddata/mdev-11079.txt @@ -0,0 +1 @@ +"%" diff --git a/mysql-test/std_data/loaddata/mdev-11631.txt b/mysql-test/std_data/loaddata/mdev-11631.txt new file mode 100644 index 00000000000..87b824b71ae --- /dev/null +++ b/mysql-test/std_data/loaddata/mdev-11631.txt @@ -0,0 +1 @@ +\ä diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 35243864c04..1bc7eb139b9 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -658,3 +658,21 @@ SET @@sql_mode= @old_mode; --remove_file $MYSQLTEST_VARDIR/mysql DROP TABLE t1; + +--echo # +--echo # MDEV-11079 Regression: LOAD DATA INFILE lost BLOB support using utf8 load files +--echo # + +CREATE TABLE t1 (a mediumblob NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci; +LOAD DATA INFILE '../../std_data/loaddata/mdev-11079.txt' INTO TABLE t1 CHARSET utf8 FIELDS TERMINATED BY ';' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n'; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +--echo # +--echo # MDEV-11631 LOAD DATA INFILE fails to load data with an escape character followed by a multi-byte character +--echo # + +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8); +LOAD DATA INFILE '../../std_data/loaddata/mdev-11631.txt' INTO TABLE t1 CHARACTER SET utf8; +SELECT HEX(a) FROM t1; +DROP TABLE t1; From ecdb39a9f51ebbdafae167889ec65ee817e07de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 10 Jan 2017 12:08:36 +0200 Subject: [PATCH 078/124] Fix problems from 5.5 merge * Update mysqld_safe script to remove duplicated parameter --crash-script * Make --core-file-size accept underscores as well as dashes correctly. * Add mysqld_safe_helper to Debian and Ubuntu files. * Update innodb minor version to 35 --- debian/dist/Debian/mariadb-server-10.0.files.in | 1 + debian/dist/Ubuntu/mariadb-server-10.0.files.in | 1 + scripts/mysqld_safe.sh | 3 +-- storage/innobase/include/univ.i | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debian/dist/Debian/mariadb-server-10.0.files.in b/debian/dist/Debian/mariadb-server-10.0.files.in index 88516bb6089..9feec684ff0 100644 --- a/debian/dist/Debian/mariadb-server-10.0.files.in +++ b/debian/dist/Debian/mariadb-server-10.0.files.in @@ -38,6 +38,7 @@ usr/bin/mysql_zap usr/bin/mysqlbinlog usr/bin/mysqld_multi usr/bin/mysqld_safe +usr/bin/mysqld_safe_helper usr/bin/mysqlhotcopy usr/bin/perror usr/bin/replace diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.files.in b/debian/dist/Ubuntu/mariadb-server-10.0.files.in index 849a763dccd..a5e8bd6e717 100644 --- a/debian/dist/Ubuntu/mariadb-server-10.0.files.in +++ b/debian/dist/Ubuntu/mariadb-server-10.0.files.in @@ -40,6 +40,7 @@ usr/bin/mysql_zap usr/bin/mysqlbinlog usr/bin/mysqld_multi usr/bin/mysqld_safe +usr/bin/mysqld_safe_helper usr/bin/mysqlhotcopy usr/bin/perror usr/bin/replace diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 10f88885068..bbd99e92ced 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -215,7 +215,6 @@ parse_arguments() { for arg do val=`echo "$arg" | sed -e "s;--[^=]*=;;"` case "$arg" in - --crash[-_]script=*) CRASH_SCRIPT="$val" ;; # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*|--data=*) DATADIR="$val" ;; @@ -241,7 +240,7 @@ parse_arguments() { --socket=*) mysql_unix_port="$val" ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! - --core[-_]file-size=*) core_file_size="$val" ;; + --core[-_]file[-_]size=*) core_file_size="$val" ;; --ledir=*) check_executable_location "$arg" ; ledir="$val" ;; --malloc[-_]lib=*) check_executable_location "$arg"; set_malloc_lib "$val" ;; --crash[-_]script=*) check_executable_location "$arg"; crash_script="$val" ;; diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index e6ddf45faba..e4b20441749 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -44,7 +44,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 33 +#define INNODB_VERSION_BUGFIX 35 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; From 4799af092574e7957d7143c7751acef74a95a495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 10 Jan 2017 14:20:43 +0200 Subject: [PATCH 079/124] Fix unit test after merge from mysql 5.5.35 perfschema The problem in MariaDB is introduced by this merge commit: c33db2cdc0ab70a874060d58710895f6dac3dea3 The merge comes from mysql and the original author comes from this commit from MySQL: ------------------------------------------------ commit 160b823d146288d66638e4a740d6d2da72f9a689 Author: Marc Alff Date: Tue Aug 30 12:14:07 2016 +0200 Bug#22551677 SIGNAL 11 IN LF_PINBOX_PUT_PINS Backport to 5.6 ------------------------------------------------ The breaking change is in start_socket_wait_v1 where instead of using m_thread_owner, we make use of my_pthread_getspecific_ptr to fetch a thread local storage value. Unfortunately this invalidates the "m_thread_owner" member when a socket is created. The internals of the socket structure have m_thread_owner set to NULL, but when checking for ownership we actually look at the current thread's key store. This seems incorrect however it is not immediately apparent why. To not diverge from MySQL's reasoning as it is not described what the actual problem was that this commit is trying to fix, I have adjusted the unittest to account for this new behaviour. We destroy the current thread in the unit test, such that the newly created socket actually has no thread owner. The m_thread_owner is untouched in all this. --- storage/perfschema/unittest/pfs-t.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc index 6121fac098f..f76b1aa2e75 100644 --- a/storage/perfschema/unittest/pfs-t.cc +++ b/storage/perfschema/unittest/pfs-t.cc @@ -1316,6 +1316,7 @@ void test_locker_disabled() /* Pretend the socket does not have a thread owner */ /* ---------------------------------------------- */ + psi->delete_current_thread(); socket_class_A->m_enabled= true; socket_A1= psi->init_socket(socket_key_A, NULL, NULL, 0); ok(socket_A1 != NULL, "instrumented"); From 6ad3dd6054b34afea1f1f13dfd925dc7e73f3b16 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Jan 2017 14:19:11 +0100 Subject: [PATCH 080/124] mysqld_safe: don't close stdout if set -x --- scripts/mysqld_safe.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 059263fad51..a93a18c729c 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -864,8 +864,13 @@ max_fast_restarts=5 have_sleep=1 # close stdout and stderr, everything goes to $logging now -exec 1>&- -exec 2>&- +if expr "${-}" : '.*x' > /dev/null +then + : +else + exec 1>&- + exec 2>&- +fi while true do From 9a4bc0d098a9fba03e88b80db0f921b5ee597123 Mon Sep 17 00:00:00 2001 From: iangilfillan Date: Tue, 3 Jan 2017 16:38:56 +0200 Subject: [PATCH 081/124] Update mysql_secure_installation man page --- man/mysql_secure_installation.1 | 72 +++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/man/mysql_secure_installation.1 b/man/mysql_secure_installation.1 index 20a77bc3f1e..2a04e5d0b98 100644 --- a/man/mysql_secure_installation.1 +++ b/man/mysql_secure_installation.1 @@ -1,6 +1,6 @@ '\" t .\" -.TH "\FBMYSQL_SECURE_INST" "1" "04/08/2015" "MariaDB 10\&.0" "MariaDB Database System" +.TH "\FBMYSQL_SECURE_INST" "1" "3 January 2017" "MariaDB 10\&.0" "MariaDB Database System" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- @@ -71,9 +71,8 @@ test database, which by default can be accessed by anonymous users\&. .RE .PP -Invoke \fBmysql_secure_installation\fR -without arguments: +can be invoked without arguments: .sp .if n \{\ .RS 4 @@ -86,10 +85,75 @@ shell> \fBmysql_secure_installation\fR .\} .PP The script will prompt you to determine which actions to perform\&. +.PP +\fBmysql_secure_installation\fR +accepts some options: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +.\" mysql_secure_installation: basedir option +.\" basedir option: mysql_secure_installation +\fB\-\-basedir=\fR\fB\fIdir_name\fR\fR +.sp +Base directory\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +.\" mysql_secure_installation: defaults-extra-file option +.\" defaults-extra-file option: mysql_secure_installation +\fB\-\-defaults\-extra\-file=\fR\fB\fIfile_name\fR\fR +.sp +Additional option file\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +.\" mysql_secure_installation: defaults-file option +.\" defaults-file option: mysql_secure_installation +\fB\-\-defaults\-file=\fR\fB\fIfile_name\fR\fR +.sp +Option file\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +.\" mysql_secure_installation: no-defaults option +.\" no-defaults option: mysql_secure_installation +\fB\-\-no\-defaults\fR +.sp +Don't read any defaults file\&. +.RE +.sp +Other unrecognized options will be passed on to the server\&. .SH "COPYRIGHT" .br .PP -Copyright 2007-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc., 2010-2015 MariaDB Foundation +Copyright 2007-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc., 2010-2017 MariaDB Foundation .PP This documentation is free software; you can redistribute it and/or modify it only under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. .PP From c1a23cd4e5f96c51064f9569bfa4f87d76d53fb6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Jan 2017 18:31:03 +0100 Subject: [PATCH 082/124] MDEV-11676 Starting service with mysqld_safe_helper fails in SELINUX "enforcing" mode compile, and install selinux policy for mysqld_safe_helper on centos6. the policy was created as described in https://mariadb.com/kb/en/mariadb/what-to-do-if-mariadb-doesnt-start/#other-selinux-changes --- .gitignore | 1 + support-files/CMakeLists.txt | 2 +- support-files/SELinux/CMakeLists.txt | 35 +++++++++++++++++++ support-files/SELinux/centos6-mariadb.te | 9 +++++ .../mysql.fc => SELinux/rhel4-mysql.fc} | 0 .../mysql.te => SELinux/rhel4-mysql.te} | 0 support-files/rpm/server-postin.sh | 7 +++- 7 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 support-files/SELinux/CMakeLists.txt create mode 100644 support-files/SELinux/centos6-mariadb.te rename support-files/{RHEL4-SElinux/mysql.fc => SELinux/rhel4-mysql.fc} (100%) rename support-files/{RHEL4-SElinux/mysql.te => SELinux/rhel4-mysql.te} (100%) diff --git a/.gitignore b/.gitignore index 8b6e416ec45..4d96bfe65a3 100644 --- a/.gitignore +++ b/.gitignore @@ -221,6 +221,7 @@ support-files/mysql.spec support-files/mysqld_multi.server support-files/wsrep.cnf support-files/wsrep_notify +support-files/SELinux/centos6-mariadb.pp tags tests/async_queries tests/bug25714 diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 4677bd59415..67a7b508e33 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -67,7 +67,7 @@ IF(UNIX) ENDFOREACH() IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) - INSTALL(DIRECTORY RHEL4-SElinux/ DESTINATION ${inst_location}/SELinux/RHEL4 COMPONENT SupportFiles) + ADD_SUBDIRECTORY(SELinux) ENDIF() INSTALL(FILES mysql.m4 DESTINATION ${INSTALL_SHAREDIR}/aclocal COMPONENT Development) diff --git a/support-files/SELinux/CMakeLists.txt b/support-files/SELinux/CMakeLists.txt new file mode 100644 index 00000000000..e3cdb26ca8f --- /dev/null +++ b/support-files/SELinux/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2017, MariaDB +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +FIND_PROGRAM(CHECKMODULE checkmodule) +FIND_PROGRAM(SEMODULE_PACKAGE semodule_package) +MARK_AS_ADVANCED(CHECKMODULE SEMODULE_PACKAGE) + +SET(params DESTINATION ${INSTALL_SUPPORTFILESDIR}/SELinux COMPONENT SupportFiles) + +IF(CHECKMODULE AND SEMODULE_PACKAGE) + FOREACH(pol centos6-mariadb) + SET(src ${CMAKE_CURRENT_SOURCE_DIR}/${pol}.te) + SET(mod ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) + SET(out ${CMAKE_CURRENT_BINARY_DIR}/${pol}.pp) + ADD_CUSTOM_COMMAND(OUTPUT ${out} + COMMAND ${CHECKMODULE} -M -m ${src} -o ${mod} + COMMAND ${SEMODULE_PACKAGE} -m ${mod} -o ${out} + DEPENDS ${src}) + ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) + INSTALL(FILES ${out} ${params}) + ENDFOREACH() +ENDIF() +INSTALL(FILES centos6-mariadb.te rhel4-mysql.fc rhel4-mysql.te ${params}) diff --git a/support-files/SELinux/centos6-mariadb.te b/support-files/SELinux/centos6-mariadb.te new file mode 100644 index 00000000000..1d3de52c700 --- /dev/null +++ b/support-files/SELinux/centos6-mariadb.te @@ -0,0 +1,9 @@ +module mariadb 1.0; + +require { + type mysqld_safe_t; + class capability { setuid setgid }; +} + +#============= mysqld_safe_t ============== +allow mysqld_safe_t self:capability { setuid setgid }; diff --git a/support-files/RHEL4-SElinux/mysql.fc b/support-files/SELinux/rhel4-mysql.fc similarity index 100% rename from support-files/RHEL4-SElinux/mysql.fc rename to support-files/SELinux/rhel4-mysql.fc diff --git a/support-files/RHEL4-SElinux/mysql.te b/support-files/SELinux/rhel4-mysql.te similarity index 100% rename from support-files/RHEL4-SElinux/mysql.te rename to support-files/SELinux/rhel4-mysql.te diff --git a/support-files/rpm/server-postin.sh b/support-files/rpm/server-postin.sh index cd2aec4d84a..377a752824d 100644 --- a/support-files/rpm/server-postin.sh +++ b/support-files/rpm/server-postin.sh @@ -79,7 +79,12 @@ if [ -f /etc/redhat-release ] ; then echo ' make load' echo echo - fi + fi + if grep 'CentOS release 6' /etc/redhat-release >/dev/null 2>&1; then + if [ -x /usr/sbin/semodule ] ; then + /usr/sbin/semodule -i /usr/share/mysql/SELinux/centos6-mariadb.pp + fi + fi fi if [ -x sbin/restorecon ] ; then From ab93a4d4df7206833fa4a8eb0aa47b8ba185da60 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Wed, 11 Jan 2017 09:05:36 -0500 Subject: [PATCH 083/124] MDEV-11685: sql_mode can't be set with non-ascii connection charset The supplied sql_mode(s) should be converted to ASCII first, before comparing it with the sql_mode set. --- mysql-test/r/ctype_ucs.result | 10 ++++++++++ mysql-test/r/ctype_utf16.result | 10 ++++++++++ mysql-test/r/ctype_utf32.result | 10 ++++++++++ mysql-test/t/ctype_ucs.test | 8 ++++++++ mysql-test/t/ctype_utf16.test | 9 +++++++++ mysql-test/t/ctype_utf32.test | 9 +++++++++ sql/sys_vars.h | 2 +- 7 files changed, 57 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index c38a03f76a8..7a93c5524ef 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -4357,5 +4357,15 @@ SELECT CHAR_LENGTH(TRIM(BOTH 0x00 FROM _ucs2 0x0061)); CHAR_LENGTH(TRIM(BOTH 0x00 FROM _ucs2 0x0061)) 1 # +# MDEV-11685: sql_mode can't be set with non-ascii connection charset +# +SET character_set_connection=ucs2; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +@@sql_mode +NO_ENGINE_SUBSTITUTION +SET sql_mode=DEFAULT; +SET NAMES utf8; +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index bfb2d6a498c..0846811e2e6 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -1207,5 +1207,15 @@ DO LPAD(_utf16 0x0061 COLLATE utf16_unicode_ci, 10000, 0x0061DE989999); Warnings: Warning 1300 Invalid utf16 character string: 'DE9899' # +# MDEV-11685: sql_mode can't be set with non-ascii connection charset +# +SET character_set_connection=utf16; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +@@sql_mode +NO_ENGINE_SUBSTITUTION +SET sql_mode=DEFAULT; +SET NAMES utf8; +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index ae55f2c101e..9b062f9480f 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -1273,5 +1273,15 @@ select hex(lower(cast(0xffff0000 as char character set utf32))) as c; c FFFF0000 # +# MDEV-11685: sql_mode can't be set with non-ascii connection charset +# +SET character_set_connection=utf32; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +@@sql_mode +NO_ENGINE_SUBSTITUTION +SET sql_mode=DEFAULT; +SET NAMES utf8; +# # End of 5.5 tests # diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 7fd3768aa5f..d94c9ae62ac 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -853,6 +853,14 @@ SELECT CHAR_LENGTH(TRIM(BOTH 0x0001 FROM _ucs2 0x0061)); SELECT CHAR_LENGTH(TRIM(BOTH 0x61 FROM _ucs2 0x0061)); SELECT CHAR_LENGTH(TRIM(BOTH 0x00 FROM _ucs2 0x0061)); +--echo # +--echo # MDEV-11685: sql_mode can't be set with non-ascii connection charset +--echo # +SET character_set_connection=ucs2; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +SET sql_mode=DEFAULT; +SET NAMES utf8; --echo # --echo # End of 5.5 tests diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test index 3f9e5eece21..ab87c7da0d8 100644 --- a/mysql-test/t/ctype_utf16.test +++ b/mysql-test/t/ctype_utf16.test @@ -792,6 +792,15 @@ SELECT 'a' AS id, REPEAT('bla bla', 100) AS body) t1; DO RPAD(_utf16 0x0061 COLLATE utf16_unicode_ci, 10000, 0x0061DE989999); DO LPAD(_utf16 0x0061 COLLATE utf16_unicode_ci, 10000, 0x0061DE989999); +--echo # +--echo # MDEV-11685: sql_mode can't be set with non-ascii connection charset +--echo # +SET character_set_connection=utf16; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +SET sql_mode=DEFAULT; +SET NAMES utf8; + --echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index 8cbb8e2e55e..2b3d3b3bdc5 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -881,6 +881,15 @@ SELECT CHAR_LENGTH(TRIM(BOTH 0x00 FROM _utf32 0x00000061)); # select hex(lower(cast(0xffff0000 as char character set utf32))) as c; +--echo # +--echo # MDEV-11685: sql_mode can't be set with non-ascii connection charset +--echo # +SET character_set_connection=utf32; +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +SELECT @@sql_mode; +SET sql_mode=DEFAULT; +SET NAMES utf8; + --echo # --echo # End of 5.5 tests --echo # diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 3cbd24f1c89..dbe27ab107e 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -1141,7 +1141,7 @@ public: if (var->value->result_type() == STRING_RESULT) { - if (!(res=var->value->val_str(&str))) + if (!(res=var->value->val_str_ascii(&str))) return true; else { From 0d1d0d77f2a72d9cb6de0489dceb37644caf9037 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 11 Jan 2017 19:12:21 +0100 Subject: [PATCH 084/124] MDEV-11706 Assertion `is_stat_field || !table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || (table->vcol_set && bitmap_is_set(table->vcol_set, field_index)))' failed in Field_time::store_TIME_with_warning vcols and triggers. Revert 094f4cf77890c5a747a57cf2bed149b0b6933507, backport the correct fix (Table_triggers_list::mark_fields_used() not marking vcols) from 10.2. --- mysql-test/suite/vcol/inc/vcol_trigger_sp.inc | 9 ++++++++- .../suite/vcol/r/vcol_trigger_sp_innodb.result | 8 +++++++- .../suite/vcol/r/vcol_trigger_sp_myisam.result | 8 +++++++- sql/sql_base.cc | 16 ++++------------ sql/sql_delete.cc | 5 +---- sql/sql_trigger.cc | 3 +++ sql/sql_update.cc | 13 +++---------- sql/table.cc | 13 +++++-------- sql/table.h | 3 +-- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc index eb7e6ad32b9..b9a6ba28a5f 100644 --- a/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc +++ b/mysql-test/suite/vcol/inc/vcol_trigger_sp.inc @@ -110,7 +110,7 @@ drop table t1,t2; drop procedure p1; --echo # ---echo # Bug mdev-3845: values of virtual columns are not computed for triggers +--echo # MDEV-3845 values of virtual columns are not computed for triggers --echo # CREATE TABLE t1 ( @@ -149,3 +149,10 @@ DROP TRIGGER t1_ins_aft; DROP TRIGGER t1_del_bef; DROP TABLE t1,t2; +# +# MDEV-11706 Assertion `is_stat_field || !table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || (table->vcol_set && bitmap_is_set(table->vcol_set, field_index)))' failed in Field_time::store_TIME_with_warning +# +create table t1 (i int, t time not null, vt time(4) as (t) virtual); +create trigger trg before update on t1 for each row set @a = 1; +insert ignore into t1 (i) values (1); +drop table t1; diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result index 1d78bbf50e4..034a67a9bb0 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_innodb.result @@ -86,7 +86,7 @@ a b c drop table t1,t2; drop procedure p1; # -# Bug mdev-3845: values of virtual columns are not computed for triggers +# MDEV-3845 values of virtual columns are not computed for triggers # CREATE TABLE t1 ( a INTEGER UNSIGNED NULL DEFAULT NULL, @@ -125,3 +125,9 @@ c DROP TRIGGER t1_ins_aft; DROP TRIGGER t1_del_bef; DROP TABLE t1,t2; +create table t1 (i int, t time not null, vt time(4) as (t) virtual); +create trigger trg before update on t1 for each row set @a = 1; +insert ignore into t1 (i) values (1); +Warnings: +Warning 1364 Field 't' doesn't have a default value +drop table t1; diff --git a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result index 77efa8fe6b9..07d011ac64c 100644 --- a/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_trigger_sp_myisam.result @@ -86,7 +86,7 @@ a b c drop table t1,t2; drop procedure p1; # -# Bug mdev-3845: values of virtual columns are not computed for triggers +# MDEV-3845 values of virtual columns are not computed for triggers # CREATE TABLE t1 ( a INTEGER UNSIGNED NULL DEFAULT NULL, @@ -125,3 +125,9 @@ c DROP TRIGGER t1_ins_aft; DROP TRIGGER t1_del_bef; DROP TABLE t1,t2; +create table t1 (i int, t time not null, vt time(4) as (t) virtual); +create trigger trg before update on t1 for each row set @a = 1; +insert ignore into t1 (i) values (1); +Warnings: +Warning 1364 Field 't' doesn't have a default value +drop table t1; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d281758fc18..7f84f35c825 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9033,9 +9033,7 @@ fill_record(THD * thd, List &fields, List &values, /* Update virtual fields*/ thd->abort_on_warning= FALSE; if (vcol_table && vcol_table->vfield && - update_virtual_fields(thd, vcol_table, - vcol_table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE)) + update_virtual_fields(thd, vcol_table, VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= save_abort_on_warning; thd->no_errors= save_no_errors; @@ -9099,9 +9097,7 @@ fill_record_n_invoke_before_triggers(THD *thd, List &fields, if (item_field && item_field->field && (table= item_field->field->table) && table->vfield) - result= update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE); + result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE); } } return result; @@ -9186,9 +9182,7 @@ fill_record(THD *thd, Field **ptr, List &values, bool ignore_errors, /* Update virtual fields*/ thd->abort_on_warning= FALSE; if (table->vfield && - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE)) + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE)) goto err; thd->abort_on_warning= abort_on_warning_saved; DBUG_RETURN(thd->is_error()); @@ -9241,9 +9235,7 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr, { TABLE *table= (*ptr)->table; if (table->vfield) - result= update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE); + result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE); } return result; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5b233cde7c7..8aca415a9d0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -328,9 +328,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ! thd->is_error()) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; // thd->is_error() is tested to disallow delete row on error if (!select || select->skip_record(thd) > 0) @@ -1073,4 +1071,3 @@ bool multi_delete::send_eof() } return 0; } - diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index b6915b708fa..4d7338b2e1d 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -2246,6 +2246,9 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); if (trg_field->get_settable_routine_parameter()) bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); + if (trigger_table->field[trg_field->field_idx]->vcol_info) + trigger_table->mark_virtual_col(trigger_table-> + field[trg_field->field_idx]); } } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f134e0ba266..060952a589d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -569,9 +569,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || (error= select->skip_record(thd)) > 0) { @@ -695,9 +693,7 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { if (table->vfield) - update_virtual_fields(thd, table, - table->triggers ? VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_READ); + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->examined_row_count++; if (!select || select->skip_record(thd) > 0) { @@ -2235,10 +2231,7 @@ int multi_update::do_updates() { int error; if (table->vfield && - update_virtual_fields(thd, table, - (table->triggers ? - VCOL_UPDATE_ALL : - VCOL_UPDATE_FOR_WRITE))) + update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE)) goto err2; if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) diff --git a/sql/table.cc b/sql/table.cc index db18214165e..1330560b6b6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6557,11 +6557,9 @@ bool is_simple_order(ORDER *order) @details The function computes the values of the virtual columns of the table and stores them in the table record buffer. - If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are - computed. Otherwise, only fields from vcol_set are computed: all of them, - if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with - the stored_in_db flag set to false, if vcol_update_mode is equal to - VCOL_UPDATE_FOR_READ. + Only fields from vcol_set are computed: all of them, if vcol_update_mode is + set to VCOL_UPDATE_FOR_WRITE, and, only those with the stored_in_db flag + set to false, if vcol_update_mode is equal to VCOL_UPDATE_FOR_READ. @retval 0 Success @@ -6583,9 +6581,8 @@ int update_virtual_fields(THD *thd, TABLE *table, { vfield= (*vfield_ptr); DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item); - if ((bitmap_is_set(table->vcol_set, vfield->field_index) && - (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) || - vcol_update_mode == VCOL_UPDATE_ALL) + if (bitmap_is_set(table->vcol_set, vfield->field_index) && + (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) { /* Compute the actual value of the virtual fields */ error= vfield->vcol_info->expr_item->save_in_field(vfield, 0); diff --git a/sql/table.h b/sql/table.h index 17fdd4aba15..dde01a85d77 100644 --- a/sql/table.h +++ b/sql/table.h @@ -302,8 +302,7 @@ enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; enum enum_vcol_update_mode { VCOL_UPDATE_FOR_READ= 0, - VCOL_UPDATE_FOR_WRITE, - VCOL_UPDATE_ALL + VCOL_UPDATE_FOR_WRITE }; typedef struct st_filesort_info From 20ca1bcf4bd81ed43683676276b5f27dc8da8e91 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 12 Jan 2017 13:54:21 +0100 Subject: [PATCH 085/124] MDEV-11527 Virtual columns do not get along well with NO_ZERO_DATE don't check defaults for vcols --- mysql-test/suite/vcol/r/vcol_misc.result | 7 +++++++ mysql-test/suite/vcol/t/vcol_misc.test | 11 +++++++++++ sql/sql_table.cc | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index 0aaed59ed6c..699b6d4efe3 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -330,3 +330,10 @@ t1 CREATE TABLE `t1` ( `c1` varchar(50) COLLATE latin1_general_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci drop table t1; +set sql_mode='no_zero_date'; +create table t1 ( +ts timestamp not null default current_timestamp, +tsv timestamp as (adddate(ts, interval 1 day)) virtual +); +drop table t1; +set sql_mode=default; diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 12f46e9b002..80a36d9c623 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -290,3 +290,14 @@ create table t1 (a int, b int as (b is null) virtual); create table t1 (v1 varchar(255) as (c1) persistent, c1 varchar(50)) collate=latin1_general_ci; show create table t1; drop table t1; + +# +# MDEV-11527 Virtual columns do not get along well with NO_ZERO_DATE +# +set sql_mode='no_zero_date'; +create table t1 ( + ts timestamp not null default current_timestamp, + tsv timestamp as (adddate(ts, interval 1 day)) virtual +); +drop table t1; +set sql_mode=default; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2cec480d23b..43e146f1f1d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3826,7 +3826,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check); if (thd->variables.sql_mode & MODE_NO_ZERO_DATE && - !sql_field->def && + !sql_field->def && !sql_field->vcol_info && sql_field->sql_type == MYSQL_TYPE_TIMESTAMP && (sql_field->flags & NOT_NULL_FLAG) && (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD)) From 939d1255a78e374f468154f3353e5faa0fa517ca Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Fri, 13 Jan 2017 10:15:28 -0500 Subject: [PATCH 086/124] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 36834bdb92d..5f666b9a57d 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=0 -MYSQL_VERSION_PATCH=29 +MYSQL_VERSION_PATCH=30 From 5fc1ba604e27b7d9eaa2977ef5b0c180f6f62565 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Fri, 13 Jan 2017 13:57:17 -0500 Subject: [PATCH 087/124] Fix for post-merge build failure. --- storage/xtradb/handler/ha_innodb.cc | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index ea6a08fc156..ea94f90cbf8 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -7340,16 +7340,7 @@ wsrep_store_key_val_for_row( blob_data = row_mysql_read_blob_ref(&blob_len, (byte*) (record + (ulint) get_field_offset(table, field)), - (ulint) field->pack_length(), -#ifdef HAVE_PERCONA_COMPRESSED_COLUMNS - field->column_format() == - COLUMN_FORMAT_TYPE_COMPRESSED, - reinterpret_cast( - field->zip_dict_data.str), - field->zip_dict_data.length, prebuilt); -#else - 0, 0, 0, prebuilt); -#endif + (ulint) field->pack_length()); true_len = blob_len; @@ -9103,9 +9094,7 @@ wsrep_calc_row_hash( switch (col_type) { case DATA_BLOB: - ptr = row_mysql_read_blob_ref(&len, ptr, len, - false, 0, 0, prebuilt); - + ptr = row_mysql_read_blob_ref(&len, ptr, len); break; case DATA_VARCHAR: From 67e2028161d1f653a852f1a4679ff5e523296218 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 14:56:01 +0100 Subject: [PATCH 088/124] MDEV-9690 concurrent queries with virtual columns crash in temporal code Item_func_le included Arg_comparator. Arg_comparator remembered the current_thd during fix_fields and used that value during execution to allocate Item_cache in get_datetime_value(). But for vcols fix_fields and val_int can happen in different threads. Same bug for Item_func_in using in_datetime or cmp_item_datetime, both also remembered current_thd at fix_fields() to use it later for get_datetime_value(). As a fix, these objects no longer remember the current_thd, and get_datetime_value() uses current_thd at run time. This should not increase the number of current_thd calls much, as Item_cache is created only once anyway. --- mysql-test/suite/vcol/r/wrong_arena.result | 39 ++++++++++++++++++++++ mysql-test/suite/vcol/t/wrong_arena.test | 22 ++++++++++++ sql/item_cmpfunc.cc | 22 ++++++------ sql/item_cmpfunc.h | 12 +++---- 4 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 mysql-test/suite/vcol/r/wrong_arena.result create mode 100644 mysql-test/suite/vcol/t/wrong_arena.test diff --git a/mysql-test/suite/vcol/r/wrong_arena.result b/mysql-test/suite/vcol/r/wrong_arena.result new file mode 100644 index 00000000000..d542c82458e --- /dev/null +++ b/mysql-test/suite/vcol/r/wrong_arena.result @@ -0,0 +1,39 @@ +create table t1 (a datetime, +# get_datetime_value +b int as (a > 1), # Arg_comparator +c int as (a in (1,2,3)), # in_datetime +d int as ((a,a) in ((1,1),(2,1),(NULL,1))) # cmp_item_datetime +); +Warnings: +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' +Warning 1292 Incorrect datetime value: '3' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` datetime DEFAULT NULL, + `b` int(11) AS (a > 1) VIRTUAL, + `c` int(11) AS (a in (1,2,3)) VIRTUAL, + `d` int(11) AS ((a,a) in ((1,1),(2,1),(NULL,1))) VIRTUAL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +Warnings: +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' +Warning 1292 Incorrect datetime value: '3' +insert t1 (a) values ('2010-10-10 10:10:10'); +select * from t1; +a b c d +2010-10-10 10:10:10 1 0 0 +Warnings: +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' +Warning 1292 Incorrect datetime value: '1' +select * from t1; +a b c d +2010-10-10 10:10:10 1 0 0 +Warnings: +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' +Warning 1292 Incorrect datetime value: '1' +drop table t1; diff --git a/mysql-test/suite/vcol/t/wrong_arena.test b/mysql-test/suite/vcol/t/wrong_arena.test new file mode 100644 index 00000000000..8bf06bdb9bd --- /dev/null +++ b/mysql-test/suite/vcol/t/wrong_arena.test @@ -0,0 +1,22 @@ +# +# This tests various issues when vcol items allocate memory (e.g. more items) +# not in the TABLE::expr_arena. +# + +# +# MDEV-9690 concurrent queries with virtual columns crash in temporal code +# +create table t1 (a datetime, + # get_datetime_value + b int as (a > 1), # Arg_comparator + c int as (a in (1,2,3)), # in_datetime + d int as ((a,a) in ((1,1),(2,1),(NULL,1))) # cmp_item_datetime +); +show create table t1; +connect con1, localhost, root; +insert t1 (a) values ('2010-10-10 10:10:10'); +select * from t1; +disconnect con1; +connection default; +select * from t1; +drop table t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3bd0b5b3fa2..46566206094 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -777,7 +777,7 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, Item **a1, Item **a2, Item_result type) { - thd= current_thd; + THD *thd= current_thd; owner= owner_arg; set_null= set_null && owner_arg; a= a1; @@ -846,7 +846,6 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value, void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg, Item **a1, Item **b1) { - thd= current_thd; owner= owner_arg; a= a1; b= b1; @@ -919,6 +918,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (cache_arg && item->const_item() && !(item->type() == Item::CACHE_ITEM && item->cmp_type() == TIME_RESULT)) { + if (!thd) + thd= current_thd; + Query_arena backup; Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_temporal *cache= new Item_cache_temporal(f_type); @@ -959,12 +961,12 @@ int Arg_comparator::compare_datetime() owner->null_value= 1; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null); + a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null); if (a_is_null) return -1; /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null); + b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null); if (b_is_null) return -1; @@ -982,10 +984,10 @@ int Arg_comparator::compare_e_datetime() longlong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null); + a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null); /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null); + b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null); return a_is_null || b_is_null ? a_is_null == b_is_null : a_value == b_value; } @@ -3600,7 +3602,7 @@ void in_datetime::set(uint pos,Item *item) bool is_null; struct packed_longlong *buff= &((packed_longlong*) base)[pos]; - buff->val= get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null); + buff->val= get_datetime_value(0, &tmp_item, 0, warn_item, &is_null); buff->unsigned_flag= 1L; } @@ -3608,7 +3610,7 @@ uchar *in_datetime::get_value(Item *item) { bool is_null; Item **tmp_item= lval_cache ? &lval_cache : &item; - tmp.val= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null); + tmp.val= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null); if (item->null_value) return 0; tmp.unsigned_flag= 1L; @@ -3852,7 +3854,7 @@ void cmp_item_datetime::store_value(Item *item) { bool is_null; Item **tmp_item= lval_cache ? &lval_cache : &item; - value= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null); + value= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null); } @@ -3861,7 +3863,7 @@ int cmp_item_datetime::cmp(Item *arg) bool is_null; Item **tmp_item= &arg; return value != - get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null); + get_datetime_value(0, &tmp_item, 0, warn_item, &is_null); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 0194f9cd0e0..a8befa47b95 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -44,7 +44,6 @@ class Arg_comparator: public Sql_alloc Arg_comparator *comparators; // used only for compare_row() double precision; /* Fields used in DATE/DATETIME comparison. */ - THD *thd; Item *a_cache, *b_cache; // Cached values of a and b items // when one of arguments is NULL. public: @@ -52,10 +51,10 @@ public: /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): set_null(TRUE), comparators(0), thd(0), + Arg_comparator(): set_null(TRUE), comparators(0), a_cache(0), b_cache(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE), - comparators(0), thd(0), a_cache(0), b_cache(0) {}; + comparators(0), a_cache(0), b_cache(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); inline int set_compare_func(Item_result_field *owner_arg) @@ -944,15 +943,13 @@ public: class in_datetime :public in_longlong { public: - THD *thd; /* An item used to issue warnings. */ Item *warn_item; /* Cache for the left item. */ Item *lval_cache; in_datetime(Item *warn_item_arg, uint elements) - :in_longlong(elements), thd(current_thd), warn_item(warn_item_arg), - lval_cache(0) {}; + :in_longlong(elements), warn_item(warn_item_arg), lval_cache(0) {}; void set(uint pos,Item *item); uchar *get_value(Item *item); Item* create_item() @@ -1112,14 +1109,13 @@ class cmp_item_datetime :public cmp_item { longlong value; public: - THD *thd; /* Item used for issuing warnings. */ Item *warn_item; /* Cache for the left item. */ Item *lval_cache; cmp_item_datetime(Item *warn_item_arg) - :thd(current_thd), warn_item(warn_item_arg), lval_cache(0) {} + : warn_item(warn_item_arg), lval_cache(0) {} void store_value(Item *item); int cmp(Item *arg); int compare(cmp_item *ci); From 798fcb541698cbf51f1ee33f44b023c11dc2b784 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 20:55:33 +0100 Subject: [PATCH 089/124] bugfix: cmp_item_row::alloc_comparators() allocated on the wrong arena it used current_thd->alloc() and allocated on the thd's execution arena, not on table->expr_arena. Remove THD::arena_for_cached_items that is temporarily set in update_virtual_fields(), and replaces THD arena in get_datetime_value(). Instead set THD arena to table->expr_arena for the whole duration of update_virtual_fields() --- mysql-test/suite/vcol/r/wrong_arena.result | 19 +++++++++++++------ mysql-test/suite/vcol/t/wrong_arena.test | 4 +++- sql/item_cmpfunc.cc | 5 ----- sql/sql_class.cc | 1 - sql/sql_class.h | 19 ------------------- sql/table.cc | 6 ++++-- 6 files changed, 20 insertions(+), 34 deletions(-) diff --git a/mysql-test/suite/vcol/r/wrong_arena.result b/mysql-test/suite/vcol/r/wrong_arena.result index d542c82458e..af41ea89ab5 100644 --- a/mysql-test/suite/vcol/r/wrong_arena.result +++ b/mysql-test/suite/vcol/r/wrong_arena.result @@ -2,7 +2,9 @@ create table t1 (a datetime, # get_datetime_value b int as (a > 1), # Arg_comparator c int as (a in (1,2,3)), # in_datetime -d int as ((a,a) in ((1,1),(2,1),(NULL,1))) # cmp_item_datetime +d int as ((a,a) in ((1,1),(2,1),(NULL,1))), # cmp_item_datetime +# other issues +e int as ((a,1) in ((1,1),(2,1),(NULL,1))) # cmp_item_row::alloc_comparators() ); Warnings: Warning 1292 Incorrect datetime value: '1' @@ -14,7 +16,8 @@ t1 CREATE TABLE `t1` ( `a` datetime DEFAULT NULL, `b` int(11) AS (a > 1) VIRTUAL, `c` int(11) AS (a in (1,2,3)) VIRTUAL, - `d` int(11) AS ((a,a) in ((1,1),(2,1),(NULL,1))) VIRTUAL + `d` int(11) AS ((a,a) in ((1,1),(2,1),(NULL,1))) VIRTUAL, + `e` int(11) AS ((a,1) in ((1,1),(2,1),(NULL,1))) VIRTUAL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 Warnings: Warning 1292 Incorrect datetime value: '1' @@ -22,18 +25,22 @@ Warning 1292 Incorrect datetime value: '2' Warning 1292 Incorrect datetime value: '3' insert t1 (a) values ('2010-10-10 10:10:10'); select * from t1; -a b c d -2010-10-10 10:10:10 1 0 0 +a b c d e +2010-10-10 10:10:10 1 0 0 NULL Warnings: Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '2' Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' select * from t1; -a b c d -2010-10-10 10:10:10 1 0 0 +a b c d e +2010-10-10 10:10:10 1 0 0 NULL Warnings: Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '2' Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '1' +Warning 1292 Incorrect datetime value: '2' drop table t1; diff --git a/mysql-test/suite/vcol/t/wrong_arena.test b/mysql-test/suite/vcol/t/wrong_arena.test index 8bf06bdb9bd..4276437f446 100644 --- a/mysql-test/suite/vcol/t/wrong_arena.test +++ b/mysql-test/suite/vcol/t/wrong_arena.test @@ -10,7 +10,9 @@ create table t1 (a datetime, # get_datetime_value b int as (a > 1), # Arg_comparator c int as (a in (1,2,3)), # in_datetime - d int as ((a,a) in ((1,1),(2,1),(NULL,1))) # cmp_item_datetime + d int as ((a,a) in ((1,1),(2,1),(NULL,1))), # cmp_item_datetime + # other issues + e int as ((a,1) in ((1,1),(2,1),(NULL,1))) # cmp_item_row::alloc_comparators() ); show create table t1; connect con1, localhost, root; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 46566206094..ebe088e5092 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -921,12 +921,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, if (!thd) thd= current_thd; - Query_arena backup; - Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup); Item_cache_temporal *cache= new Item_cache_temporal(f_type); - if (save_arena) - thd->set_query_arena(save_arena); - cache->store_packed(value, item); *cache_arg= cache; *item_arg= cache_arg; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 62339b2690a..93af4d3bb4d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -957,7 +957,6 @@ THD::THD() m_internal_handler= NULL; m_binlog_invoker= FALSE; - arena_for_cached_items= 0; memset(&invoker_user, 0, sizeof(invoker_user)); memset(&invoker_host, 0, sizeof(invoker_host)); prepare_derived_at_open= FALSE; diff --git a/sql/sql_class.h b/sql/sql_class.h index 27bc40e3761..5dd7cd18a5d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3102,26 +3102,7 @@ public: } } -private: - /* - This reference points to the table arena when the expression - for a virtual column is being evaluated - */ - Query_arena *arena_for_cached_items; - public: - void reset_arena_for_cached_items(Query_arena *new_arena) - { - arena_for_cached_items= new_arena; - } - Query_arena *switch_to_arena_for_cached_items(Query_arena *backup) - { - if (!arena_for_cached_items) - return 0; - set_n_backup_active_arena(arena_for_cached_items, backup); - return backup; - } - void clear_wakeup_ready() { wakeup_ready= false; } /* Sleep waiting for others to wake us up with signal_wakeup_ready(). diff --git a/sql/table.cc b/sql/table.cc index 1330560b6b6..9d52d5f87a2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6575,7 +6575,9 @@ int update_virtual_fields(THD *thd, TABLE *table, int error __attribute__ ((unused))= 0; DBUG_ASSERT(table && table->vfield); - thd->reset_arena_for_cached_items(table->expr_arena); + Query_arena backup_arena; + thd->set_n_backup_active_arena(table->expr_arena, &backup_arena); + /* Iterate over virtual fields in the table */ for (vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++) { @@ -6593,7 +6595,7 @@ int update_virtual_fields(THD *thd, TABLE *table, DBUG_PRINT("info", ("field '%s' - skipped", vfield->field_name)); } } - thd->reset_arena_for_cached_items(0); + thd->restore_active_arena(table->expr_arena, &backup_arena); DBUG_RETURN(0); } From b948b5f7c64c6430d98dc31b7e9f71d990b40ec1 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 14 Jan 2017 21:23:00 +0100 Subject: [PATCH 090/124] bugfix: Item_func_min_max stored thd internally It was used for get_datetime_value() and for thd->is_error(). But in fact, get_datetime_value() never used thd argument, because the cache ptr argument was NULL. And thd->is_error() check was not needed at that place at all. --- mysql-test/suite/vcol/r/wrong_arena.result | 15 +++++++++++++++ mysql-test/suite/vcol/t/wrong_arena.test | 11 +++++++++++ sql/item_func.cc | 7 ++----- sql/item_func.h | 1 - 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/vcol/r/wrong_arena.result b/mysql-test/suite/vcol/r/wrong_arena.result index af41ea89ab5..172b59d6c4c 100644 --- a/mysql-test/suite/vcol/r/wrong_arena.result +++ b/mysql-test/suite/vcol/r/wrong_arena.result @@ -44,3 +44,18 @@ Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '1' Warning 1292 Incorrect datetime value: '2' drop table t1; +create table t1 (a datetime, +b datetime as (least(a,1)) # Item_func_min_max::get_date +); +insert t1 (a) values ('2010-10-10 10:10:10'); +select * from t1; +a b +2010-10-10 10:10:10 0000-00-00 00:00:00 +Warnings: +Warning 1292 Incorrect datetime value: '1' +select * from t1; +a b +2010-10-10 10:10:10 0000-00-00 00:00:00 +Warnings: +Warning 1292 Incorrect datetime value: '1' +drop table t1; diff --git a/mysql-test/suite/vcol/t/wrong_arena.test b/mysql-test/suite/vcol/t/wrong_arena.test index 4276437f446..484f1fe685d 100644 --- a/mysql-test/suite/vcol/t/wrong_arena.test +++ b/mysql-test/suite/vcol/t/wrong_arena.test @@ -22,3 +22,14 @@ disconnect con1; connection default; select * from t1; drop table t1; + +connect con1, localhost, root; +create table t1 (a datetime, + b datetime as (least(a,1)) # Item_func_min_max::get_date +); +insert t1 (a) values ('2010-10-10 10:10:10'); +select * from t1; +disconnect con1; +connection default; +select * from t1; +drop table t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index 89d3cd9e32a..cfccd66ea8a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2856,7 +2856,6 @@ void Item_func_min_max::fix_length_and_dec() decimals=0; max_length=0; maybe_null=0; - thd= current_thd; cmp_type=args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) @@ -2929,13 +2928,11 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { Item **arg= args + i; bool is_null; - longlong res= get_datetime_value(thd, &arg, 0, compare_as_dates, &is_null); + longlong res= get_datetime_value(0, &arg, 0, compare_as_dates, &is_null); /* Check if we need to stop (because of error or KILL) and stop the loop */ - if (thd->is_error() || args[i]->null_value) - { + if (args[i]->null_value) return (null_value= 1); - } if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) min_max= res; diff --git a/sql/item_func.h b/sql/item_func.h index 0da38e22c7f..d60801745fe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1068,7 +1068,6 @@ class Item_func_min_max :public Item_func int cmp_sign; /* An item used for issuing warnings while string to DATETIME conversion. */ Item *compare_as_dates; - THD *thd; protected: enum_field_types cached_field_type; public: From eddbae422bd3430f684d5cd287ca522467040c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 16 Jan 2017 12:49:22 +0200 Subject: [PATCH 091/124] MDEV-11712: ArmHF EXPLAIN JSON garbage longlong values printed Make sure printing with snprintf uses the correct typed parameters. --- sql/field.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/field.cc b/sql/field.cc index 58def13f5f3..ea56489543d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10600,7 +10600,7 @@ Create_field::Create_field(THD *thd, Field *old_field, Field *orig_field) if (length != 4) { char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; - my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length); + my_snprintf(buff, sizeof(buff), "YEAR(%llu)", length); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_WARN_DEPRECATED_SYNTAX, ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), From 6560e9c3a86383cb3af1333987abd39aae6af8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Mon, 16 Jan 2017 12:50:12 +0200 Subject: [PATCH 092/124] MDEV-11711: ArmHF EXPLAIN JSON garbage longlong values printed Make sure printing with snprintf uses the correct typed parameters. --- sql/my_json_writer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc index d36fdd1192a..135ce353552 100644 --- a/sql/my_json_writer.cc +++ b/sql/my_json_writer.cc @@ -125,7 +125,7 @@ void Json_writer::start_element() void Json_writer::add_ll(longlong val) { char buf[64]; - my_snprintf(buf, sizeof(buf), "%ld", val); + my_snprintf(buf, sizeof(buf), "%lld", val); add_unquoted_str(buf); } @@ -135,16 +135,16 @@ void Json_writer::add_size(longlong val) { char buf[64]; if (val < 1024) - my_snprintf(buf, sizeof(buf), "%ld", val); + my_snprintf(buf, sizeof(buf), "%lld", val); else if (val < 1024*1024*16) { /* Values less than 16MB are specified in KB for precision */ - size_t len= my_snprintf(buf, sizeof(buf), "%ld", val/1024); + size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/1024); strcpy(buf + len, "Kb"); } else { - size_t len= my_snprintf(buf, sizeof(buf), "%ld", val/(1024*1024)); + size_t len= my_snprintf(buf, sizeof(buf), "%lld", val/(1024*1024)); strcpy(buf + len, "Mb"); } add_str(buf); From d807e41511c92a1497f8550fdee6557eb856218a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 17 Jan 2017 00:37:20 +0200 Subject: [PATCH 093/124] Post merge fix sysvars_innodb for xtradb --- mysql-test/suite/sys_vars/t/sysvars_innodb.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/suite/sys_vars/t/sysvars_innodb.test b/mysql-test/suite/sys_vars/t/sysvars_innodb.test index bd8442b6a44..8faa9bce31a 100644 --- a/mysql-test/suite/sys_vars/t/sysvars_innodb.test +++ b/mysql-test/suite/sys_vars/t/sysvars_innodb.test @@ -3,6 +3,11 @@ --source include/not_valgrind.inc --source include/word_size.inc +if (`select plugin_auth_version <= "5.6.34-79.1" from information_schema.plugins where plugin_name='innodb'`) +{ + --skip Not fixed in XtraDB as of 10.1.21-MariaDB or earlier +} + --vertical_results --replace_regex /^\/\S+/PATH/ /\.\//PATH/ select * from information_schema.system_variables From 1e192e901ccf34454967cc3f62a71432c50f2c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 17 Jan 2017 02:35:16 +0200 Subject: [PATCH 094/124] Post merge review fixes * Remove duplicate lines from tests * Use thd instead of current_thd * Remove extra wsrep_binlog_format_names * Correctly merge union patch from 5.5 wrt duplicate rows. * Correctly merge SELinux changes into 10.1 --- .gitignore | 2 +- .../suite/rpl/r/rpl_row_mysqlbinlog.result | 1 - .../suite/rpl/t/rpl_row_mysqlbinlog.test | 2 - scripts/mysqld_safe.sh | 4 - sql/item.cc | 2 +- sql/mysqld.cc | 4 - sql/sql_select.cc | 2 +- support-files/CMakeLists.txt | 20 ++- support-files/SELinux/CMakeLists.txt | 35 ----- support-files/SELinux/rhel4-mysql.fc | 41 ----- support-files/SELinux/rhel4-mysql.te | 147 ------------------ .../selinux/mysqld-safe.te} | 0 support-files/rpm/server-postin.sh | 2 +- 13 files changed, 23 insertions(+), 239 deletions(-) delete mode 100644 support-files/SELinux/CMakeLists.txt delete mode 100644 support-files/SELinux/rhel4-mysql.fc delete mode 100644 support-files/SELinux/rhel4-mysql.te rename support-files/{SELinux/centos6-mariadb.te => policy/selinux/mysqld-safe.te} (100%) diff --git a/.gitignore b/.gitignore index c76b08477c9..5d882f268ff 100644 --- a/.gitignore +++ b/.gitignore @@ -218,7 +218,7 @@ support-files/mysql.spec support-files/mysqld_multi.server support-files/wsrep.cnf support-files/wsrep_notify -support-files/SELinux/centos6-mariadb.pp +support-files/policy/selinux/mysqld-safe.pp tags tests/async_queries tests/bug25714 diff --git a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result index 08a2237df39..7c7c6997b07 100644 --- a/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result +++ b/mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result @@ -1,7 +1,6 @@ include/master-slave.inc [connection master] ---Setup Section -- ----Setup Section -- set timestamp=1000000000; CREATE TABLE t1(word VARCHAR(20)); CREATE TABLE t2(id INT AUTO_INCREMENT NOT NULL PRIMARY KEY); diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test index 6f17824f43e..678679f0cf1 100644 --- a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test +++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test @@ -11,8 +11,6 @@ --echo ---Setup Section -- ---echo ---Setup Section -- - # we need this for getting fixed timestamps inside of this test set timestamp=1000000000; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 8faa11467d4..59f69e79a55 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -975,10 +975,6 @@ cmd="$cmd $args" # Avoid 'nohup: ignoring input' warning test -n "$NOHUP_NICENESS" && cmd="$cmd < /dev/null" -# close stdout and stderr, everything goes to $logging now -exec 1>&- -exec 2>&- - log_notice "Starting $MYSQLD daemon with databases from $DATADIR" # variable to track the current number of "fast" (a.k.a. subsecond) restarts diff --git a/sql/item.cc b/sql/item.cc index 2e7bc8e20c0..643e5c85df5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1133,7 +1133,7 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) if (conv == example) return this; Item_cache *cache; - if (!conv || conv->fix_fields(current_thd, (Item **) NULL) || + if (!conv || conv->fix_fields(thd, (Item **) NULL) || !(cache= new (thd->mem_root) Item_cache_str(thd, conv))) return NULL; // Safe conversion is not possible, or OEM cache->setup(thd, conv); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b0bb0e5cd22..5ff56daf7c2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -480,10 +480,6 @@ ulong opt_binlog_rows_event_max_size; my_bool opt_master_verify_checksum= 0; my_bool opt_slave_sql_verify_checksum= 1; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; -#ifdef WITH_WSREP -const char *wsrep_binlog_format_names[]= - {"MIXED", "STATEMENT", "ROW", "NONE", NullS}; -#endif /* WITH_WSREP */ volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */ uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_extra_port; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f299e863bf2..1bd101bbe6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17972,7 +17972,7 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) error= NESTED_LOOP_OK; /* select_limit used */ } - join->thd->limit_found_rows= join->send_records; + join->thd->limit_found_rows= join->send_records - join->duplicate_rows; if (error == NESTED_LOOP_NO_MORE_ROWS || join->thd->killed == ABORT_QUERY) error= NESTED_LOOP_OK; diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index e2c449d3b80..40a28e67625 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -56,10 +56,28 @@ IF(UNIX) INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${script} DESTINATION ${inst_location} COMPONENT Server_Scripts) ENDFOREACH() + + FIND_PROGRAM(CHECKMODULE checkmodule) + FIND_PROGRAM(SEMODULE_PACKAGE semodule_package) + MARK_AS_ADVANCED(CHECKMODULE SEMODULE_PACKAGE) + + # Build pp files in policy/selinux + IF(CHECKMODULE AND SEMODULE_PACKAGE) + FOREACH(pol mysqld-safe) + SET(src ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.te) + SET(mod ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) + SET(out ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.pp) + ADD_CUSTOM_COMMAND(OUTPUT ${out} + COMMAND ${CHECKMODULE} -M -m ${src} -o ${mod} + COMMAND ${SEMODULE_PACKAGE} -m ${mod} -o ${out} + DEPENDS ${src}) + ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) + ENDFOREACH() + ENDIF() + IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) INSTALL(DIRECTORY policy DESTINATION ${inst_location} COMPONENT SupportFiles) - ADD_SUBDIRECTORY(SELinux) ENDIF() CONFIGURE_FILE(mariadb.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mariadb.pc @ONLY) diff --git a/support-files/SELinux/CMakeLists.txt b/support-files/SELinux/CMakeLists.txt deleted file mode 100644 index e3cdb26ca8f..00000000000 --- a/support-files/SELinux/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2017, MariaDB -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -FIND_PROGRAM(CHECKMODULE checkmodule) -FIND_PROGRAM(SEMODULE_PACKAGE semodule_package) -MARK_AS_ADVANCED(CHECKMODULE SEMODULE_PACKAGE) - -SET(params DESTINATION ${INSTALL_SUPPORTFILESDIR}/SELinux COMPONENT SupportFiles) - -IF(CHECKMODULE AND SEMODULE_PACKAGE) - FOREACH(pol centos6-mariadb) - SET(src ${CMAKE_CURRENT_SOURCE_DIR}/${pol}.te) - SET(mod ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) - SET(out ${CMAKE_CURRENT_BINARY_DIR}/${pol}.pp) - ADD_CUSTOM_COMMAND(OUTPUT ${out} - COMMAND ${CHECKMODULE} -M -m ${src} -o ${mod} - COMMAND ${SEMODULE_PACKAGE} -m ${mod} -o ${out} - DEPENDS ${src}) - ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) - INSTALL(FILES ${out} ${params}) - ENDFOREACH() -ENDIF() -INSTALL(FILES centos6-mariadb.te rhel4-mysql.fc rhel4-mysql.te ${params}) diff --git a/support-files/SELinux/rhel4-mysql.fc b/support-files/SELinux/rhel4-mysql.fc deleted file mode 100644 index aa0fced4bbc..00000000000 --- a/support-files/SELinux/rhel4-mysql.fc +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2007 MySQL AB -# Use is subject to license terms -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -# MySQL Database Server - -# -# /etc -# -/etc/my\.cnf -- gen_context(system_u:object_r:mysqld_etc_t,s0) -/etc/mysql(/.*)? gen_context(system_u:object_r:mysqld_etc_t,s0) - -# -# /usr -# Red Hat compatibility -/usr/libexec/mysqld -- gen_context(system_u:object_r:mysqld_exec_t,s0) - -# MySQL AB compatibility -/usr/sbin/mysqld(-max)? -- gen_context(system_u:object_r:mysqld_exec_t,s0) - -# -# /var -# -/var/lib/mysql(/.*)? gen_context(system_u:object_r:mysqld_db_t,s0) -/var/lib/mysql/mysql\.sock -s gen_context(system_u:object_r:mysqld_var_run_t,s0) - -/var/log/mysql.* -- gen_context(system_u:object_r:mysqld_log_t,s0) - -/var/run/mysqld(/.*)? gen_context(system_u:object_r:mysqld_var_run_t,s0) diff --git a/support-files/SELinux/rhel4-mysql.te b/support-files/SELinux/rhel4-mysql.te deleted file mode 100644 index d2609244640..00000000000 --- a/support-files/SELinux/rhel4-mysql.te +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright (C) 2007 MySQL AB -# Use is subject to license terms -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -policy_module(mysql,1.0.0) - -######################################## -# -# Declarations -# - -type mysqld_t; -type mysqld_exec_t; -init_daemon_domain(mysqld_t,mysqld_exec_t) - -type mysqld_var_run_t; -files_pid_file(mysqld_var_run_t) - -type mysqld_db_t; -files_type(mysqld_db_t) - -type mysqld_etc_t alias etc_mysqld_t; -files_config_file(mysqld_etc_t) - -type mysqld_log_t; -logging_log_file(mysqld_log_t) - -type mysqld_tmp_t; -files_tmp_file(mysqld_tmp_t) - -######################################## -# -# Local policy -# - -allow mysqld_t self:capability { dac_override setgid setuid sys_resource net_bind_service }; -dontaudit mysqld_t self:capability sys_tty_config; -allow mysqld_t self:process { setsched getsched setrlimit signal_perms rlimitinh }; -allow mysqld_t self:fifo_file { read write }; -allow mysqld_t self:unix_stream_socket create_stream_socket_perms; -allow mysqld_t self:tcp_socket create_stream_socket_perms; -allow mysqld_t self:udp_socket create_socket_perms; - -allow mysqld_t mysqld_db_t:dir create_dir_perms; -allow mysqld_t mysqld_db_t:file create_file_perms; -allow mysqld_t mysqld_db_t:lnk_file create_lnk_perms; -files_var_lib_filetrans(mysqld_t,mysqld_db_t,{ dir file }) - -allow mysqld_t mysqld_etc_t:file { getattr read }; -allow mysqld_t mysqld_etc_t:lnk_file { getattr read }; -allow mysqld_t mysqld_etc_t:dir list_dir_perms; - -allow mysqld_t mysqld_log_t:file create_file_perms; -logging_log_filetrans(mysqld_t,mysqld_log_t,file) - -allow mysqld_t mysqld_tmp_t:dir create_dir_perms; -allow mysqld_t mysqld_tmp_t:file create_file_perms; -files_tmp_filetrans(mysqld_t, mysqld_tmp_t, { file dir }) - -allow mysqld_t mysqld_var_run_t:dir rw_dir_perms; -allow mysqld_t mysqld_var_run_t:sock_file create_file_perms; -allow mysqld_t mysqld_var_run_t:file create_file_perms; -files_pid_filetrans(mysqld_t,mysqld_var_run_t,file) - -kernel_read_system_state(mysqld_t) -kernel_read_kernel_sysctls(mysqld_t) - -corenet_non_ipsec_sendrecv(mysqld_t) -corenet_tcp_sendrecv_all_if(mysqld_t) -corenet_udp_sendrecv_all_if(mysqld_t) -corenet_tcp_sendrecv_all_nodes(mysqld_t) -corenet_udp_sendrecv_all_nodes(mysqld_t) -corenet_tcp_sendrecv_all_ports(mysqld_t) -corenet_udp_sendrecv_all_ports(mysqld_t) -corenet_tcp_bind_all_nodes(mysqld_t) -corenet_tcp_bind_mysqld_port(mysqld_t) -corenet_tcp_connect_mysqld_port(mysqld_t) -corenet_sendrecv_mysqld_client_packets(mysqld_t) -corenet_sendrecv_mysqld_server_packets(mysqld_t) - -dev_read_sysfs(mysqld_t) - -fs_getattr_all_fs(mysqld_t) -fs_search_auto_mountpoints(mysqld_t) - -term_dontaudit_use_console(mysqld_t) - -domain_use_interactive_fds(mysqld_t) - -files_getattr_var_lib_dirs(mysqld_t) -files_read_etc_runtime_files(mysqld_t) -files_read_etc_files(mysqld_t) -files_read_usr_files(mysqld_t) -files_search_var_lib(mysqld_t) - -auth_use_nsswitch(mysqld_t) - -init_use_fds(mysqld_t) -init_use_script_ptys(mysqld_t) - -libs_use_ld_so(mysqld_t) -libs_use_shared_libs(mysqld_t) - -logging_send_syslog_msg(mysqld_t) - -miscfiles_read_localization(mysqld_t) - -sysnet_read_config(mysqld_t) - -userdom_dontaudit_use_unpriv_user_fds(mysqld_t) -# for /root/.my.cnf - should not be needed: -userdom_read_sysadm_home_content_files(mysqld_t) - -ifdef(`distro_redhat',` - # because Fedora has the sock_file in the database directory - type_transition mysqld_t mysqld_db_t:sock_file mysqld_var_run_t; -') - -ifdef(`targeted_policy',` - term_dontaudit_use_unallocated_ttys(mysqld_t) - term_dontaudit_use_generic_ptys(mysqld_t) - files_dontaudit_read_root_files(mysqld_t) -') - -optional_policy(` - daemontools_service_domain(mysqld_t, mysqld_exec_t) -') - -optional_policy(` - seutil_sigchld_newrole(mysqld_t) -') - -optional_policy(` - udev_read_db(mysqld_t) -') diff --git a/support-files/SELinux/centos6-mariadb.te b/support-files/policy/selinux/mysqld-safe.te similarity index 100% rename from support-files/SELinux/centos6-mariadb.te rename to support-files/policy/selinux/mysqld-safe.te diff --git a/support-files/rpm/server-postin.sh b/support-files/rpm/server-postin.sh index fca66a96c04..bdce35b1d0e 100644 --- a/support-files/rpm/server-postin.sh +++ b/support-files/rpm/server-postin.sh @@ -96,7 +96,7 @@ if [ -f /etc/redhat-release ] ; then fi if grep 'CentOS release 6' /etc/redhat-release >/dev/null 2>&1; then if [ -x /usr/sbin/semodule ] ; then - /usr/sbin/semodule -i /usr/share/mysql/SELinux/centos6-mariadb.pp + /usr/sbin/semodule -i /usr/share/mysql/policy/selinux/mysqld-safe.pp fi fi fi From 3e589d4b8edf3d435a44cf71419a8355fe284f8e Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 17 Jan 2017 12:24:55 +0100 Subject: [PATCH 095/124] MDEV-11811: dual master with parallel replication memory leak in write master Gtid_list_log_event::do_apply_event() did not free_root(thd->mem_root). It can allocate on this in record_gtid(), and in some scenarios there is nothing else that does free_root(), leading to temporary memory leak until stop of SQL thread. One scenario is in circular replication with only one master active. The active master receives only its own events on the slave, all of which are ignored. But whenever the SQL thread catches up with the IO thread, a Gtid_list_log_event is applied, leading to the leak. --- sql/log_event.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/log_event.cc b/sql/log_event.cc index d311297f8a8..14f6bb20b47 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6915,6 +6915,7 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi) rli->abort_slave= true; rli->stop_for_until= true; } + free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC)); return ret; } From 30a9ac4250e1b19754dd0ae43705108cc9de2ab0 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 17 Jan 2017 15:32:41 +0400 Subject: [PATCH 096/124] MDEV-10956 Strict Password Validation Breaks Replication. strict_password_validation variable now has no effect in the slave thread. --- .../r/rpl_strict_password_validation.result | 13 ++++++++++ .../rpl/t/rpl_strict_password_validation.test | 24 +++++++++++++++++++ sql/sql_acl.cc | 9 +++---- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_strict_password_validation.result create mode 100644 mysql-test/suite/rpl/t/rpl_strict_password_validation.test diff --git a/mysql-test/suite/rpl/r/rpl_strict_password_validation.result b/mysql-test/suite/rpl/r/rpl_strict_password_validation.result new file mode 100644 index 00000000000..071d730fa72 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_strict_password_validation.result @@ -0,0 +1,13 @@ +include/master-slave.inc +[connection master] +install soname "simple_password_check"; +select @@strict_password_validation; +@@strict_password_validation +1 +create user foo1 identified by password '11111111111111111111111111111111111111111'; +set password for foo1 = PASSWORD('PLAINtext-password!!99'); +drop user foo1; +create user foo1 identified by password '11111111111111111111111111111111111111111'; +ERROR HY000: The MariaDB server is running with the --strict-password-validation option so it cannot execute this statement +uninstall plugin simple_password_check; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_strict_password_validation.test b/mysql-test/suite/rpl/t/rpl_strict_password_validation.test new file mode 100644 index 00000000000..c4dda1e1269 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_strict_password_validation.test @@ -0,0 +1,24 @@ +if (!$SIMPLE_PASSWORD_CHECK_SO) { + skip No SIMPLE_PASSWORD_CHECK plugin; +} + +--source include/master-slave.inc + + +--connection slave +install soname "simple_password_check"; +select @@strict_password_validation; + +--connection master +create user foo1 identified by password '11111111111111111111111111111111111111111'; +set password for foo1 = PASSWORD('PLAINtext-password!!99'); +drop user foo1; +--sync_slave_with_master + +--connection slave +--error ER_OPTION_PREVENTS_STATEMENT +create user foo1 identified by password '11111111111111111111111111111111111111111'; + +uninstall plugin simple_password_check; + +--source include/rpl_end.inc diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2accb3abc91..912930d60f3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -895,7 +895,7 @@ static my_bool do_validate(THD *, plugin_ref plugin, void *arg) } -static bool validate_password(LEX_USER *user) +static bool validate_password(LEX_USER *user, THD *thd) { if (user->pwtext.length || !user->pwhash.length) { @@ -911,7 +911,8 @@ static bool validate_password(LEX_USER *user) } else { - if (strict_password_validation && has_validation_plugins()) + if (!thd->slave_thread && + strict_password_validation && has_validation_plugins()) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation"); return true; @@ -2750,7 +2751,7 @@ bool check_change_password(THD *thd, LEX_USER *user) LEX_USER *real_user= get_current_user(thd, user); if (fix_and_copy_user(real_user, user, thd) || - validate_password(real_user)) + validate_password(real_user, thd)) return true; *user= *real_user; @@ -3465,7 +3466,7 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo, } if (!old_row_exists || combo.pwtext.length || combo.pwhash.length) - if (!handle_as_role && validate_password(&combo)) + if (!handle_as_role && validate_password(&combo, thd)) goto end; /* Update table columns with new privileges */ From e4e801d4789d3992c1f04b260de3af4c9e5e6b0c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2017 11:15:21 +0100 Subject: [PATCH 097/124] connect: compilation errors and few obvious bugs --- storage/connect/filamzip.cpp | 8 ++++---- storage/connect/ioapi.h | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 65013e170e4..22fe95aebad 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -97,7 +97,7 @@ loopStart: if (!*++pat) return TRUE; goto loopStart; default: - if (mapCaseTable[*s] != mapCaseTable[*p]) + if (mapCaseTable[(unsigned)*s] != mapCaseTable[(unsigned)*p]) goto starCheck; break; } /* endswitch */ @@ -151,7 +151,7 @@ int ZIPUTIL::findEntry(PGLOBAL g, bool next) if (rc == UNZ_END_OF_LIST_OF_FILE) return RC_EF; else if (rc != UNZ_OK) { - sprintf(g->Message, "unzGoToNextFile rc = ", rc); + sprintf(g->Message, "unzGoToNextFile rc = %d", rc); return RC_FX; } // endif rc @@ -261,7 +261,7 @@ bool ZIPUTIL::OpenTable(PGLOBAL g, MODE mode, char *fn) fp->Memory = memory; fp->Mode = mode; fp->File = this; - fp->Handle = NULL; + fp->Handle = 0; } // endif fp } else @@ -297,7 +297,7 @@ bool ZIPUTIL::openEntry(PGLOBAL g) memory = new char[size + 1]; if ((rc = unzReadCurrentFile(zipfile, memory, size)) < 0) { - sprintf(g->Message, "unzReadCurrentFile rc = ", rc); + sprintf(g->Message, "unzReadCurrentFile rc = %d", rc); unzCloseCurrentFile(zipfile); free(memory); memory = NULL; diff --git a/storage/connect/ioapi.h b/storage/connect/ioapi.h index 8dcbdb06e35..4fa73002053 100644 --- a/storage/connect/ioapi.h +++ b/storage/connect/ioapi.h @@ -129,8 +129,9 @@ extern "C" { #endif #endif - - +#ifndef OF +#define OF(args) args +#endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); From 736afe868094b9aa24211c3772fb3b297d62d8fc Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Fri, 13 Jan 2017 11:25:38 +0100 Subject: [PATCH 098/124] mysql_install_db enhancements to facilitate Debian bug#848616 fix In Debian, the default install is made more secure by omitting the anonymous user and by making the root account authenticate by unix socket authentication instead of the default password-less root. However, Debian hard-codes this change in mysql_install_db, which breaks that program for other users. This commit instead implements new general options for mysql_install_db that can be used by anyone to similarly perform a more secure install: --skip-auth-anonymous-user: omits the anonymous user. --auth-root-authentication-method=normal: Keeps the existing behaviour with a password-less root account. Currently on by default. --auth-root-socket-user=USER --auth-root-authentication-method=socket: creates the MariaDB root user with the name USER (defaults to 'root') and using unix socket authentication. This way, only that user has MariaDB root access after install. The idea with --auth-root-authentication-method=normal is that applications that need this behaviour can give that option explicitly. Then eventually we could make --auth-root-authentication-method=socket the default, giving a more secure default installation. Note that it is perfectly possible to do a secure install with --auth-root-authentication-method=normal. For example, installing a private server just for local access by a single OS-level user, by using --skip-networking and putting the connection socket in a location without public access. So it is important to preserve this API for backwards compatibility. --- ...mysql_create_system_tables__no_test.dpatch | 24 +++++------ scripts/mysql_install_db.sh | 40 ++++++++++++++++++- scripts/mysql_system_tables_data.sql | 27 ++++++++----- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch index 6547e4434f1..183212ef678 100755 --- a/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch +++ b/debian/patches/33_scripts__mysql_create_system_tables__no_test.dpatch @@ -8,8 +8,8 @@ ## DP: http://bugs.mysql.com/bug.php?id=6901 @DPATCH@ ---- old/scripts/mysql_system_tables_data.sql 2008-12-04 22:59:44.000000000 +0100 -+++ new/scripts/mysql_system_tables_data.sql 2008-12-04 23:00:07.000000000 +0100 +--- a/scripts/mysql_system_tables_data.sql ++++ b/scripts/mysql_system_tables_data.sql @@ -26,16 +26,6 @@ -- a plain character SELECT LOWER( REPLACE((SELECT REPLACE(@@hostname,'_','\_')),'%','\%') )INTO @current_hostname; @@ -26,14 +26,14 @@ - -- Fill "user" table with default users allowing root access -- from local machine if "user" table didn't exist before - CREATE TEMPORARY TABLE tmp_user LIKE user; -@@ -43,8 +33,6 @@ INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y',' - REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0 FROM dual WHERE @current_hostname != 'localhost'; - REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0); - REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); --INSERT INTO tmp_user (host,user) VALUES ('localhost',''); --INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; - INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0; - DROP TABLE tmp_user; + CREATE TEMPORARY TABLE tmp_user_nopasswd LIKE user; +@@ -48,9 +38,6 @@ REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y' + REPLACE INTO tmp_user_nopasswd VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); + -- More secure root account using unix sucket auth. + INSERT INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),'','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'unix_socket','','N', 'N','', 0); +--- Anonymous user with no privileges. +-INSERT INTO tmp_user_anonymous (host,user) VALUES ('localhost',''); +-INSERT INTO tmp_user_anonymous (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; - + INSERT INTO user SELECT * FROM tmp_user_nopasswd WHERE @had_user_table=0 AND @skip_auth_root_nopasswd IS NULL; + INSERT INTO user SELECT * FROM tmp_user_socket WHERE @had_user_table=0 AND @auth_root_socket IS NOT NULL; diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 5eb0796c647..364cc4fb9e0 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -34,11 +34,26 @@ force=0 in_rpm=0 ip_only=0 cross_bootstrap=0 +install_params="" +auth_root_authentication_method=normal +auth_root_socket_user='root' usage() { cat < /dev/null +case "$auth_root_authentication_method" in + normal) + install_params="$install_params +SET @skip_auth_root_nopasswd=NULL; +SET @auth_root_socket=NULL;" ;; + socket) + install_params="$install_params +SET @skip_auth_root_nopasswd=1; +SET @auth_root_socket='$auth_root_socket_user';" ;; +esac +if { echo "use mysql;$install_params"; cat "$create_system_tables" "$create_system_tables2" "$fill_system_tables"; } | eval "$filter_cmd_line" | mysqld_install_cmd_line > /dev/null then s_echo "OK" else diff --git a/scripts/mysql_system_tables_data.sql b/scripts/mysql_system_tables_data.sql index 075aafd5e3b..9556e7ba160 100644 --- a/scripts/mysql_system_tables_data.sql +++ b/scripts/mysql_system_tables_data.sql @@ -38,15 +38,24 @@ DROP TABLE tmp_db; -- Fill "user" table with default users allowing root access -- from local machine if "user" table didn't exist before -CREATE TEMPORARY TABLE tmp_user LIKE user; -INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N', 'N','', 0); -REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0 FROM dual WHERE @current_hostname != 'localhost'; -REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0); -REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); -INSERT INTO tmp_user (host,user) VALUES ('localhost',''); -INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; -INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0; -DROP TABLE tmp_user; +CREATE TEMPORARY TABLE tmp_user_nopasswd LIKE user; +CREATE TEMPORARY TABLE tmp_user_socket LIKE user; +CREATE TEMPORARY TABLE tmp_user_anonymous LIKE user; +-- Classic passwordless root account. +INSERT INTO tmp_user_nopasswd VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N', 'N','', 0); +REPLACE INTO tmp_user_nopasswd SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0 FROM dual WHERE @current_hostname != 'localhost'; +REPLACE INTO tmp_user_nopasswd VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N','',0); +REPLACE INTO tmp_user_nopasswd VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N','N', '', 0); +-- More secure root account using unix sucket auth. +INSERT INTO tmp_user_socket VALUES ('localhost',IFNULL(@auth_root_socket, 'root'),'','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'unix_socket','','N', 'N','', 0); +-- Anonymous user with no privileges. +INSERT INTO tmp_user_anonymous (host,user) VALUES ('localhost',''); +INSERT INTO tmp_user_anonymous (host,user) SELECT @current_hostname,'' FROM dual WHERE @current_hostname != 'localhost'; + +INSERT INTO user SELECT * FROM tmp_user_nopasswd WHERE @had_user_table=0 AND @skip_auth_root_nopasswd IS NULL; +INSERT INTO user SELECT * FROM tmp_user_socket WHERE @had_user_table=0 AND @auth_root_socket IS NOT NULL; +INSERT INTO user SELECT * FROM tmp_user_anonymous WHERE @had_user_table=0 AND @skip_auth_anonymous IS NULL; +DROP TABLE tmp_user_nopasswd, tmp_user_socket, tmp_user_anonymous; CREATE TEMPORARY TABLE tmp_proxies_priv LIKE proxies_priv; INSERT INTO tmp_proxies_priv VALUES ('localhost', 'root', '', '', TRUE, '', now()); From e79e840607adff6f2e55d4c889ae055d07bdabf5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2017 14:09:38 +0100 Subject: [PATCH 099/124] selinux fixes for 10.0->10.1 merge 1. don't put generated files into ${CMAKE_CURRENT_SOURCE_DIR} 2. policy file name must match the module name (Fedora 24 requirement) --- support-files/CMakeLists.txt | 36 +++++++++---------- .../selinux/{mysqld-safe.te => mariadb.te} | 0 support-files/rpm/server-postin.sh | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) rename support-files/policy/selinux/{mysqld-safe.te => mariadb.te} (100%) diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 40a28e67625..c80de04d069 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -57,27 +57,27 @@ IF(UNIX) DESTINATION ${inst_location} COMPONENT Server_Scripts) ENDFOREACH() - FIND_PROGRAM(CHECKMODULE checkmodule) - FIND_PROGRAM(SEMODULE_PACKAGE semodule_package) - MARK_AS_ADVANCED(CHECKMODULE SEMODULE_PACKAGE) - - # Build pp files in policy/selinux - IF(CHECKMODULE AND SEMODULE_PACKAGE) - FOREACH(pol mysqld-safe) - SET(src ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.te) - SET(mod ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) - SET(out ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.pp) - ADD_CUSTOM_COMMAND(OUTPUT ${out} - COMMAND ${CHECKMODULE} -M -m ${src} -o ${mod} - COMMAND ${SEMODULE_PACKAGE} -m ${mod} -o ${out} - DEPENDS ${src}) - ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) - ENDFOREACH() - ENDIF() - IF(INSTALL_SUPPORTFILESDIR) INSTALL(FILES magic DESTINATION ${inst_location} COMPONENT SupportFiles) INSTALL(DIRECTORY policy DESTINATION ${inst_location} COMPONENT SupportFiles) + FIND_PROGRAM(CHECKMODULE checkmodule) + FIND_PROGRAM(SEMODULE_PACKAGE semodule_package) + MARK_AS_ADVANCED(CHECKMODULE SEMODULE_PACKAGE) + + # Build pp files in policy/selinux + IF(CHECKMODULE AND SEMODULE_PACKAGE) + FOREACH(pol mariadb) + SET(src ${CMAKE_CURRENT_SOURCE_DIR}/policy/selinux/${pol}.te) + SET(tmp ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${pol}-pp.dir/${pol}.mod) + SET(out ${CMAKE_CURRENT_BINARY_DIR}/${pol}.pp) + ADD_CUSTOM_COMMAND(OUTPUT ${out} + COMMAND ${CHECKMODULE} -M -m ${src} -o ${tmp} + COMMAND ${SEMODULE_PACKAGE} -m ${tmp} -o ${out} + DEPENDS ${src}) + ADD_CUSTOM_TARGET(${pol}-pp ALL DEPENDS ${out}) + INSTALL(FILES ${out} DESTINATION ${inst_location}/policy/selinux COMPONENT SupportFiles) + ENDFOREACH() + ENDIF() ENDIF() CONFIGURE_FILE(mariadb.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mariadb.pc @ONLY) diff --git a/support-files/policy/selinux/mysqld-safe.te b/support-files/policy/selinux/mariadb.te similarity index 100% rename from support-files/policy/selinux/mysqld-safe.te rename to support-files/policy/selinux/mariadb.te diff --git a/support-files/rpm/server-postin.sh b/support-files/rpm/server-postin.sh index bdce35b1d0e..9ef9bec3e0d 100644 --- a/support-files/rpm/server-postin.sh +++ b/support-files/rpm/server-postin.sh @@ -96,7 +96,7 @@ if [ -f /etc/redhat-release ] ; then fi if grep 'CentOS release 6' /etc/redhat-release >/dev/null 2>&1; then if [ -x /usr/sbin/semodule ] ; then - /usr/sbin/semodule -i /usr/share/mysql/policy/selinux/mysqld-safe.pp + /usr/sbin/semodule -i /usr/share/mysql/policy/selinux/mariadb.pp fi fi fi From ef8003eb9a23007ac5d606530dcdcc3ea2f0c039 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2017 18:23:02 +0100 Subject: [PATCH 100/124] MDEV-11698 Old Bug possibly not fixed; BEFORE INSERT Trigger on NOT NULL check_that_all_fields_are_given_values() relied on write_set, but was run too early, before triggers updated write_set. also, when triggers are present, fields might get values conditionally, so we need to check that all fields are given values for every row. --- mysql-test/r/insert_update.result | 4 +- mysql-test/r/trigger_no_defaults-11698.result | 22 ++++ mysql-test/t/insert_update.test | 6 +- mysql-test/t/trigger_no_defaults-11698.test | 25 ++++ sql/sql_insert.cc | 118 +++++++++--------- sql/sql_insert.h | 3 +- sql/sql_prepare.cc | 2 +- 7 files changed, 119 insertions(+), 61 deletions(-) create mode 100644 mysql-test/r/trigger_no_defaults-11698.result create mode 100644 mysql-test/t/trigger_no_defaults-11698.test diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 1987c5c0559..e8e6e16fe5a 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -242,14 +242,16 @@ ERROR 42S22: Unknown column 'a' in 'field list' DROP TABLE t1,t2; SET SQL_MODE = 'TRADITIONAL'; CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL); +INSERT INTO t1 VALUES (1,1); INSERT INTO t1 (a) VALUES (1); ERROR HY000: Field 'b' doesn't have a default value INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b; ERROR HY000: Field 'b' doesn't have a default value +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = a; INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b; -ERROR HY000: Field 'b' doesn't have a default value SELECT * FROM t1; a b +1 1 DROP TABLE t1; CREATE TABLE t1 (f1 INT AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(5) NOT NULL UNIQUE); diff --git a/mysql-test/r/trigger_no_defaults-11698.result b/mysql-test/r/trigger_no_defaults-11698.result new file mode 100644 index 00000000000..40546cee41d --- /dev/null +++ b/mysql-test/r/trigger_no_defaults-11698.result @@ -0,0 +1,22 @@ +set sql_mode='strict_all_tables'; +create table t1 (a int not null, b int); +insert t1 (b) values (1); +ERROR HY000: Field 'a' doesn't have a default value +create trigger trgi before insert on t1 for each row +case new.b +when 10 then +set new.a = new.b; +when 30 then +set new.a = new.a; +else +do 1; +end case| +insert t1 (b) values (10); +insert t1 (b) values (20); +ERROR HY000: Field 'a' doesn't have a default value +insert t1 (b) values (30); +select * from t1; +a b +10 10 +0 30 +drop table t1; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index de38ae0b0d3..7234973eeb8 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -170,6 +170,7 @@ DROP TABLE t1,t2; SET SQL_MODE = 'TRADITIONAL'; CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL); +INSERT INTO t1 VALUES (1,1); --error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 (a) VALUES (1); @@ -177,7 +178,10 @@ INSERT INTO t1 (a) VALUES (1); --error ER_NO_DEFAULT_FOR_FIELD INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b; ---error ER_NO_DEFAULT_FOR_FIELD +# this one is ok +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = a; + +# arguably the statement below should fail INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b; SELECT * FROM t1; diff --git a/mysql-test/t/trigger_no_defaults-11698.test b/mysql-test/t/trigger_no_defaults-11698.test new file mode 100644 index 00000000000..fab7845ad7d --- /dev/null +++ b/mysql-test/t/trigger_no_defaults-11698.test @@ -0,0 +1,25 @@ +# +# MDEV-11698 Old Bug possibly not fixed; BEFORE INSERT Trigger on NOT NULL +# +set sql_mode='strict_all_tables'; +create table t1 (a int not null, b int); +--error ER_NO_DEFAULT_FOR_FIELD +insert t1 (b) values (1); +delimiter |; +create trigger trgi before insert on t1 for each row + case new.b + when 10 then + set new.a = new.b; + when 30 then + set new.a = new.a; + else + do 1; + end case| +delimiter ;| +insert t1 (b) values (10); +--error ER_NO_DEFAULT_FOR_FIELD +insert t1 (b) values (20); +# arguably the statement below should fail too +insert t1 (b) values (30); +select * from t1; +drop table t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ac7fd93f0c0..f4e0a6a00eb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -304,6 +304,32 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(0); } +static bool has_no_default_value(THD *thd, Field *field, TABLE_LIST *table_list) +{ + if ((field->flags & NO_DEFAULT_VALUE_FLAG) && field->real_type() != MYSQL_TYPE_ENUM) + { + bool view= false; + if (table_list) + { + table_list= table_list->top_table(); + view= table_list->view != NULL; + } + if (view) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER_THD(thd, ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, table_list->view_name.str); + } + else + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_FIELD, + ER_THD(thd, ER_NO_DEFAULT_FOR_FIELD), field->field_name); + } + return true; + } + return false; +} + /** Check if update fields are correct. @@ -733,13 +759,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (mysql_prepare_insert(thd, table_list, table, fields, values, update_fields, update_values, duplic, &unused_conds, - FALSE, - (fields.elements || !value_count || - table_list->view != 0), - !ignore && thd->is_strict_mode())) + FALSE)) goto abort; - /* mysql_prepare_insert set table_list->table if it was not set */ + /* mysql_prepare_insert sets table_list->table if it was not set */ table= table_list->table; context= &thd->lex->select_lex.context; @@ -866,6 +889,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->prepare_triggers_for_insert_stmt_or_event(); table->mark_columns_needed_for_insert(); + if (fields.elements || !value_count || table_list->view != 0) + { + if (check_that_all_fields_are_given_values(thd, table, table_list)) + { + error= 1; + goto values_loop_end; + } + } if (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)) @@ -965,6 +996,23 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error= 1; break; } + /* + with triggers a field can get a value *conditionally*, so we have to repeat + has_no_default_value() check for every row + */ + if (table->triggers && + table->triggers->has_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE)) + { + for (Field **f=table->field ; *f ; f++) + { + if (!((*f)->flags & HAS_EXPLICIT_VALUE) && has_no_default_value(thd, *f, table_list)) + { + error= 1; + goto values_loop_end; + } + (*f)->flags &= ~HAS_EXPLICIT_VALUE; + } + } if ((res= table_list->view_check_option(thd, (values_list.elements == 1 ? @@ -1374,10 +1422,6 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement - check_fields TRUE if need to check that all INSERT fields are - given values. - abort_on_warning whether to report if some INSERT field is not - assigned as an error (TRUE) or as a warning (FALSE). TODO (in far future) In cases of: @@ -1397,9 +1441,8 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables) bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, - enum_duplicates duplic, - COND **where, bool select_insert, - bool check_fields, bool abort_on_warning) + enum_duplicates duplic, COND **where, + bool select_insert) { SELECT_LEX *select_lex= &thd->lex->select_lex; Name_resolution_context *context= &select_lex->context; @@ -1470,17 +1513,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, check_insert_fields(thd, context->table_list, fields, *values, !insert_into_view, 0, &map)); - if (!res && check_fields) - { - bool saved_abort_on_warning= thd->abort_on_warning; - thd->abort_on_warning= abort_on_warning; - res= check_that_all_fields_are_given_values(thd, - table ? table : - context->table_list->table, - context->table_list); - thd->abort_on_warning= saved_abort_on_warning; - } - if (!res) res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); @@ -1923,8 +1955,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, - TABLE_LIST *table_list) + +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list) { int err= 0; MY_BITMAP *write_set= entry->write_set; @@ -1932,32 +1964,8 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, for (Field **field=entry->field ; *field ; field++) { if (!bitmap_is_set(write_set, (*field)->field_index) && - ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && - ((*field)->real_type() != MYSQL_TYPE_ENUM)) - { - bool view= FALSE; - if (table_list) - { - table_list= table_list->top_table(); - view= MY_TEST(table_list->view); - } - if (view) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_VIEW_FIELD, - ER_THD(thd, ER_NO_DEFAULT_FOR_VIEW_FIELD), - table_list->view_db.str, - table_list->view_name.str); - } - else - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER_THD(thd, ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); - } - err= 1; - } + has_no_default_value(thd, *field, table_list)) + err=1; } return thd->abort_on_warning ? err : 0; } @@ -3390,9 +3398,8 @@ bool mysql_insert_select_prepare(THD *thd) if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, - lex->update_list, lex->value_list, - lex->duplicates, - &select_lex->where, TRUE, FALSE, FALSE)) + lex->update_list, lex->value_list, lex->duplicates, + &select_lex->where, TRUE)) DBUG_RETURN(TRUE); DBUG_ASSERT(select_lex->leaf_tables.elements != 0); @@ -3479,8 +3486,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) { bool saved_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); - res= check_that_all_fields_are_given_values(thd, table_list->table, - table_list); + res= check_that_all_fields_are_given_values(thd, table_list->table, table_list); thd->abort_on_warning= saved_abort_on_warning; } diff --git a/sql/sql_insert.h b/sql/sql_insert.h index cbfc1ea9dcd..aea0dac6b0d 100644 --- a/sql/sql_insert.h +++ b/sql/sql_insert.h @@ -27,8 +27,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, enum_duplicates duplic, - COND **where, bool select_insert, - bool check_fields, bool abort_on_warning); + COND **where, bool select_insert); bool mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d381825851d..d3a5d0aeef6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1299,7 +1299,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, if (mysql_prepare_insert(thd, table_list, table_list->table, fields, values, update_fields, update_values, - duplic, &unused_conds, FALSE, FALSE, FALSE)) + duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; From f797ea7124e906fd3abf311d66101a21dce2d27d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 16 Jan 2017 18:47:53 +0100 Subject: [PATCH 101/124] MDEV-11601 Out-of-bounds string access in create_schema_table() in Item_partition_func_safe_string(THD *thd, const char *name_arg, uint length, CHARSET_INFO *cs= NULL), the 'name_arg' is the value of the string constant and 'length' is the length of this constant, so length == strlen(name_arg). --- sql/item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item.h b/sql/item.h index 07b8a865652..b09e9297826 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3206,7 +3206,7 @@ class Item_blob :public Item_partition_func_safe_string { public: Item_blob(THD *thd, const char *name_arg, uint length): - Item_partition_func_safe_string(thd, name_arg, length, &my_charset_bin) + Item_partition_func_safe_string(thd, name_arg, strlen(name_arg), &my_charset_bin) { max_length= length; } enum Type type() const { return TYPE_HOLDER; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } From fbcdc3437c94314f69d255a303d791f704916653 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2017 22:08:19 +0100 Subject: [PATCH 102/124] connect zip bug fix --- storage/connect/filamzip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp index 22fe95aebad..6aca4631f32 100644 --- a/storage/connect/filamzip.cpp +++ b/storage/connect/filamzip.cpp @@ -97,7 +97,7 @@ loopStart: if (!*++pat) return TRUE; goto loopStart; default: - if (mapCaseTable[(unsigned)*s] != mapCaseTable[(unsigned)*p]) + if (mapCaseTable[(uchar)*s] != mapCaseTable[(uchar)*p]) goto starCheck; break; } /* endswitch */ From a14638581b4c8ef175e68dccff07967d819b3b7e Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Wed, 18 Jan 2017 08:39:18 -0500 Subject: [PATCH 103/124] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ad620531c9a..9f8b1071da3 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=21 +MYSQL_VERSION_PATCH=22 From dc557ca817f18e27ab46342865a510898f76822e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 19 Jan 2017 08:19:08 +0200 Subject: [PATCH 104/124] MDEV-11835: InnoDB: Failing assertion: free_slot != NULL on restarting server with encryption and read-only buf0buf.cc: Temporary slots used in encryption was calculated by read_threads * write_threads. However, in read-only mode write_threads is zero. Correct way is to calculate (read_threads + write_threads) * max pending IO requests. --- .../encryption/r/innodb-read-only.result | 3 ++ .../suite/encryption/t/innodb-read-only.opt | 3 ++ .../suite/encryption/t/innodb-read-only.test | 34 +++++++++++++++++++ storage/innobase/buf/buf0buf.cc | 2 +- storage/xtradb/buf/buf0buf.cc | 2 +- 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/encryption/r/innodb-read-only.result create mode 100644 mysql-test/suite/encryption/t/innodb-read-only.opt create mode 100644 mysql-test/suite/encryption/t/innodb-read-only.test diff --git a/mysql-test/suite/encryption/r/innodb-read-only.result b/mysql-test/suite/encryption/r/innodb-read-only.result new file mode 100644 index 00000000000..5d063e129e2 --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb-read-only.result @@ -0,0 +1,3 @@ +# Wait max 10 min for key encryption threads to encrypt all spaces +# Success! +# All done diff --git a/mysql-test/suite/encryption/t/innodb-read-only.opt b/mysql-test/suite/encryption/t/innodb-read-only.opt new file mode 100644 index 00000000000..acedb1a17bb --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb-read-only.opt @@ -0,0 +1,3 @@ +--innodb-encrypt-tables=1 +--innodb-encryption-threads=4 +--innodb-tablespaces-encryption diff --git a/mysql-test/suite/encryption/t/innodb-read-only.test b/mysql-test/suite/encryption/t/innodb-read-only.test new file mode 100644 index 00000000000..10ec87467b6 --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb-read-only.test @@ -0,0 +1,34 @@ +--source suite/encryption/include/have_file_key_management_plugin.inc +--source include/have_innodb.inc +--source include/not_embedded.inc + +--echo # Wait max 10 min for key encryption threads to encrypt all spaces +let $cnt=600; +while ($cnt) +{ + let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0`; + if ($success) + { + let $cnt=0; + } + if (!$success) + { + real_sleep 1; + dec $cnt; + } +} +if (!$success) +{ + SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION; + SHOW STATUS LIKE 'innodb_encryption%'; + -- die Timeout waiting for encryption threads +} +--echo # Success! + +# +# MDEV-11835: InnoDB: Failing assertion: free_slot != NULL on +# restarting server with encryption and read-only +# +--let $restart_parameters= --innodb-read-only=1 --innodb-encrypt-tables=1 +--source include/restart_mysqld.inc +--echo # All done diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index c918522233f..7a8bcd1b9d0 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1508,7 +1508,7 @@ buf_pool_init_instance( /* Initialize the temporal memory array and slots */ buf_pool->tmp_arr = (buf_tmp_array_t *)mem_zalloc(sizeof(buf_tmp_array_t)); - ulint n_slots = srv_n_read_io_threads * srv_n_write_io_threads * (8 * OS_AIO_N_PENDING_IOS_PER_THREAD); + ulint n_slots = (srv_n_read_io_threads + srv_n_write_io_threads) * (8 * OS_AIO_N_PENDING_IOS_PER_THREAD); buf_pool->tmp_arr->n_slots = n_slots; buf_pool->tmp_arr->slots = (buf_tmp_buffer_t*)mem_zalloc(sizeof(buf_tmp_buffer_t) * n_slots); diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 31a3f4978b8..e859301a38f 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -1571,7 +1571,7 @@ buf_pool_init_instance( /* Initialize the temporal memory array and slots */ buf_pool->tmp_arr = (buf_tmp_array_t *)mem_zalloc(sizeof(buf_tmp_array_t)); - ulint n_slots = srv_n_read_io_threads * srv_n_write_io_threads * (8 * OS_AIO_N_PENDING_IOS_PER_THREAD); + ulint n_slots = (srv_n_read_io_threads + srv_n_write_io_threads) * (8 * OS_AIO_N_PENDING_IOS_PER_THREAD); buf_pool->tmp_arr->n_slots = n_slots; buf_pool->tmp_arr->slots = (buf_tmp_buffer_t*)mem_zalloc(sizeof(buf_tmp_buffer_t) * n_slots); From 8a4d605500ae487d3dc515305662769645bb092f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 19 Jan 2017 12:20:54 +0200 Subject: [PATCH 105/124] MDEV-11838: Innodb-encryption-algorithm default should be != none Change default to zlib, this has effect only if user has explicitly requested page compression and then user naturally expects that pages are really compressed if they can be compressed. --- .../r/innodb-page_compression_default.result | 20 ++++++++ .../t/innodb-page_compression_default.test | 51 +++++++++++++++++++ .../suite/sys_vars/r/sysvars_innodb.result | 4 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/xtradb/handler/ha_innodb.cc | 2 +- 5 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb-page_compression_default.result create mode 100644 mysql-test/suite/innodb/t/innodb-page_compression_default.test diff --git a/mysql-test/suite/innodb/r/innodb-page_compression_default.result b/mysql-test/suite/innodb/r/innodb-page_compression_default.result new file mode 100644 index 00000000000..10e1d6c766c --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-page_compression_default.result @@ -0,0 +1,20 @@ +SET GLOBAL innodb_file_format = `Barracuda`; +SET GLOBAL innodb_file_per_table = ON; +create table t1 (c1 int not null primary key auto_increment, b char(200)) engine=innodb page_compressed=1; +insert into t1 values(NULL,'compressed_text_aaaaaaaaabbbbbbbbbbbbbccccccccccccc'); +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +# t1 compressed expected NOT FOUND +NOT FOUND /compressed_text/ in t1.ibd +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb-page_compression_default.test b/mysql-test/suite/innodb/t/innodb-page_compression_default.test new file mode 100644 index 00000000000..28f184c278c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-page_compression_default.test @@ -0,0 +1,51 @@ +--source include/have_innodb.inc + +--disable_query_log +let $innodb_compression_algorithm_orig=`SELECT @@innodb_compression_algorithm`; +let $innodb_file_format_orig = `SELECT @@innodb_file_format`; +let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`; +--enable_query_log + +--disable_warnings +SET GLOBAL innodb_file_format = `Barracuda`; +SET GLOBAL innodb_file_per_table = ON; +--enable_warnings + +create table t1 (c1 int not null primary key auto_increment, b char(200)) engine=innodb page_compressed=1; +insert into t1 values(NULL,'compressed_text_aaaaaaaaabbbbbbbbbbbbbccccccccccccc'); +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; +insert into t1(b) select b from t1; + +let $wait_condition= select variable_value > 0 from information_schema.global_status where variable_name = 'INNODB_NUM_PAGES_PAGE_COMPRESSED'; +--source include/wait_condition.inc + +--let $MYSQLD_DATADIR=`select @@datadir` +--let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd +--let SEARCH_RANGE = 10000000 +--let SEARCH_PATTERN=compressed_text + +--echo # t1 compressed expected NOT FOUND +-- let SEARCH_FILE=$t1_IBD +-- source include/search_pattern_in_file.inc + +drop table t1; + +# reset system +--disable_query_log +--disable_warnings +EVAL SET GLOBAL innodb_compression_algorithm = $innodb_compression_algorithm_orig; +EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig; +EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig; +--enable_warnings +--enable_query_log diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 05b1a07c328..afa152b0c7b 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -497,9 +497,9 @@ READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_COMPRESSION_ALGORITHM SESSION_VALUE NULL -GLOBAL_VALUE none +GLOBAL_VALUE zlib GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE none +DEFAULT_VALUE zlib VARIABLE_SCOPE GLOBAL VARIABLE_TYPE ENUM VARIABLE_COMMENT Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, or bzip2 diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 297ca0d162d..33eb352c42f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19774,7 +19774,7 @@ static MYSQL_SYSVAR_ENUM(compression_algorithm, innodb_compression_algorithm, /* We use here the largest number of supported compression method to enable all those methods that are available. Availability of compression method is verified on innodb_compression_algorithm_validate function. */ - PAGE_UNCOMPRESSED, + PAGE_ZLIB_ALGORITHM, &page_compression_algorithms_typelib); static MYSQL_SYSVAR_LONG(mtflush_threads, srv_mtflush_threads, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index a3f1d9c3c85..e9d42097fd0 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -21257,7 +21257,7 @@ static MYSQL_SYSVAR_ENUM(compression_algorithm, innodb_compression_algorithm, /* We use here the largest number of supported compression method to enable all those methods that are available. Availability of compression method is verified on innodb_compression_algorithm_validate function. */ - PAGE_UNCOMPRESSED, + PAGE_ZLIB_ALGORITHM, &page_compression_algorithms_typelib); static MYSQL_SYSVAR_LONG(mtflush_threads, srv_mtflush_threads, From 18ef02b04dfae21148c7397d088c7ffdfcd23c4e Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 10 Jan 2017 10:08:04 +0530 Subject: [PATCH 106/124] MDEV-4774 Strangeness with max_binlog_stmt_cache_size Settings Problem:- When setting max_binlog_stmt_cache_size=18446744073709547520 from either command line or .cnf file, server fails to start. Solution:- Added one more function eval_num_suffix_ull , which uses strtoull to get unsigned ulonglong from string. And getopt_ull calls this function instead of eval_num_suffix. Also changed previous eval_num_suffix to eval_num_suffix_ll to remain consistent. --- .../binlog_max_binlog_stmt_cache_size.result | 31 ++++++++ .../t/binlog_max_binlog_stmt_cache_size.opt | 1 + .../t/binlog_max_binlog_stmt_cache_size.test | 22 ++++++ mysys/my_getopt.c | 72 +++++++++++++++---- 4 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result create mode 100644 mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.opt create mode 100644 mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test diff --git a/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result b/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result new file mode 100644 index 00000000000..cf4d7004195 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result @@ -0,0 +1,31 @@ +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709547520 +set global max_binlog_stmt_cache_size= 18446744073709547520; +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709547520 +set global max_binlog_stmt_cache_size= 18446744073709547519; +Warnings: +Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709547519' +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709543424 +set global max_binlog_stmt_cache_size= 18446744073709551615; +Warnings: +Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709551615' +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709547520 +set global max_binlog_stmt_cache_size= 18446744073709551614; +Warnings: +Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709551614' +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709547520 +set global max_binlog_stmt_cache_size= 18446744073709551616; +ERROR 42000: Incorrect argument type to variable 'max_binlog_stmt_cache_size' +select @@max_binlog_stmt_cache_size; +@@max_binlog_stmt_cache_size +18446744073709547520 +set global max_binlog_stmt_cache_size= 18446744073709547520; diff --git a/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.opt b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.opt new file mode 100644 index 00000000000..c52ef14d5d0 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.opt @@ -0,0 +1 @@ +--max_binlog_stmt_cache_size=18446744073709547520 diff --git a/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test new file mode 100644 index 00000000000..f85eed3cea8 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test @@ -0,0 +1,22 @@ +source include/have_log_bin.inc; +select @@max_binlog_stmt_cache_size; + +--let $cache_size=`select @@max_binlog_stmt_cache_size;` + +set global max_binlog_stmt_cache_size= 18446744073709547520; +select @@max_binlog_stmt_cache_size; + +set global max_binlog_stmt_cache_size= 18446744073709547519; +select @@max_binlog_stmt_cache_size; + +set global max_binlog_stmt_cache_size= 18446744073709551615; +select @@max_binlog_stmt_cache_size; + +set global max_binlog_stmt_cache_size= 18446744073709551614; +select @@max_binlog_stmt_cache_size; + +--error ER_WRONG_TYPE_FOR_VAR +set global max_binlog_stmt_cache_size= 18446744073709551616; +select @@max_binlog_stmt_cache_size; + +--eval set global max_binlog_stmt_cache_size= $cache_size diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 2a4557118b0..e68a08ee735 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -895,15 +895,39 @@ my_bool getopt_compare_strings(register const char *s, register const char *t, /* function: eval_num_suffix + Transforms suffix like k/m/g to their real value. +*/ + +static inline long eval_num_suffix(char *suffix, int *error) +{ + long num= 1; + if (*suffix == 'k' || *suffix == 'K') + num*= 1024L; + else if (*suffix == 'm' || *suffix == 'M') + num*= 1024L * 1024L; + else if (*suffix == 'g' || *suffix == 'G') + num*= 1024L * 1024L * 1024L; + else if (*suffix) + { + *error= 1; + return 0; + } + return num; +} + +/* + function: eval_num_suffix_ll + Transforms a number with a suffix to real number. Suffix can be k|K for kilo, m|M for mega or g|G for giga. */ -static longlong eval_num_suffix(char *argument, int *error, char *option_name) +static longlong eval_num_suffix_ll(char *argument, + int *error, char *option_name) { char *endchar; longlong num; - DBUG_ENTER("eval_num_suffix"); + DBUG_ENTER("eval_num_suffix_ll"); *error= 0; @@ -916,23 +940,47 @@ static longlong eval_num_suffix(char *argument, int *error, char *option_name) *error= 1; DBUG_RETURN(0); } - if (*endchar == 'k' || *endchar == 'K') - num*= 1024L; - else if (*endchar == 'm' || *endchar == 'M') - num*= 1024L * 1024L; - else if (*endchar == 'g' || *endchar == 'G') - num*= 1024L * 1024L * 1024L; - else if (*endchar) - { + num*= eval_num_suffix(endchar, error); + if (*error) fprintf(stderr, "Unknown suffix '%c' used for variable '%s' (value '%s')\n", *endchar, option_name, argument); + DBUG_RETURN(num); +} + +/* + function: eval_num_suffix_ull + + Transforms a number with a suffix to positive Integer. Suffix can + be k|K for kilo, m|M for mega or g|G for giga. +*/ + +static ulonglong eval_num_suffix_ull(char *argument, + int *error, char *option_name) +{ + char *endchar; + ulonglong num; + DBUG_ENTER("eval_num_suffix_ull"); + + *error= 0; + errno= 0; + num= strtoull(argument, &endchar, 10); + if (errno == ERANGE) + { + my_getopt_error_reporter(ERROR_LEVEL, + "Incorrect integer value: '%s'", argument); *error= 1; DBUG_RETURN(0); } + num*= eval_num_suffix(endchar, error); + if (*error) + fprintf(stderr, + "Unknown suffix '%c' used for variable '%s' (value '%s')\n", + *endchar, option_name, argument); DBUG_RETURN(num); } + /* function: getopt_ll @@ -946,7 +994,7 @@ static longlong eval_num_suffix(char *argument, int *error, char *option_name) static longlong getopt_ll(char *arg, const struct my_option *optp, int *err) { - longlong num=eval_num_suffix(arg, err, (char*) optp->name); + longlong num=eval_num_suffix_ll(arg, err, (char*) optp->name); return getopt_ll_limit_value(num, optp, NULL); } @@ -1023,7 +1071,7 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err) { - ulonglong num= eval_num_suffix(arg, err, (char*) optp->name); + ulonglong num= eval_num_suffix_ull(arg, err, (char*) optp->name); return getopt_ull_limit_value(num, optp, NULL); } From 213fc700b64a38d64efceef2a2ef8de9748a8ce5 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Sat, 21 Jan 2017 00:56:33 +0530 Subject: [PATCH 107/124] MDEV-10232: Scalar result of subquery changes after adding an outer select stmt In a subquery, we don't have to maintain order Added a fix such that order is considered when there is a limit clause. --- mysql-test/r/subselect4.result | 12 ++++++++++++ mysql-test/t/subselect4.test | 10 ++++++++++ sql/sql_select.cc | 5 +++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 8b912e1bfe9..3783ba12db2 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2442,3 +2442,15 @@ i drop table t1, t2, t3; SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; +# +# MDEV-10232 Scalar result of subquery changes after adding an outer select stmt +# +create table t1(c1 int, c2 int, primary key(c2)); +insert into t1 values(2,1),(1,2); +select (select c1 from t1 group by c1,c2 order by c1 limit 1) as x; +x +1 +(select c1 from t1 group by c1,c2 order by c1 limit 1); +c1 +1 +drop table t1; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index cb102f8319e..253160c46ac 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -1999,3 +1999,13 @@ drop table t1, t2, t3; SET optimizer_switch= @@global.optimizer_switch; set @@tmp_table_size= @@global.tmp_table_size; + +--echo # +--echo # MDEV-10232 Scalar result of subquery changes after adding an outer select stmt +--echo # + +create table t1(c1 int, c2 int, primary key(c2)); +insert into t1 values(2,1),(1,2); +select (select c1 from t1 group by c1,c2 order by c1 limit 1) as x; +(select c1 from t1 group by c1,c2 order by c1 limit 1); +drop table t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1bd101bbe6f..e37c1b8c280 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1619,7 +1619,8 @@ JOIN::optimize_inner() to ORDER BY . There are three exceptions: - if skip_sort_order is set (see above), then we can simply skip GROUP BY; - - if we are in a subquery, we don't have to maintain order + - if we are in a subquery, we don't have to maintain order unless there + is a limit clause in the subquery. - we can only rewrite ORDER BY if the ORDER BY fields are 'compatible' with the GROUP BY ones, i.e. either one is a prefix of another. We only check if the ORDER BY is a prefix of GROUP BY. In this case @@ -1631,7 +1632,7 @@ JOIN::optimize_inner() if (!order || test_if_subpart(group_list, order)) { if (skip_sort_order || - select_lex->master_unit()->item) // This is a subquery + (select_lex->master_unit()->item && select_limit == HA_POS_ERROR)) // This is a subquery order= NULL; else order= group_list; From b7b4c332c0869676ef69276ddaef4ac4521cb04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Sun, 22 Jan 2017 08:44:04 +0200 Subject: [PATCH 108/124] MDEV-11614: Syslog messages: "InnoDB: Log sequence number at the start 759654123 and the end 0 do not match." For page compressed and encrypted tables log sequence number at end is not stored, thus disable this message for them. --- storage/innobase/buf/buf0buf.cc | 21 +++++++++++++-------- storage/xtradb/buf/buf0buf.cc | 21 +++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 7a8bcd1b9d0..ef120b8409f 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2013, 2017, MariaDB Corporation. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -642,8 +642,12 @@ buf_page_is_corrupted( ulint checksum_field2; ulint space_id = mach_read_from_4( read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + ulint page_type = mach_read_from_4( + read_buf + FIL_PAGE_TYPE); + bool no_checksum = (page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); - bool page_encrypted = false; + /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true @@ -651,10 +655,15 @@ buf_page_is_corrupted( if (crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED && fil_page_is_encrypted(read_buf)) { - page_encrypted = true; + no_checksum = true; } - if (!page_encrypted && !zip_size + /* Return early if there is no checksum or END_LSN */ + if (no_checksum) { + return (FALSE); + } + + if (!no_checksum && !zip_size && memcmp(read_buf + FIL_PAGE_LSN + 4, read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) { @@ -713,10 +722,6 @@ buf_page_is_corrupted( return(!page_zip_verify_checksum(read_buf, zip_size)); } - if (page_encrypted) { - return (FALSE); - } - checksum_field1 = mach_read_from_4( read_buf + FIL_PAGE_SPACE_OR_CHKSUM); diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index e859301a38f..65c4e734968 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2013, 2017, MariaDB Corporation. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -707,8 +707,12 @@ buf_page_is_corrupted( ulint checksum_field2; ulint space_id = mach_read_from_4( read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + ulint page_type = mach_read_from_4( + read_buf + FIL_PAGE_TYPE); + bool no_checksum = (page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); - bool page_encrypted = false; + /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true @@ -716,10 +720,15 @@ buf_page_is_corrupted( if (crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED && fil_page_is_encrypted(read_buf)) { - page_encrypted = true; + no_checksum = true; } - if (!page_encrypted && !zip_size + /* Return early if there is no checksum or END_LSN */ + if (no_checksum) { + return (FALSE); + } + + if (!no_checksum && !zip_size && memcmp(read_buf + FIL_PAGE_LSN + 4, read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) { @@ -778,10 +787,6 @@ buf_page_is_corrupted( return(!page_zip_verify_checksum(read_buf, zip_size)); } - if (page_encrypted) { - return (FALSE); - } - checksum_field1 = mach_read_from_4( read_buf + FIL_PAGE_SPACE_OR_CHKSUM); From 10b1f4dd093cb2b21aa9ed09dc453bc52d028b3d Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 23 Jan 2017 13:32:57 +1100 Subject: [PATCH 109/124] MDEV-11866: ANALYZE FORMAT=JSON not predicatable for r_total_time_ms/r_buffer_size [0-9]*[.]?[0-9]* wasn't a sufficient regex to cover the %lg used in Json_writer::add_double. Exponent formats where missed. Here we normalize all the replace_regex expressions for ANALYZE FORMAT=JSON into one include file. Signed-off-by: Daniel Black --- mysql-test/include/analyze-format.inc | 3 ++ mysql-test/r/analyze_format_json.result | 50 +++++++++---------- mysql-test/t/analyze_format_json.test | 38 +++++++------- mysql-test/t/analyze_stmt_orderby.test | 18 +++---- mysql-test/t/explain_json.test | 10 ++-- .../t/explain_json_format_partitions.test | 6 +-- mysql-test/t/subselect_cache.test | 4 +- 7 files changed, 66 insertions(+), 63 deletions(-) create mode 100644 mysql-test/include/analyze-format.inc diff --git a/mysql-test/include/analyze-format.inc b/mysql-test/include/analyze-format.inc new file mode 100644 index 00000000000..65e61b81582 --- /dev/null +++ b/mysql-test/include/analyze-format.inc @@ -0,0 +1,3 @@ +# The time on ANALYSE FORMAT=JSON is rather variable + +--replace_regex /("(r_total_time_ms|r_buffer_size)": )[^, \n]*/\1"REPLACED"/ diff --git a/mysql-test/r/analyze_format_json.result b/mysql-test/r/analyze_format_json.result index 69930bc0215..78892711dc4 100644 --- a/mysql-test/r/analyze_format_json.result +++ b/mysql-test/r/analyze_format_json.result @@ -487,14 +487,14 @@ ANALYZE "query_block": { "select_id": 1, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "having_condition": "(TOP > a)", "filesort": { "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "r_used_priority_queue": false, "r_output_rows": 0, - "volatile parameter": "REPLACED", + "r_buffer_size": "REPLACED", "temporary_table": { "table": { "table_name": "t2", @@ -502,7 +502,7 @@ ANALYZE "r_loops": 1, "rows": 256, "r_rows": 256, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 } @@ -517,13 +517,13 @@ ANALYZE "query_block": { "select_id": 1, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filesort": { "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "r_used_priority_queue": false, "r_output_rows": 256, - "volatile parameter": "REPLACED", + "r_buffer_size": "REPLACED", "temporary_table": { "table": { "table_name": "t2", @@ -531,7 +531,7 @@ ANALYZE "r_loops": 1, "rows": 256, "r_rows": 256, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 } @@ -557,13 +557,13 @@ ANALYZE "query_block": { "select_id": 1, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filesort": { "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "r_used_priority_queue": false, "r_output_rows": 256, - "volatile parameter": "REPLACED", + "r_buffer_size": "REPLACED", "temporary_table": { "table": { "table_name": "t2", @@ -571,7 +571,7 @@ ANALYZE "r_loops": 1, "rows": 256, "r_rows": 256, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 } @@ -593,14 +593,14 @@ ANALYZE "query_block": { "select_id": 1, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", "access_type": "ALL", "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 }, @@ -612,7 +612,7 @@ ANALYZE "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 }, @@ -625,14 +625,14 @@ ANALYZE "query_block": { "select_id": 2, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "table": { "table_name": "t1", "access_type": "ALL", "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 } @@ -646,7 +646,7 @@ ANALYZE "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 }, @@ -678,19 +678,19 @@ ANALYZE "query_block": { "select_id": 1, "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filesort": { "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "r_used_priority_queue": false, "r_output_rows": 0, - "volatile parameter": "REPLACED", + "r_buffer_size": "REPLACED", "filesort": { "r_loops": 1, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "r_used_priority_queue": false, "r_output_rows": 0, - "volatile parameter": "REPLACED", + "r_buffer_size": "REPLACED", "temporary_table": { "temporary_table": { "table": { @@ -699,7 +699,7 @@ ANALYZE "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 100 }, @@ -710,7 +710,7 @@ ANALYZE "r_loops": 1, "rows": 2, "r_rows": 2, - "volatile parameter": "REPLACED", + "r_total_time_ms": "REPLACED", "filtered": 100, "r_filtered": 0, "attached_condition": "(t3.f3 in (1,2))" diff --git a/mysql-test/t/analyze_format_json.test b/mysql-test/t/analyze_format_json.test index 807e02d2334..88a907718d9 100644 --- a/mysql-test/t/analyze_format_json.test +++ b/mysql-test/t/analyze_format_json.test @@ -9,34 +9,34 @@ create table t0 (a int); INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); --echo # r_filtered=30%, because 3 rows match: 0,1,2 ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t0 where a<3; create table t1 (a int, b int, c int, key(a)); insert into t1 select A.a*10 + B.a, A.a*10 + B.a, A.a*10 + B.a from t0 A, t0 B; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze select * from t0, t1 where t1.a=t0.a and t0.a > 9; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t0, t1 where t1.a=t0.a and t0.a > 9; analyze select * from t0, t1 where t1.a=t0.a and t1.b<4; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t0, t1 where t1.a=t0.a and t1.b<4; analyze select * from t1 tbl1, t1 tbl2 where tbl1.b<2 and tbl2.b>5; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 tbl1, t1 tbl2 where tbl1.b<20 and tbl2.b<60 and tbl1.c > tbl2.c; @@ -53,7 +53,7 @@ insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t2 (a int, key(a)); insert into t2 values (0),(1); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 straight_join t2 force index(a) where t2.a=t1.a; drop table t1,t2; @@ -69,7 +69,7 @@ select database(); connect (con1,localhost,root,,*NO-ONE*); connection con1; select database(); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from test.t1 where t1.a<5; disconnect con1; connection default; @@ -91,15 +91,15 @@ create table t1 (pk int primary key); insert into t1 select a from t3; alter table t1 add b int; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json update t1 set b=pk; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 where pk < 10 and b > 4; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json delete from t1 where pk < 10 and b > 4; @@ -127,7 +127,7 @@ create table t2 (key1 int, key2 int, key3 int, key4 int, col1 int, insert into t2 select a,a,a,a,a from t3; insert into t2 select 15,15,15,15,15 from t4; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1, t2 where (t2.key1 between t1.lb1 and t1.rb1) and (t2.key2 between t1.lb2 and t1.rb2) and @@ -144,7 +144,7 @@ INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 (a int); INSERT INTO t1 select * from t0; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json (select * from t1 tbl1 where a<5) union (select * from t1 tbl2 where a in (2,3)); drop table t0, t1; @@ -164,16 +164,16 @@ create table t2 ( ); insert into t2 select A.a*1000 + B.a, A.a*1000 + B.a from t0 A, t1 B; --echo # normal HAVING ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc analyze format=json select a, max(b) as TOP from t2 group by a having TOP > a; --echo # HAVING is always TRUE (not printed) ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc analyze format=json select a, max(b) as TOP from t2 group by a having 1<>2; --echo # HAVING is always FALSE (intercepted by message) ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc analyze format=json select a, max(b) as TOP from t2 group by a having 1=2; --echo # HAVING is absent ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc analyze format=json select a, max(b) as TOP from t2 group by a; drop table t0, t1, t2; @@ -186,7 +186,7 @@ INSERT INTO t1 VALUES (1),(2); CREATE TABLE t2 (b INT); INSERT INTO t2 VALUES (3),(4); ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc ANALYZE FORMAT=JSON SELECT STRAIGHT_JOIN * FROM t1, t2 WHERE b IN ( SELECT a FROM t1 ); drop table t1,t2; @@ -203,7 +203,7 @@ INSERT INTO t2 VALUES (2),(3); CREATE TABLE t3 (f3 INT) ENGINE=MyISAM; INSERT INTO t3 VALUES (3),(4); ---replace_regex /"(r_total_time_ms|r_buffer_size)": .*?,/"volatile parameter": "REPLACED",/ +--source include/analyze-format.inc ANALYZE FORMAT=JSON SELECT GROUP_CONCAT(f3) AS gc, ( SELECT MAX(f1) FROM t1, t2 WHERE f2 = f3 ) sq FROM t2, t3 diff --git a/mysql-test/t/analyze_stmt_orderby.test b/mysql-test/t/analyze_stmt_orderby.test index a40f34805d1..a1cfb58f31a 100644 --- a/mysql-test/t/analyze_stmt_orderby.test +++ b/mysql-test/t/analyze_stmt_orderby.test @@ -22,7 +22,7 @@ explain update t2 set b=b+1 order by b limit 5; explain format=json update t2 set b=b+1 order by b limit 5; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json update t2 set b=b+1 order by b limit 5; @@ -33,7 +33,7 @@ explain update t2 set a=a+1 where a<10; explain format=json update t2 set a=a+1 where a<10; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json update t2 set a=a+1 where a<10; @@ -44,7 +44,7 @@ explain delete from t2 order by b limit 5; explain format=json delete from t2 order by b limit 5; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json delete from t2 order by b limit 5; @@ -55,7 +55,7 @@ explain select * from t0,t2 where t2.a=t0.a order by t2.b limit 4; explain format=json select * from t0,t2 where t2.a=t0.a order by t2.b limit 4; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t0,t2 where t2.a=t0.a order by t2.b limit 4; @@ -67,7 +67,7 @@ explain select * from t0,t2 where t2.a=t0.a order by t0.a limit 4; explain format=json select * from t0,t2 where t2.a=t0.a order by t0.a limit 4; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t0,t2 where t2.a=t0.a order by t0.a limit 4; @@ -86,7 +86,7 @@ select c.a from t0 a, t0 b, t0 c; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select MAX(b) from t2 where mod(a,2)=0 group by c; @@ -115,7 +115,7 @@ drop table t3; create table t3 (a int, b int); insert into t3 select a, 123 from t0; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select distinct max(t3.b) Q from t0, t3 where t0.a=t3.a group by t0.a order by null; @@ -136,7 +136,7 @@ insert into t6 values (0, 0), (1, 1), (2, 1), (3, 1), (4, 1); insert into t7 values (3, 3), (2, 2), (1, 1); --echo # TODO: This ANALYZE output doesn't make it clear what is used for what. ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select count(distinct t5.b) as sum from t5, t6 where t5.a=t6.a and t6.b > 0 and t5.a <= 5 @@ -168,7 +168,7 @@ explain select col1 f1, col2 f2, col1 f3 from t2 group by f1; analyze select col1 f1, col2 f2, col1 f3 from t2 group by f1; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ /"r_buffer_size": "[^"]+"/"r_buffer_size": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select col1 f1, col2 f2, col1 f3 from t2 group by f1; drop table t2; diff --git a/mysql-test/t/explain_json.test b/mysql-test/t/explain_json.test index 153d85359c9..2ca91c1f200 100644 --- a/mysql-test/t/explain_json.test +++ b/mysql-test/t/explain_json.test @@ -219,7 +219,7 @@ create table t1 (a int, b int, c int, d int, key(a,b,c)); insert into t1 select A.a, B.a, C.a, D.a from t2 A, t2 B, t2 C, t2 D; explain select count(distinct b) from t1 group by a; explain format=json select count(distinct b) from t1 group by a; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select count(distinct b) from t1 group by a; drop table t1,t2; @@ -342,7 +342,7 @@ explain select * from t1 left join t2 on t2.pk > 10 and t2.pk < 0; explain format=json select * from t1 left join t2 on t2.pk > 10 and t2.pk < 0; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 left join t2 on t2.pk > 10 and t2.pk < 0; @@ -351,7 +351,7 @@ explain select * from t1 left join t2 on t2.pk=t1.a where t2.pk is null; explain format=json select * from t1 left join t2 on t2.pk=t1.a where t2.pk is null; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 left join t2 on t2.pk=t1.a where t2.pk is null; @@ -360,7 +360,7 @@ explain select distinct t1.a from t1 join t2 on t2.pk=t1.a; explain format=json select distinct t1.a from t1 join t2 on t2.pk=t1.a; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select distinct t1.a from t1 join t2 on t2.pk=t1.a; drop table t1,t2; @@ -386,7 +386,7 @@ explain select * from t3,t4 where t3.a=t4.a and (t4.b+1 <= t3.b+1); explain format=json select * from t3,t4 where t3.a=t4.a and (t4.b+1 <= t3.b+1); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t3,t4 where t3.a=t4.a and (t4.b+1 <= t3.b+1); set optimizer_switch=@tmp_optimizer_switch; diff --git a/mysql-test/t/explain_json_format_partitions.test b/mysql-test/t/explain_json_format_partitions.test index f3567797019..4c7d3f165d1 100644 --- a/mysql-test/t/explain_json_format_partitions.test +++ b/mysql-test/t/explain_json_format_partitions.test @@ -8,10 +8,10 @@ create table t1 ( insert into t1 select a from t2; explain partitions select * from t1 where a in (2,3,4); explain format=json select * from t1 where a in (2,3,4); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select * from t1 where a in (2,3,4); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json update t1 set a=a+10 where a in (2,3,4); ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json delete from t1 where a in (20,30,40); drop table t1,t2; diff --git a/mysql-test/t/subselect_cache.test b/mysql-test/t/subselect_cache.test index 21247541fb6..55da0000f13 100644 --- a/mysql-test/t/subselect_cache.test +++ b/mysql-test/t/subselect_cache.test @@ -24,10 +24,10 @@ select a, (select d from t2 where b=c) from t1; show status like "subquery_cache%"; show status like '%Handler_read%'; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select a, (select d from t2 where b=c) from t1; ---replace_regex /"r_total_time_ms": [0-9]*[.]?[0-9]*/"r_total_time_ms": "REPLACED"/ +--source include/analyze-format.inc analyze format=json select a, (select d from t2 where b=c), (select d from t2 where b=c union select 1 order by 1 limit 1) from t1; explain format=json From 15f46d517435f3570e2c788349637a06d818a619 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Mon, 23 Jan 2017 22:27:42 +0530 Subject: [PATCH 110/124] MDEV-7409 On RBR, extend the PROCESSLIST info to include at least the name of the recently used table When RBR is used, add the db name to db Field and table name to Status Field of the "SHOW FULL PROCESSLIST" command for SQL thread. --- mysql-test/suite/rpl/r/rpl_rbr_monitor.result | 62 ++++++++++++++ mysql-test/suite/rpl/t/rpl_rbr_monitor.test | 79 ++++++++++++++++++ sql/log_event.cc | 83 ++++++++++++++----- 3 files changed, 204 insertions(+), 20 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_rbr_monitor.result create mode 100644 mysql-test/suite/rpl/t/rpl_rbr_monitor.test diff --git a/mysql-test/suite/rpl/r/rpl_rbr_monitor.result b/mysql-test/suite/rpl/r/rpl_rbr_monitor.result new file mode 100644 index 00000000000..0aa9e7807c1 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_rbr_monitor.result @@ -0,0 +1,62 @@ +include/master-slave.inc +[connection master] +connection master; +create table t1(a int primary key); +connection slave; +SET GLOBAL debug_dbug="+d,should_sleep_for_mdev7409"; +select * from t1; +a +connection master; +insert into t1(a) values(1); +#monitoring write rows +connection slave; +SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; +db state +test Write_rows_log_event::write_row(-1) on table t1 +#monitoring update rows +connection master; +update t1 set a = a + 4194304 ; +connection slave; +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; +db state +test Update_rows_log_event::find_row(-1) on table t1 +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; +db state +test Update_rows_log_event::unpack_current_row(-1) on table t1 +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; +db state +test Update_rows_log_event::ha_update_row(-1) on table t1 +#monitoring delete rows +connection master; +delete from t1 where a>1; +connection slave; +SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; +db state +test Delete_rows_log_event::find_row(-1) on table t1 +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; +db state +test Delete_rows_log_event::ha_delete_row(-1) on table t1 +connection master; +drop table t1; +connection slave; +SET GLOBAL debug_dbug=""; +include/rpl_end.inc +connection server_2; +connection server_2; +connection server_2; +connection server_2; +connection server_1; +connection server_1; +connection server_1; +connection server_2; +connection server_1; +connection server_2; +connection server_2; +connection server_1; +connection server_1; diff --git a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test new file mode 100644 index 00000000000..becd6599124 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test @@ -0,0 +1,79 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc +--enable_connect_log + +--connection master +create table t1(a int primary key); +--save_master_pos + +--connection slave +--sync_with_master +SET GLOBAL debug_dbug="+d,should_sleep_for_mdev7409"; +select * from t1; + +--connection master +insert into t1(a) values(1); +--save_master_pos + +--echo #monitoring write rows +--connection slave + +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; +--sync_with_master + +--echo #monitoring update rows +--connection master +update t1 set a = a + 4194304 ; + +--connection slave +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; + +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; + +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; + +--source include/wait_condition.inc +--sync_with_master + +--echo #monitoring delete rows +--connection master +delete from t1 where a>1; + +--connection slave +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; + +let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; +--source include/wait_condition.inc +SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; + +--sync_with_master + +#CleanUp +--connection master +drop table t1; +--connection slave +SET GLOBAL debug_dbug=""; +--source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 21b5de2725e..05112712322 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -11765,18 +11765,27 @@ Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table != NULL); const char *tmp= thd->get_proc_info(); - const char *message= "Write_rows_log_event::write_row()"; + char *tmp_db= thd->db; + char *message, msg[128]; + my_snprintf(msg, sizeof(msg),"Write_rows_log_event::write_row() on table %s", + m_table->s->table_name.str); + thd->db= m_table->s->db.str; + message= msg; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Write_rows_log_event::write_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Write_rows_log_event::write_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); thd_proc_info(thd, tmp); + thd->db= tmp_db; if (error && !thd->is_error()) { @@ -12372,32 +12381,45 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) { int error; const char *tmp= thd->get_proc_info(); - const char *message= "Delete_rows_log_event::find_row()"; + char *tmp_db= thd->db; + char *message, msg[128]; + my_snprintf(msg, sizeof(msg),"Delete_rows_log_event::find_row() on table %s", + m_table->s->table_name.str); + thd->db= m_table->s->db.str; + message= msg; const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::find_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Delete_rows_log_event::find_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); if (!(error= find_row(rgi))) { /* Delete the record found, located in record[0] */ - message= "Delete_rows_log_event::ha_delete_row()"; + my_snprintf(msg, sizeof(msg),"Delete_rows_log_event::ha_delete_row() on table %s", + m_table->s->table_name.str); + message= msg; #ifdef WSREP_PROC_INFO snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::ha_delete_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Delete_rows_log_event::ha_delete_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; message= thd->wsrep_info; #endif thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); if (invoke_triggers && process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) @@ -12414,6 +12436,7 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) m_table->file->ha_index_or_rnd_end(); } thd_proc_info(thd, tmp); + thd->db= tmp_db; return error; } @@ -12532,17 +12555,26 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; const char *tmp= thd->get_proc_info(); - const char *message= "Update_rows_log_event::find_row()"; + char *tmp_db= thd->db; + char *message, msg[128]; DBUG_ASSERT(m_table != NULL); + my_snprintf(msg, sizeof(msg),"Update_rows_log_event::find_row() on table %s", + m_table->s->table_name.str); + thd->db= m_table->s->db.str; + message= msg; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::find_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Update_rows_log_event::find_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); + int error= find_row(rgi); if (error) { @@ -12553,6 +12585,7 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) if ((m_curr_row= m_curr_row_end)) unpack_current_row(rgi, &m_cols_ai); thd_proc_info(thd, tmp); + thd->db= tmp_db; return error; } @@ -12570,16 +12603,21 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; - message= "Update_rows_log_event::unpack_current_row()"; + my_snprintf(msg, sizeof(msg),"Update_rows_log_event::unpack_current_row() on table %s", + m_table->s->table_name.str); + message= msg; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::unpack_current_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Update_rows_log_event::unpack_current_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ /* this also updates m_curr_row_end */ thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); if ((error= unpack_current_row(rgi, &m_cols_ai))) goto err; @@ -12597,15 +12635,20 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif - message= "Update_rows_log_event::ha_update_row()"; + my_snprintf(msg, sizeof(msg),"Update_rows_log_event::ha_update_row() on table %s", + m_table->s->table_name.str); + message= msg; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::ha_update_row(%lld)", - (long long) wsrep_thd_trx_seqno(thd)); + "Update_rows_log_event::ha_update_row(%lld) on table %s", + (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); + DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ + my_sleep(500000); + };); if (invoke_triggers && process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) { @@ -12627,9 +12670,9 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) error= HA_ERR_GENERIC; // in case if error is not set yet - thd_proc_info(thd, tmp); - err: + thd_proc_info(thd, tmp); + thd->db= tmp_db; m_table->file->ha_index_or_rnd_end(); return error; } From 8725b35d897cfad6e55217ae80e7c387e8dfe8da Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 24 Jan 2017 01:25:50 +0530 Subject: [PATCH 111/124] MDEV-11108: Assertion `uniq_tuple_length_arg <= table->file->max_key_length()' failed in SJ_TMP_TABLE::create_sj_weedout_tmp_table Removed the assert from the if clause to the else clause. --- sql/opt_subselect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index a81b091461f..564a108c766 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -4044,13 +4044,13 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd) share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON); table->file= get_new_handler(share, &table->mem_root, share->db_type()); - DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length()); } else { share->db_plugin= ha_lock_engine(0, heap_hton); table->file= get_new_handler(share, &table->mem_root, share->db_type()); + DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length()); } if (!table->file) goto err; From 86ca1357b0637f76be4184b76cbe4b32080c10de Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 24 Jan 2017 19:26:16 +0530 Subject: [PATCH 112/124] Revert "MDEV-7409 On RBR, extend the PROCESSLIST info to include at least the name of the recently used table" This reverts commit 15f46d517435f3570e2c788349637a06d818a619. --- mysql-test/suite/rpl/r/rpl_rbr_monitor.result | 62 -------------- mysql-test/suite/rpl/t/rpl_rbr_monitor.test | 79 ------------------ sql/log_event.cc | 83 +++++-------------- 3 files changed, 20 insertions(+), 204 deletions(-) delete mode 100644 mysql-test/suite/rpl/r/rpl_rbr_monitor.result delete mode 100644 mysql-test/suite/rpl/t/rpl_rbr_monitor.test diff --git a/mysql-test/suite/rpl/r/rpl_rbr_monitor.result b/mysql-test/suite/rpl/r/rpl_rbr_monitor.result deleted file mode 100644 index 0aa9e7807c1..00000000000 --- a/mysql-test/suite/rpl/r/rpl_rbr_monitor.result +++ /dev/null @@ -1,62 +0,0 @@ -include/master-slave.inc -[connection master] -connection master; -create table t1(a int primary key); -connection slave; -SET GLOBAL debug_dbug="+d,should_sleep_for_mdev7409"; -select * from t1; -a -connection master; -insert into t1(a) values(1); -#monitoring write rows -connection slave; -SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; -db state -test Write_rows_log_event::write_row(-1) on table t1 -#monitoring update rows -connection master; -update t1 set a = a + 4194304 ; -connection slave; -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; -db state -test Update_rows_log_event::find_row(-1) on table t1 -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; -db state -test Update_rows_log_event::unpack_current_row(-1) on table t1 -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; -db state -test Update_rows_log_event::ha_update_row(-1) on table t1 -#monitoring delete rows -connection master; -delete from t1 where a>1; -connection slave; -SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; -db state -test Delete_rows_log_event::find_row(-1) on table t1 -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST -WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; -db state -test Delete_rows_log_event::ha_delete_row(-1) on table t1 -connection master; -drop table t1; -connection slave; -SET GLOBAL debug_dbug=""; -include/rpl_end.inc -connection server_2; -connection server_2; -connection server_2; -connection server_2; -connection server_1; -connection server_1; -connection server_1; -connection server_2; -connection server_1; -connection server_2; -connection server_2; -connection server_1; -connection server_1; diff --git a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test b/mysql-test/suite/rpl/t/rpl_rbr_monitor.test deleted file mode 100644 index becd6599124..00000000000 --- a/mysql-test/suite/rpl/t/rpl_rbr_monitor.test +++ /dev/null @@ -1,79 +0,0 @@ ---source include/have_innodb.inc ---source include/have_binlog_format_row.inc ---source include/master-slave.inc ---enable_connect_log - ---connection master -create table t1(a int primary key); ---save_master_pos - ---connection slave ---sync_with_master -SET GLOBAL debug_dbug="+d,should_sleep_for_mdev7409"; -select * from t1; - ---connection master -insert into t1(a) values(1); ---save_master_pos - ---echo #monitoring write rows ---connection slave - -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Write_rows_log_event::write_row(%) on table t1"; ---sync_with_master - ---echo #monitoring update rows ---connection master -update t1 set a = a + 4194304 ; - ---connection slave -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::find_row(%) on table t1"; - -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::unpack_current_row(%) on table t1"; - -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Update_rows_log_event::ha_update_row(%) on table t1"; - ---source include/wait_condition.inc ---sync_with_master - ---echo #monitoring delete rows ---connection master -delete from t1 where a>1; - ---connection slave -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db , state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::find_row(%) on table t1"; - -let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; ---source include/wait_condition.inc -SELECT db, state FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE DB = 'test' AND STATE LIKE "Delete_rows_log_event::ha_delete_row(%) on table t1"; - ---sync_with_master - -#CleanUp ---connection master -drop table t1; ---connection slave -SET GLOBAL debug_dbug=""; ---source include/rpl_end.inc diff --git a/sql/log_event.cc b/sql/log_event.cc index 05112712322..21b5de2725e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -11765,27 +11765,18 @@ Write_rows_log_event::do_exec_row(rpl_group_info *rgi) { DBUG_ASSERT(m_table != NULL); const char *tmp= thd->get_proc_info(); - char *tmp_db= thd->db; - char *message, msg[128]; - my_snprintf(msg, sizeof(msg),"Write_rows_log_event::write_row() on table %s", - m_table->s->table_name.str); - thd->db= m_table->s->db.str; - message= msg; + const char *message= "Write_rows_log_event::write_row()"; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Write_rows_log_event::write_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str); + "Write_rows_log_event::write_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); int error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT); thd_proc_info(thd, tmp); - thd->db= tmp_db; if (error && !thd->is_error()) { @@ -12381,45 +12372,32 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) { int error; const char *tmp= thd->get_proc_info(); - char *tmp_db= thd->db; - char *message, msg[128]; - my_snprintf(msg, sizeof(msg),"Delete_rows_log_event::find_row() on table %s", - m_table->s->table_name.str); - thd->db= m_table->s->db.str; - message= msg; + const char *message= "Delete_rows_log_event::find_row()"; const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; DBUG_ASSERT(m_table != NULL); #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::find_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; + "Delete_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); if (!(error= find_row(rgi))) { /* Delete the record found, located in record[0] */ - my_snprintf(msg, sizeof(msg),"Delete_rows_log_event::ha_delete_row() on table %s", - m_table->s->table_name.str); - message= msg; + message= "Delete_rows_log_event::ha_delete_row()"; #ifdef WSREP_PROC_INFO snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Delete_rows_log_event::ha_delete_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; + "Delete_rows_log_event::ha_delete_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); if (invoke_triggers && process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) @@ -12436,7 +12414,6 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi) m_table->file->ha_index_or_rnd_end(); } thd_proc_info(thd, tmp); - thd->db= tmp_db; return error; } @@ -12555,26 +12532,17 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) const bool invoke_triggers= slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers; const char *tmp= thd->get_proc_info(); - char *tmp_db= thd->db; - char *message, msg[128]; + const char *message= "Update_rows_log_event::find_row()"; DBUG_ASSERT(m_table != NULL); - my_snprintf(msg, sizeof(msg),"Update_rows_log_event::find_row() on table %s", - m_table->s->table_name.str); - thd->db= m_table->s->db.str; - message= msg; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::find_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; + "Update_rows_log_event::find_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); - int error= find_row(rgi); if (error) { @@ -12585,7 +12553,6 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) if ((m_curr_row= m_curr_row_end)) unpack_current_row(rgi, &m_cols_ai); thd_proc_info(thd, tmp); - thd->db= tmp_db; return error; } @@ -12603,21 +12570,16 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) store_record(m_table,record[1]); m_curr_row= m_curr_row_end; - my_snprintf(msg, sizeof(msg),"Update_rows_log_event::unpack_current_row() on table %s", - m_table->s->table_name.str); - message= msg; + message= "Update_rows_log_event::unpack_current_row()"; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::unpack_current_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; + "Update_rows_log_event::unpack_current_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ /* this also updates m_curr_row_end */ thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); if ((error= unpack_current_row(rgi, &m_cols_ai))) goto err; @@ -12635,20 +12597,15 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength); #endif - my_snprintf(msg, sizeof(msg),"Update_rows_log_event::ha_update_row() on table %s", - m_table->s->table_name.str); - message= msg; + message= "Update_rows_log_event::ha_update_row()"; #ifdef WSREP_PROC_INFO my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1, - "Update_rows_log_event::ha_update_row(%lld) on table %s", - (long long) wsrep_thd_trx_seqno(thd), m_table->s->table_name.str) ; + "Update_rows_log_event::ha_update_row(%lld)", + (long long) wsrep_thd_trx_seqno(thd)); message= thd->wsrep_info; #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - DBUG_EXECUTE_IF("should_sleep_for_mdev7409",{ - my_sleep(500000); - };); if (invoke_triggers && process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) { @@ -12670,9 +12627,9 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) error= HA_ERR_GENERIC; // in case if error is not set yet -err: thd_proc_info(thd, tmp); - thd->db= tmp_db; + +err: m_table->file->ha_index_or_rnd_end(); return error; } From ee3febae044e8258c1a33d5ef08ff4eb55c3d0f5 Mon Sep 17 00:00:00 2001 From: iangilfillan Date: Thu, 26 Jan 2017 13:51:03 +0200 Subject: [PATCH 113/124] Minor typo --- scripts/mariadb-service-convert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mariadb-service-convert b/scripts/mariadb-service-convert index 42654f68420..83c92659144 100755 --- a/scripts/mariadb-service-convert +++ b/scripts/mariadb-service-convert @@ -16,7 +16,7 @@ # # PURPOSE: # -# Used to generate a mariadb.service file based on the curent mysql/maridb settings +# Used to generate a mariadb.service file based on the current mysql/mariadb settings # # This is to assist distro maintainers in migrating to systemd service definations from # a user mysqld_safe settings in the my.cnf files. From 49fe9bad01cbd7f66efd52171c4234636ba61276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 25 Jan 2017 15:11:46 +0200 Subject: [PATCH 114/124] MDEV-11814 Refuse innodb_read_only startup if crash recovery is needed recv_scan_log_recs(): Remember if redo log apply is needed, even if starting up in innodb_read_only mode. recv_recovery_from_checkpoint_start_func(): Refuse innodb_read_only startup if redo log apply is needed. --- .../include/kill_and_restart_mysqld.inc | 19 ++ mysql-test/include/kill_mysqld.inc | 7 + mysql-test/include/search_pattern_in_file.inc | 41 ++-- mysql-test/include/start_mysqld.inc | 9 +- .../suite/innodb/r/log_file_size.result | 35 ++++ mysql-test/suite/innodb/t/log_file_size.test | 185 ++++++++++++++++++ storage/innobase/log/log0recv.cc | 14 +- storage/xtradb/log/log0recv.cc | 15 +- 8 files changed, 299 insertions(+), 26 deletions(-) create mode 100644 mysql-test/include/kill_and_restart_mysqld.inc create mode 100644 mysql-test/include/kill_mysqld.inc create mode 100644 mysql-test/suite/innodb/r/log_file_size.result create mode 100644 mysql-test/suite/innodb/t/log_file_size.test diff --git a/mysql-test/include/kill_and_restart_mysqld.inc b/mysql-test/include/kill_and_restart_mysqld.inc new file mode 100644 index 00000000000..f2ac9b504d2 --- /dev/null +++ b/mysql-test/include/kill_and_restart_mysqld.inc @@ -0,0 +1,19 @@ +--let $_server_id= `SELECT @@server_id` +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect + +if ($restart_parameters) +{ + --echo # Kill and restart: $restart_parameters + --exec echo "restart: $restart_parameters" > $_expect_file_name +} +if (!$restart_parameters) +{ + --echo # Kill and restart + --exec echo "restart" > $_expect_file_name +} + +--shutdown_server 0 +--source include/wait_until_disconnected.inc +--enable_reconnect +--source include/wait_until_connected_again.inc +--disable_reconnect diff --git a/mysql-test/include/kill_mysqld.inc b/mysql-test/include/kill_mysqld.inc new file mode 100644 index 00000000000..86ee048a0f1 --- /dev/null +++ b/mysql-test/include/kill_mysqld.inc @@ -0,0 +1,7 @@ +--let $_server_id= `SELECT @@server_id` +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect + +--echo # Kill the server +--exec echo "wait" > $_expect_file_name +--shutdown_server 0 +--source include/wait_until_disconnected.inc diff --git a/mysql-test/include/search_pattern_in_file.inc b/mysql-test/include/search_pattern_in_file.inc index 84237026ed0..f77a7c60916 100644 --- a/mysql-test/include/search_pattern_in_file.inc +++ b/mysql-test/include/search_pattern_in_file.inc @@ -60,25 +60,36 @@ perl; use strict; - my $search_file= $ENV{'SEARCH_FILE'} or die "SEARCH_FILE not set"; + die "SEARCH_FILE not set" unless $ENV{'SEARCH_FILE'}; + my @search_files= glob($ENV{'SEARCH_FILE'}); my $search_pattern= $ENV{'SEARCH_PATTERN'} or die "SEARCH_PATTERN not set"; my $search_range= $ENV{'SEARCH_RANGE'}; - my $file_content; + my $content; $search_range= 50000 unless $search_range =~ /-?[0-9]+/; - open(FILE, '<', $search_file) or die("Unable to open '$search_file': $!\n"); - if ($search_range >= 0) { - read(FILE, $file_content, $search_range, 0); - } else { - my $size= -s $search_file; - $search_range = -$size if $size > -$search_range; - seek(FILE, $search_range, 2); - read(FILE, $file_content, -$search_range, 0); + foreach my $search_file (@search_files) { + open(FILE, '<', $search_file) or die("Unable to open '$search_file': $!\n"); + my $file_content; + if ($search_range >= 0) { + read(FILE, $file_content, $search_range, 0); + } else { + my $size= -s $search_file; + $search_range = -$size if $size > -$search_range; + seek(FILE, $search_range, 2); + read(FILE, $file_content, -$search_range, 0); + } + close(FILE); + $content.= $file_content; } - close(FILE); - $search_file =~ s{^.*?([^/\\]+)$}{$1}; - if ($file_content =~ m{$search_pattern}) { - print "FOUND /$search_pattern/ in $search_file\n" + $ENV{'SEARCH_FILE'} =~ s{^.*?([^/\\]+)$}{$1}; + if ($content =~ m{$search_pattern}) { + die "FOUND /$search_pattern/ in $ENV{'SEARCH_FILE'}\n" + if $ENV{SEARCH_ABORT} eq 'FOUND'; + print "FOUND /$search_pattern/ in $ENV{'SEARCH_FILE'}\n" + unless defined $ENV{SEARCH_ABORT}; } else { - print "NOT FOUND /$search_pattern/ in $search_file\n" + die "NOT FOUND /$search_pattern/ in $ENV{'SEARCH_FILE'}\n" + if $ENV{SEARCH_ABORT} eq 'NOT FOUND'; + print "NOT FOUND /$search_pattern/ in $ENV{'SEARCH_FILE'}\n" + unless defined $ENV{SEARCH_ABORT}; } EOF diff --git a/mysql-test/include/start_mysqld.inc b/mysql-test/include/start_mysqld.inc index 983c566821e..e31f26aad8c 100644 --- a/mysql-test/include/start_mysqld.inc +++ b/mysql-test/include/start_mysqld.inc @@ -1,7 +1,14 @@ # Include this script only after using shutdown_mysqld.inc # where $_expect_file_name was initialized. # Write file to make mysql-test-run.pl start up the server again ---exec echo "restart" > $_expect_file_name +if ($restart_parameters) +{ + --exec echo "restart: $restart_parameters" > $_expect_file_name +} +if (!$restart_parameters) +{ + --exec echo "restart" > $_expect_file_name +} # Turn on reconnect --enable_reconnect diff --git a/mysql-test/suite/innodb/r/log_file_size.result b/mysql-test/suite/innodb/r/log_file_size.result new file mode 100644 index 00000000000..1519f02a8c8 --- /dev/null +++ b/mysql-test/suite/innodb/r/log_file_size.result @@ -0,0 +1,35 @@ +call mtr.add_suppression("InnoDB: Resizing redo log"); +call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +BEGIN; +INSERT INTO t1 VALUES (42); +# Kill and restart: --innodb-log-file-size=6M +SELECT * FROM t1; +a +INSERT INTO t1 VALUES (42); +BEGIN; +DELETE FROM t1; +# Kill and restart: --innodb-log-files-in-group=3 --innodb-log-file-size=5M +SELECT * FROM t1; +a +42 +INSERT INTO t1 VALUES (123); +BEGIN; +DELETE FROM t1; +# Kill the server +--innodb-force-recovery-crash=1 +--innodb-force-recovery-crash=3 +--innodb-force-recovery-crash=4 +--innodb-force-recovery-crash=5 +--innodb-force-recovery-crash=6 +--innodb-force-recovery-crash=7 +--innodb-force-recovery-crash=8 +--innodb-force-recovery-crash=9 +--innodb-force-recovery-crash=10 +SELECT * FROM t1; +a +42 +123 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/log_file_size.test b/mysql-test/suite/innodb/t/log_file_size.test new file mode 100644 index 00000000000..95a7bcc143a --- /dev/null +++ b/mysql-test/suite/innodb/t/log_file_size.test @@ -0,0 +1,185 @@ +# Test resizing the InnoDB redo log. + +--source include/have_innodb.inc + +# Embedded server does not support crashing +--source include/not_embedded.inc +# Avoid CrashReporter popup on Mac +--source include/not_crashrep.inc +# innodb-force-recovery-crash needs debug +--source include/have_debug.inc + +if (`SELECT @@innodb_log_file_size = 1048576`) { + --skip Test requires innodb_log_file_size>1M. +} + +call mtr.add_suppression("InnoDB: Resizing redo log"); +call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); + +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +BEGIN; +INSERT INTO t1 VALUES (42); + +let $restart_parameters = --innodb-log-file-size=6M; +--source include/kill_and_restart_mysqld.inc + +SELECT * FROM t1; + +INSERT INTO t1 VALUES (42); +BEGIN; +DELETE FROM t1; + +let $restart_parameters = --innodb-log-files-in-group=3 --innodb-log-file-size=5M; +--source include/kill_and_restart_mysqld.inc + +SELECT * FROM t1; + +INSERT INTO t1 VALUES (123); + +let MYSQLD_DATADIR= `select @@datadir`; +let SEARCH_ABORT = NOT FOUND; +let SEARCH_FILE= $MYSQLTEST_VARDIR/log/my_restart.err; +let $args=--innodb --unknown-option --loose-console --core-file > $SEARCH_FILE 2>&1; +let $crash=--innodb --unknown-option --loose-console > $SEARCH_FILE 2>&1 --innodb-force-recovery-crash; + +BEGIN; +DELETE FROM t1; + +--source include/kill_mysqld.inc + +--error 2 +--exec $MYSQLD_CMD $args --innodb-log-group-home-dir=foo\;bar +let SEARCH_PATTERN= syntax error in innodb_log_group_home_dir; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--echo --innodb-force-recovery-crash=1 +--error 3 +--exec $MYSQLD_CMD $crash=1 +let SEARCH_PATTERN= InnoDB: Starting an apply batch of log records; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--echo --innodb-force-recovery-crash=3 +--error 3 +--exec $MYSQLD_CMD $crash=3 +let SEARCH_PATTERN= InnoDB: Starting an apply batch of log records; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--error 2 +--exec $MYSQLD_CMD $args --innodb-read-only +let SEARCH_PATTERN= InnoDB: innodb_read_only prevents crash recovery; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--echo --innodb-force-recovery-crash=4 +--error 3 +--exec $MYSQLD_CMD $crash=4 +let SEARCH_PATTERN= InnoDB: Starting an apply batch of log records; +--source include/search_pattern_in_file.inc +let SEARCH_PATTERN= InnoDB: Resizing redo log from 3\*[0-9]+ to 2\*[0-9]+ pages; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--echo --innodb-force-recovery-crash=5 +--error 3 +--exec $MYSQLD_CMD $crash=5 +let SEARCH_PATTERN= InnoDB: Starting an apply batch of log records; +--source include/search_pattern_in_file.inc +let SEARCH_PATTERN= InnoDB: Resizing redo log from 3\*[0-9]+ to 2\*[0-9]+ pages; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--error 2 +--exec $MYSQLD_CMD $args --innodb-read-only +let SEARCH_PATTERN= InnoDB: innodb_read_only prevents crash recovery; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--echo --innodb-force-recovery-crash=6 +--error 3 +--exec $MYSQLD_CMD $crash=6 +let SEARCH_PATTERN= InnoDB: Starting an apply batch of log records; +--source include/search_pattern_in_file.inc +let SEARCH_PATTERN= InnoDB: Resizing redo log from 3\*[0-9]+ to 2\*[0-9]+ pages; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--echo --innodb-force-recovery-crash=7 +--error 3 +--exec $MYSQLD_CMD $crash=7 +# this crashes right after deleting all log files +--remove_file $SEARCH_FILE + +--error 2 +--exec $MYSQLD_CMD $args --innodb-read-only +let SEARCH_PATTERN= InnoDB: Cannot create log files in read-only mode; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--echo --innodb-force-recovery-crash=8 +--error 3 +--exec $MYSQLD_CMD $crash=8 +let SEARCH_PATTERN= InnoDB: Setting log file .*ib_logfile[0-9]+ size to; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--echo --innodb-force-recovery-crash=9 +--error 3 +--exec $MYSQLD_CMD $crash=9 +let SEARCH_PATTERN= InnoDB: Setting log file .*ib_logfile[0-9]+ size to; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +# We should have perfectly synced files here. +# Rename the log files, and trigger an error in recovery. +--move_file $MYSQLD_DATADIR/ib_logfile101 $MYSQLD_DATADIR/ib_logfile0 +--move_file $MYSQLD_DATADIR/ib_logfile1 $MYSQLD_DATADIR/ib_logfile1_hidden +--error 2 +--exec $MYSQLD_CMD $args +let SEARCH_PATTERN= InnoDB: Only one log file found; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--move_file $MYSQLD_DATADIR/ib_logfile0 $MYSQLD_DATADIR/ib_logfile101 + +perl; +die unless open(FILE, ">$ENV{MYSQLD_DATADIR}/ib_logfile0"); +print FILE "garbage"; +close(FILE); +EOF +--error 2 +--exec $MYSQLD_CMD $args +let SEARCH_PATTERN= InnoDB: Log file .*ib_logfile0 size 7 is not a multiple of innodb_page_size; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--remove_file $MYSQLD_DATADIR/ib_logfile0 +--move_file $MYSQLD_DATADIR/ib_logfile101 $MYSQLD_DATADIR/ib_logfile0 + +perl; +die unless open(FILE, ">$ENV{MYSQLD_DATADIR}/ib_logfile1"); +print FILE "junkfill" x 131072; +close(FILE); +EOF + +--error 2 +--exec $MYSQLD_CMD $args +let SEARCH_PATTERN= InnoDB: Log file .*ib_logfile1 is of different size 1048576 bytes than other log files; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE +--remove_file $MYSQLD_DATADIR/ib_logfile1 +--move_file $MYSQLD_DATADIR/ib_logfile0 $MYSQLD_DATADIR/ib_logfile101 +--move_file $MYSQLD_DATADIR/ib_logfile1_hidden $MYSQLD_DATADIR/ib_logfile1 + +--echo --innodb-force-recovery-crash=10 +--error 3 +--exec $MYSQLD_CMD $crash=10 +let SEARCH_PATTERN= InnoDB: Setting log file .*ib_logfile[0-9]+ size to; +--source include/search_pattern_in_file.inc +let SEARCH_PATTERN= InnoDB: Renaming log file .*ib_logfile101 to .*ib_logfile0; +--source include/search_pattern_in_file.inc +--remove_file $SEARCH_FILE + +--let $restart_parameters= +--source include/start_mysqld.inc + +SELECT * FROM t1; +DROP TABLE t1; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index aed94d00834..e52448c87f6 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2806,11 +2806,10 @@ recv_scan_log_recs( recv_init_crash_recovery(); } else { - - ib_logf(IB_LOG_LEVEL_WARN, - "Recovery skipped, " - "--innodb-read-only set!"); - + ib_logf(IB_LOG_LEVEL_ERROR, + "innodb_read_only prevents" + " crash recovery"); + recv_needed_recovery = TRUE; return(TRUE); } } @@ -3227,6 +3226,11 @@ recv_recovery_from_checkpoint_start_func( /* Done with startup scan. Clear the flag. */ recv_log_scan_is_startup_type = FALSE; + + if (srv_read_only_mode && recv_needed_recovery) { + return(DB_READ_ONLY); + } + if (TYPE_CHECKPOINT) { /* NOTE: we always do a 'recovery' at startup, but only if there is something wrong we will print a message to the diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index 9e42fb5cc1c..a66172ac861 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -2,6 +2,7 @@ Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. +Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2895,11 +2896,10 @@ recv_scan_log_recs( recv_init_crash_recovery(); } else { - - ib_logf(IB_LOG_LEVEL_WARN, - "Recovery skipped, " - "--innodb-read-only set!"); - + ib_logf(IB_LOG_LEVEL_ERROR, + "innodb_read_only prevents" + " crash recovery"); + recv_needed_recovery = TRUE; return(TRUE); } } @@ -3323,6 +3323,11 @@ recv_recovery_from_checkpoint_start_func( /* Done with startup scan. Clear the flag. */ recv_log_scan_is_startup_type = FALSE; + + if (srv_read_only_mode && recv_needed_recovery) { + return(DB_READ_ONLY); + } + if (TYPE_CHECKPOINT) { /* NOTE: we always do a 'recovery' at startup, but only if there is something wrong we will print a message to the From afb461587c0b7dea2e5e70a165e8d4d437c3f964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 26 Jan 2017 14:05:00 +0200 Subject: [PATCH 115/124] MDEV-11915 Detect InnoDB system tablespace size mismatch early InnoDB would refuse to start up if there is a mismatch on the size of the system tablespace files. However, before this check is conducted, the system tablespace may already have been heavily modified. InnoDB should perform the size check as early as possible. recv_recovery_from_checkpoint_finish(): Move the recv_apply_hashed_log_recs() call to innobase_start_or_create_for_mysql(). innobase_start_or_create_for_mysql(): Test the mutex functionality before doing anything else. Use a compile_time_assert() for a sizeof() constraint. Check the size of the system tablespace as early as possible. --- storage/innobase/log/log0recv.cc | 9 -- storage/innobase/srv/srv0start.cc | 256 +++++++++++------------------- storage/xtradb/log/log0recv.cc | 9 -- storage/xtradb/srv/srv0start.cc | 251 +++++++++++------------------ 4 files changed, 184 insertions(+), 341 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e52448c87f6..70913bd49ce 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3381,15 +3381,6 @@ void recv_recovery_from_checkpoint_finish(void) /*======================================*/ { - /* Apply the hashed log records to the respective file pages */ - - if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { - - recv_apply_hashed_log_recs(TRUE); - } - - DBUG_PRINT("ib_log", ("apply completed")); - if (recv_needed_recovery) { trx_sys_print_mysql_master_log_pos(); trx_sys_print_mysql_binlog_offset(); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 5c3bee5e0b7..0e7d4b6c511 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -3,6 +3,7 @@ Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Percona Inc. +Copyright (c) 2013, 2017, MariaDB Corporation Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -1550,8 +1551,6 @@ innobase_start_or_create_for_mysql(void) ulint max_arch_log_no; #endif /* UNIV_LOG_ARCHIVE */ ulint sum_of_new_sizes; - ulint sum_of_data_file_sizes; - ulint tablespace_size_in_header; dberr_t err; unsigned i; ulint srv_n_log_files_found = srv_n_log_files; @@ -1564,6 +1563,19 @@ innobase_start_or_create_for_mysql(void) size_t dirnamelen; bool sys_datafiles_created = false; + /* Check that os_fast_mutexes work as expected */ + os_fast_mutex_init(PFS_NOT_INSTRUMENTED, &srv_os_test_mutex); + + ut_a(0 == os_fast_mutex_trylock(&srv_os_test_mutex)); + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_lock(&srv_os_test_mutex); + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_free(&srv_os_test_mutex); + high_level_read_only = srv_read_only_mode || srv_force_recovery > SRV_FORCE_NO_TRX_UNDO; @@ -1606,22 +1618,7 @@ innobase_start_or_create_for_mysql(void) #endif /* PAGE_ATOMIC_REF_COUNT */ ); - - if (sizeof(ulint) != sizeof(void*)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: size of InnoDB's ulint is %lu, " - "but size of void*\n", (ulong) sizeof(ulint)); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: is %lu. The sizes should be the same " - "so that on a 64-bit\n", - (ulong) sizeof(void*)); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: platforms you can allocate more than 4 GB " - "of memory.\n"); - } + compile_time_assert(sizeof(ulint) == sizeof(void*)); #ifdef UNIV_DEBUG ut_print_timestamp(stderr); @@ -2332,7 +2329,6 @@ files_checked: trx_sys_create(); if (create_new_db) { - ut_a(!srv_read_only_mode); mtr_start(&mtr); @@ -2446,24 +2442,89 @@ files_checked: LOG_CHECKPOINT, LSN_MAX, min_flushed_lsn, max_flushed_lsn); - if (err != DB_SUCCESS) { - - return(DB_ERROR); + if (err == DB_SUCCESS) { + /* Initialize the change buffer. */ + err = dict_boot(); } - /* Since the insert buffer init is in dict_boot, and the - insert buffer is needed in any disk i/o, first we call - dict_boot(). Note that trx_sys_init_at_db_start() only needs - to access space 0, and the insert buffer at this stage already - works for space 0. */ - - err = dict_boot(); - if (err != DB_SUCCESS) { return(err); } + if (!srv_read_only_mode) { + if (sum_of_new_sizes > 0) { + /* New data file(s) were added */ + mtr_start(&mtr); + fsp_header_inc_size(0, sum_of_new_sizes, &mtr); + mtr_commit(&mtr); + /* Immediately write the log record about + increased tablespace size to disk, so that it + is durable even if mysqld would crash + quickly */ + log_buffer_flush_to_disk(); + } + } + + const ulint tablespace_size_in_header + = fsp_header_get_tablespace_size(); + +#ifdef UNIV_DEBUG + /* buf_debug_prints = TRUE; */ +#endif /* UNIV_DEBUG */ + ulint sum_of_data_file_sizes = 0; + + for (ulint d = 0; d < srv_n_data_files; d++) { + sum_of_data_file_sizes += srv_data_file_sizes[d]; + } + + /* Compare the system tablespace file size to what is + stored in FSP_SIZE. In open_or_create_data_files() + we already checked that the file sizes match the + innodb_data_file_path specification. */ + if (srv_read_only_mode + || sum_of_data_file_sizes == tablespace_size_in_header) { + /* Do not complain about the size. */ + } else if (!srv_auto_extend_last_data_file + || sum_of_data_file_sizes + < tablespace_size_in_header) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Tablespace size stored in header is " ULINTPF + " pages, but the sum of data file sizes is " + ULINTPF " pages", + tablespace_size_in_header, + sum_of_data_file_sizes); + + if (srv_force_recovery == 0 + && sum_of_data_file_sizes + < tablespace_size_in_header) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot start InnoDB. The tail of" + " the system tablespace is" + " missing. Have you edited" + " innodb_data_file_path in my.cnf" + " in an inappropriate way, removing" + " data files from there?" + " You can set innodb_force_recovery=1" + " in my.cnf to force" + " a startup if you are trying to" + " recover a badly corrupt database."); + + return(DB_ERROR); + } + } + + /* This must precede recv_apply_hashed_log_recs(TRUE). */ ib_bh = trx_sys_init_at_db_start(); + + if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { + /* Apply the hashed log records to the + respective file pages, for the last batch of + recv_group_scan_log_recs(). */ + + recv_apply_hashed_log_recs(TRUE); + DBUG_PRINT("ib_log", ("apply completed")); + } + n_recovered_trx = UT_LIST_GET_LEN(trx_sys->rw_trx_list); /* The purge system needs to create the purge view and @@ -2610,20 +2671,8 @@ files_checked: trx_sys_file_format_tag_init(); } - if (!create_new_db && sum_of_new_sizes > 0) { - /* New data file(s) were added */ - mtr_start(&mtr); - - fsp_header_inc_size(0, sum_of_new_sizes, &mtr); - - mtr_commit(&mtr); - - /* Immediately write the log record about increased tablespace - size to disk, so that it is durable even if mysqld would crash - quickly */ - - log_buffer_flush_to_disk(); - } + ut_ad(err == DB_SUCCESS); + ut_a(sum_of_new_sizes != ULINT_UNDEFINED); #ifdef UNIV_LOG_ARCHIVE /* Archiving is always off under MySQL */ @@ -2766,125 +2815,6 @@ files_checked: buf_flush_page_cleaner_thread_started = true; } -#ifdef UNIV_DEBUG - /* buf_debug_prints = TRUE; */ -#endif /* UNIV_DEBUG */ - sum_of_data_file_sizes = 0; - - for (i = 0; i < srv_n_data_files; i++) { - sum_of_data_file_sizes += srv_data_file_sizes[i]; - } - - tablespace_size_in_header = fsp_header_get_tablespace_size(); - - if (!srv_read_only_mode - && !srv_auto_extend_last_data_file - && sum_of_data_file_sizes != tablespace_size_in_header) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: tablespace size" - " stored in header is %lu pages, but\n", - (ulong) tablespace_size_in_header); - ut_print_timestamp(stderr); - fprintf(stderr, - "InnoDB: the sum of data file sizes is %lu pages\n", - (ulong) sum_of_data_file_sizes); - - if (srv_force_recovery == 0 - && sum_of_data_file_sizes < tablespace_size_in_header) { - /* This is a fatal error, the tail of a tablespace is - missing */ - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot start InnoDB." - " The tail of the system tablespace is\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: missing. Have you edited" - " innodb_data_file_path in my.cnf in an\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: inappropriate way, removing" - " ibdata files from there?\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: You can set innodb_force_recovery=1" - " in my.cnf to force\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: a startup if you are trying" - " to recover a badly corrupt database.\n"); - - return(DB_ERROR); - } - } - - if (!srv_read_only_mode - && srv_auto_extend_last_data_file - && sum_of_data_file_sizes < tablespace_size_in_header) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: tablespace size stored in header" - " is %lu pages, but\n", - (ulong) tablespace_size_in_header); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: the sum of data file sizes" - " is only %lu pages\n", - (ulong) sum_of_data_file_sizes); - - if (srv_force_recovery == 0) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot start InnoDB. The tail of" - " the system tablespace is\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: missing. Have you edited" - " innodb_data_file_path in my.cnf in an\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: inappropriate way, removing" - " ibdata files from there?\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: You can set innodb_force_recovery=1" - " in my.cnf to force\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: a startup if you are trying to" - " recover a badly corrupt database.\n"); - - return(DB_ERROR); - } - } - - /* Check that os_fast_mutexes work as expected */ - os_fast_mutex_init(PFS_NOT_INSTRUMENTED, &srv_os_test_mutex); - - if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: pthread_mutex_trylock returns" - " an unexpected value on\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: success! Cannot continue.\n"); - exit(1); - } - - os_fast_mutex_unlock(&srv_os_test_mutex); - - os_fast_mutex_lock(&srv_os_test_mutex); - - os_fast_mutex_unlock(&srv_os_test_mutex); - - os_fast_mutex_free(&srv_os_test_mutex); - if (srv_print_verbose_log) { ib_logf(IB_LOG_LEVEL_INFO, "%s started; log sequence number " LSN_PF "", diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc index a66172ac861..e355c25318c 100644 --- a/storage/xtradb/log/log0recv.cc +++ b/storage/xtradb/log/log0recv.cc @@ -3478,15 +3478,6 @@ void recv_recovery_from_checkpoint_finish(void) /*======================================*/ { - /* Apply the hashed log records to the respective file pages */ - - if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { - - recv_apply_hashed_log_recs(TRUE); - } - - DBUG_PRINT("ib_log", ("apply completed")); - if (recv_needed_recovery) { trx_sys_print_mysql_master_log_pos(); trx_sys_print_mysql_binlog_offset(); diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index 9f426a8b513..a19f120a7d8 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -1609,8 +1609,6 @@ innobase_start_or_create_for_mysql(void) lsn_t max_arch_log_no = LSN_MAX; #endif /* UNIV_LOG_ARCHIVE */ ulint sum_of_new_sizes; - ulint sum_of_data_file_sizes; - ulint tablespace_size_in_header; dberr_t err; unsigned i; ulint srv_n_log_files_found = srv_n_log_files; @@ -1623,6 +1621,19 @@ innobase_start_or_create_for_mysql(void) size_t dirnamelen; bool sys_datafiles_created = false; + /* Check that os_fast_mutexes work as expected */ + os_fast_mutex_init(PFS_NOT_INSTRUMENTED, &srv_os_test_mutex); + + ut_a(0 == os_fast_mutex_trylock(&srv_os_test_mutex)); + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_lock(&srv_os_test_mutex); + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_free(&srv_os_test_mutex); + high_level_read_only = srv_read_only_mode || srv_force_recovery > SRV_FORCE_NO_TRX_UNDO; @@ -1665,22 +1676,7 @@ innobase_start_or_create_for_mysql(void) #endif /* PAGE_ATOMIC_REF_COUNT */ ); - - if (sizeof(ulint) != sizeof(void*)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: size of InnoDB's ulint is %lu, " - "but size of void*\n", (ulong) sizeof(ulint)); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: is %lu. The sizes should be the same " - "so that on a 64-bit\n", - (ulong) sizeof(void*)); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: platforms you can allocate more than 4 GB " - "of memory.\n"); - } + compile_time_assert(sizeof(ulint) == sizeof(void*)); /* If stacktrace is used we set up signal handler for SIGUSR2 signal here. If signal handler set fails we report that and disable @@ -2411,7 +2407,6 @@ files_checked: trx_sys_create(); if (create_new_db) { - ut_a(!srv_read_only_mode); init_log_online(); @@ -2493,25 +2488,92 @@ files_checked: min_flushed_lsn, max_flushed_lsn); if (err != DB_SUCCESS) { - - return(DB_ERROR); + return(err); } init_log_online(); - /* Since the insert buffer init is in dict_boot, and the - insert buffer is needed in any disk i/o, first we call - dict_boot(). Note that trx_sys_init_at_db_start() only needs - to access space 0, and the insert buffer at this stage already - works for space 0. */ - + /* Initialize the change buffer. */ err = dict_boot(); if (err != DB_SUCCESS) { return(err); } + if (!srv_read_only_mode) { + if (sum_of_new_sizes > 0) { + /* New data file(s) were added */ + mtr_start(&mtr); + fsp_header_inc_size(0, sum_of_new_sizes, &mtr); + mtr_commit(&mtr); + /* Immediately write the log record about + increased tablespace size to disk, so that it + is durable even if mysqld would crash + quickly */ + log_buffer_flush_to_disk(); + } + } + + const ulint tablespace_size_in_header + = fsp_header_get_tablespace_size(); + +#ifdef UNIV_DEBUG + /* buf_debug_prints = TRUE; */ +#endif /* UNIV_DEBUG */ + ulint sum_of_data_file_sizes = 0; + + for (ulint d = 0; d < srv_n_data_files; d++) { + sum_of_data_file_sizes += srv_data_file_sizes[d]; + } + + /* Compare the system tablespace file size to what is + stored in FSP_SIZE. In open_or_create_data_files() + we already checked that the file sizes match the + innodb_data_file_path specification. */ + if (srv_read_only_mode + || sum_of_data_file_sizes == tablespace_size_in_header) { + /* Do not complain about the size. */ + } else if (!srv_auto_extend_last_data_file + || sum_of_data_file_sizes + < tablespace_size_in_header) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Tablespace size stored in header is " ULINTPF + " pages, but the sum of data file sizes is " + ULINTPF " pages", + tablespace_size_in_header, + sum_of_data_file_sizes); + + if (srv_force_recovery == 0 + && sum_of_data_file_sizes + < tablespace_size_in_header) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot start InnoDB. The tail of" + " the system tablespace is" + " missing. Have you edited" + " innodb_data_file_path in my.cnf" + " in an inappropriate way, removing" + " data files from there?" + " You can set innodb_force_recovery=1" + " in my.cnf to force" + " a startup if you are trying to" + " recover a badly corrupt database."); + + return(DB_ERROR); + } + } + + /* This must precede recv_apply_hashed_log_recs(TRUE). */ ib_bh = trx_sys_init_at_db_start(); + + if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { + /* Apply the hashed log records to the + respective file pages, for the last batch of + recv_group_scan_log_recs(). */ + + recv_apply_hashed_log_recs(TRUE); + DBUG_PRINT("ib_log", ("apply completed")); + } + n_recovered_trx = UT_LIST_GET_LEN(trx_sys->rw_trx_list); /* The purge system needs to create the purge view and @@ -2664,20 +2726,8 @@ files_checked: trx_sys_file_format_tag_init(); } - if (!create_new_db && sum_of_new_sizes > 0) { - /* New data file(s) were added */ - mtr_start(&mtr); - - fsp_header_inc_size(0, sum_of_new_sizes, &mtr); - - mtr_commit(&mtr); - - /* Immediately write the log record about increased tablespace - size to disk, so that it is durable even if mysqld would crash - quickly */ - - log_buffer_flush_to_disk(); - } + ut_ad(err == DB_SUCCESS); + ut_a(sum_of_new_sizes != ULINT_UNDEFINED); #ifdef UNIV_LOG_ARCHIVE if (!srv_read_only_mode) { @@ -2826,125 +2876,6 @@ files_checked: buf_flush_lru_manager_thread_handle = os_thread_create(buf_flush_lru_manager_thread, NULL, NULL); buf_flush_lru_manager_thread_started = true; -#ifdef UNIV_DEBUG - /* buf_debug_prints = TRUE; */ -#endif /* UNIV_DEBUG */ - sum_of_data_file_sizes = 0; - - for (i = 0; i < srv_n_data_files; i++) { - sum_of_data_file_sizes += srv_data_file_sizes[i]; - } - - tablespace_size_in_header = fsp_header_get_tablespace_size(); - - if (!srv_read_only_mode - && !srv_auto_extend_last_data_file - && sum_of_data_file_sizes != tablespace_size_in_header) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: tablespace size" - " stored in header is %lu pages, but\n", - (ulong) tablespace_size_in_header); - ut_print_timestamp(stderr); - fprintf(stderr, - "InnoDB: the sum of data file sizes is %lu pages\n", - (ulong) sum_of_data_file_sizes); - - if (srv_force_recovery == 0 - && sum_of_data_file_sizes < tablespace_size_in_header) { - /* This is a fatal error, the tail of a tablespace is - missing */ - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot start InnoDB." - " The tail of the system tablespace is\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: missing. Have you edited" - " innodb_data_file_path in my.cnf in an\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: inappropriate way, removing" - " ibdata files from there?\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: You can set innodb_force_recovery=1" - " in my.cnf to force\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: a startup if you are trying" - " to recover a badly corrupt database.\n"); - - return(DB_ERROR); - } - } - - if (!srv_read_only_mode - && srv_auto_extend_last_data_file - && sum_of_data_file_sizes < tablespace_size_in_header) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: tablespace size stored in header" - " is %lu pages, but\n", - (ulong) tablespace_size_in_header); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: the sum of data file sizes" - " is only %lu pages\n", - (ulong) sum_of_data_file_sizes); - - if (srv_force_recovery == 0) { - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Cannot start InnoDB. The tail of" - " the system tablespace is\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: missing. Have you edited" - " innodb_data_file_path in my.cnf in an\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: inappropriate way, removing" - " ibdata files from there?\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: You can set innodb_force_recovery=1" - " in my.cnf to force\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: a startup if you are trying to" - " recover a badly corrupt database.\n"); - - return(DB_ERROR); - } - } - - /* Check that os_fast_mutexes work as expected */ - os_fast_mutex_init(PFS_NOT_INSTRUMENTED, &srv_os_test_mutex); - - if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: pthread_mutex_trylock returns" - " an unexpected value on\n"); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: success! Cannot continue.\n"); - exit(1); - } - - os_fast_mutex_unlock(&srv_os_test_mutex); - - os_fast_mutex_lock(&srv_os_test_mutex); - - os_fast_mutex_unlock(&srv_os_test_mutex); - - os_fast_mutex_free(&srv_os_test_mutex); - if (!srv_file_per_table && srv_pass_corrupt_table) { fprintf(stderr, "InnoDB: Warning:" " The option innodb_file_per_table is disabled," From 732672c3044e60fb0d1dfdb466bd3c3d13ea2f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 5 Dec 2016 15:25:59 +0200 Subject: [PATCH 116/124] MDEV-11233 CREATE FULLTEXT INDEX with a token longer than 127 bytes crashes server This bug is the result of merging the Oracle MySQL follow-up fix BUG#22963169 MYSQL CRASHES ON CREATE FULLTEXT INDEX without merging the base bug fix: Bug#79475 Insert a token of 84 4-bytes chars into fts index causes server crash. Unlike the above mentioned fixes in MySQL, our fix will not change the storage format of fulltext indexes in InnoDB or XtraDB when a character encoding with mbmaxlen=2 or mbmaxlen=3 and the length of a word is between 128 and 84*mbmaxlen bytes. The Oracle fix would allocate 2 length bytes for these cases. Compatibility with other MySQL and MariaDB releases is ensured by persisting the used maximum length in the SYS_COLUMNS table in the InnoDB data dictionary. This fix also removes some unnecessary strcmp() calls when checking for the legacy default collation my_charset_latin1 (my_charset_latin1.name=="latin1_swedish_ci"). fts_create_one_index_table(): Store the actual length in bytes. This metadata will be written to the SYS_COLUMNS table. fts_zip_initialize(): Initialize only the first byte of the buffer. Actually the code should not even care about this first byte, because the length is set as 0. FTX_MAX_WORD_LEN: Define as HA_FT_MAXCHARLEN * 4 aka 336 bytes, not as 254 bytes. row_merge_create_fts_sort_index(): Set the actual maximum length of the column in bytes, similar to fts_create_one_index_table(). row_merge_fts_doc_tokenize(): Remove the redundant parameter word_dtype. Use the actual maximum length of the column. Calculate the extra_size in the same way as row_merge_buf_encode() does. --- mysql-test/suite/innodb_fts/r/create.result | 168 ++++++++++++++++++++ mysql-test/suite/innodb_fts/t/create.opt | 1 + mysql-test/suite/innodb_fts/t/create.test | 92 +++++++++++ storage/innobase/fts/fts0fts.cc | 16 +- storage/innobase/fts/fts0opt.cc | 3 +- storage/innobase/handler/ha_innodb.cc | 11 +- storage/innobase/include/fts0fts.h | 5 +- storage/innobase/row/row0ftsort.cc | 71 ++++----- storage/xtradb/fts/fts0fts.cc | 16 +- storage/xtradb/fts/fts0opt.cc | 3 +- storage/xtradb/handler/ha_innodb.cc | 11 +- storage/xtradb/include/fts0fts.h | 5 +- storage/xtradb/row/row0ftsort.cc | 71 ++++----- 13 files changed, 365 insertions(+), 108 deletions(-) create mode 100644 mysql-test/suite/innodb_fts/r/create.result create mode 100644 mysql-test/suite/innodb_fts/t/create.opt create mode 100644 mysql-test/suite/innodb_fts/t/create.test diff --git a/mysql-test/suite/innodb_fts/r/create.result b/mysql-test/suite/innodb_fts/r/create.result new file mode 100644 index 00000000000..c537aa81efd --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/create.result @@ -0,0 +1,168 @@ +SET NAMES utf8mb4; +# +# MDEV-11233 CREATE FULLTEXT INDEX with a token +# longer than 127 bytes crashes server +# +CREATE TABLE t(t TEXT CHARACTER SET utf8mb3) ENGINE=InnoDB; +INSERT INTO t SET t=REPEAT(CONCAT(REPEAT(_utf8mb3 0xE0B987, 4), REPEAT(_utf8mb3 0xE0B989, 5)), 5); +INSERT INTO t SET t=REPEAT(_utf8 0xefbc90,84); +INSERT INTO t SET t=REPEAT('befor',17); +INSERT INTO t SET t='BeforeTheIndexCreation'; +CREATE FULLTEXT INDEX ft ON t(t); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +INSERT INTO t SET t='this was inserted after creating the index'; +INSERT INTO t SET t=REPEAT(_utf8 0xefbc91,84); +INSERT INTO t SET t=REPEAT('after',17); +INSERT INTO t SET t=REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15); +# The data below is not 3-byte UTF-8, but 4-byte chars. +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9695, 84); +Warnings: +Warning 1366 Incorrect string value: '\xF0\x9F\x96\x95\xF0\x9F...' for column 't' at row 1 +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9696, 85); +Warnings: +Warning 1366 Incorrect string value: '\xF0\x9F\x96\x96\xF0\x9F...' for column 't' at row 1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST +(REPEAT(CONCAT(REPEAT(_utf8mb3 0xE0B987, 4), REPEAT(_utf8mb3 0xE0B989, 5)), 5)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('BeforeTheIndexCreation'); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('befor',17)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('after'); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('after',17)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 84)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 85)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 84)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 85)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 84)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 84)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 85)); +COUNT(*) +0 +SELECT * FROM t; +t +็็็็้้้้้็็็็้้้้้็็็็้้้้้็็็็้้้้้็็็็้้้้้ +000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +beforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbefor +BeforeTheIndexCreation +this was inserted after creating the index +111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +afterafterafterafterafterafterafterafterafterafterafterafterafterafterafterafterafter +甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文 +???????????????????????????????????????????????????????????????????????????????????? +????????????????????????????????????????????????????????????????????????????????????? +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +len COUNT(*) +252 6 +DROP TABLE t; +CREATE TABLE t(t TEXT CHARACTER SET utf8mb4) ENGINE=InnoDB; +INSERT INTO t SET t=REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15); +INSERT INTO t SET t=REPEAT(_utf8 0xefbc90,84); +INSERT INTO t SET t=REPEAT('befor',17); +INSERT INTO t SET t='BeforeTheIndexCreation'; +CREATE FULLTEXT INDEX ft ON t(t); +Warnings: +Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID +INSERT INTO t SET t='this was inserted after creating the index'; +INSERT INTO t SET t=REPEAT(_utf8 0xefbc91,84); +INSERT INTO t SET t=REPEAT('after',17); +INSERT INTO t SET t=REPEAT(concat(repeat(_utf8mb3 0xE0B987, 4), repeat(_utf8mb3 0xE0B989, 5)), 5); +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9695, 84); +# The token below exceeds the 84-character limit. +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9696, 85); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('BeforeTheIndexCreation'); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('befor',17)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('after'); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('after',17)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 84)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 85)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 84)); +COUNT(*) +1 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 85)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 83)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 84)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 84)); +COUNT(*) +0 +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 85)); +COUNT(*) +0 +SELECT * FROM t; +t +甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文甲骨文 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +beforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbeforbefor +BeforeTheIndexCreation +this was inserted after creating the index +111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +afterafterafterafterafterafterafterafterafterafterafterafterafterafterafterafterafter +็็็็้้้้้็็็็้้้้้็็็็้้้้้็็็็้้้้้็็็็้้้้้ +🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕🖕 +🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖🖖 +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +len COUNT(*) +336 6 +DROP TABLE t; +CREATE TABLE t(t TEXT CHARACTER SET latin1, FULLTEXT INDEX(t)) +ENGINE=InnoDB; +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +len COUNT(*) +84 6 +DROP TABLE t; diff --git a/mysql-test/suite/innodb_fts/t/create.opt b/mysql-test/suite/innodb_fts/t/create.opt new file mode 100644 index 00000000000..3ad568c816e --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/create.opt @@ -0,0 +1 @@ +--loose-innodb-sys-columns diff --git a/mysql-test/suite/innodb_fts/t/create.test b/mysql-test/suite/innodb_fts/t/create.test new file mode 100644 index 00000000000..f0329602ed1 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/create.test @@ -0,0 +1,92 @@ +--source include/have_innodb.inc +SET NAMES utf8mb4; + +--echo # +--echo # MDEV-11233 CREATE FULLTEXT INDEX with a token +--echo # longer than 127 bytes crashes server +--echo # + +# This bug is the result of merging the Oracle MySQL follow-up fix +# BUG#22963169 MYSQL CRASHES ON CREATE FULLTEXT INDEX +# without merging a fix of Bug#79475 Insert a token of 84 4-bytes +# chars into fts index causes server crash. + +# Oracle did not publish tests for either of the above MySQL bugs. +# The tests below were developed for MariaDB Server. +# The maximum length of a fulltext-indexed word is 84 characters. + +CREATE TABLE t(t TEXT CHARACTER SET utf8mb3) ENGINE=InnoDB; +INSERT INTO t SET t=REPEAT(CONCAT(REPEAT(_utf8mb3 0xE0B987, 4), REPEAT(_utf8mb3 0xE0B989, 5)), 5); +INSERT INTO t SET t=REPEAT(_utf8 0xefbc90,84); +INSERT INTO t SET t=REPEAT('befor',17); # too long, will not be indexed +INSERT INTO t SET t='BeforeTheIndexCreation'; +CREATE FULLTEXT INDEX ft ON t(t); +INSERT INTO t SET t='this was inserted after creating the index'; +INSERT INTO t SET t=REPEAT(_utf8 0xefbc91,84); +INSERT INTO t SET t=REPEAT('after',17); # too long, will not be indexed +INSERT INTO t SET t=REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15); +--echo # The data below is not 3-byte UTF-8, but 4-byte chars. +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9695, 84); +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9696, 85); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST +(REPEAT(CONCAT(REPEAT(_utf8mb3 0xE0B987, 4), REPEAT(_utf8mb3 0xE0B989, 5)), 5)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('BeforeTheIndexCreation'); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('befor',17)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('after'); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('after',17)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 85)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 85)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 85)); +SELECT * FROM t; + +# The column length should be 252 bytes (84 characters * 3 bytes/character). +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +DROP TABLE t; + +CREATE TABLE t(t TEXT CHARACTER SET utf8mb4) ENGINE=InnoDB; +INSERT INTO t SET t=REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15); +INSERT INTO t SET t=REPEAT(_utf8 0xefbc90,84); +INSERT INTO t SET t=REPEAT('befor',17); # too long, will not be indexed +INSERT INTO t SET t='BeforeTheIndexCreation'; +CREATE FULLTEXT INDEX ft ON t(t); +INSERT INTO t SET t='this was inserted after creating the index'; +INSERT INTO t SET t=REPEAT(_utf8 0xefbc91,84); +INSERT INTO t SET t=REPEAT('after',17); # too long, will not be indexed +INSERT INTO t SET t=REPEAT(concat(repeat(_utf8mb3 0xE0B987, 4), repeat(_utf8mb3 0xE0B989, 5)), 5); +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9695, 84); +--echo # The token below exceeds the 84-character limit. +INSERT INTO t SET t=REPEAT(_utf8mb4 0xf09f9696, 85); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb3 0xe794b2e9aaa8e69687, 15)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('BeforeTheIndexCreation'); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('befor',17)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST ('after'); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT('after',17)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc90, 85)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8 0xefbc91, 85)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 83)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9695, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 84)); +SELECT COUNT(*) FROM t WHERE MATCH t AGAINST (REPEAT(_utf8mb4 0xf09f9696, 85)); +SELECT * FROM t; + +# The column length should be 336 bytes (84 characters * 4 bytes/character). +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +DROP TABLE t; + +CREATE TABLE t(t TEXT CHARACTER SET latin1, FULLTEXT INDEX(t)) +ENGINE=InnoDB; + +# The column length should be 84 bytes (84 characters * 1 byte/character). +SELECT len,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS where name='word' GROUP BY len; +DROP TABLE t; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 6059c28eabc..18d09c8138f 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1934,6 +1935,8 @@ func_exit: /*************************************************************//** Wrapper function of fts_create_index_tables_low(), create auxiliary tables for an FTS index + +@see row_merge_create_fts_sort_index() @return: DB_SUCCESS or error code */ static dict_table_t* @@ -1965,13 +1968,12 @@ fts_create_one_index_table( (int)(field->col->prtype & DATA_MYSQL_TYPE_MASK), (uint) dtype_get_charset_coll(field->col->prtype)); - if (strcmp(charset->name, "latin1_swedish_ci") == 0) { - dict_mem_table_add_col(new_table, heap, "word", DATA_VARCHAR, - field->col->prtype, FTS_MAX_WORD_LEN); - } else { - dict_mem_table_add_col(new_table, heap, "word", DATA_VARMYSQL, - field->col->prtype, FTS_MAX_WORD_LEN); - } + dict_mem_table_add_col(new_table, heap, "word", + charset == &my_charset_latin1 + ? DATA_VARCHAR : DATA_VARMYSQL, + field->col->prtype, + FTS_MAX_WORD_LEN_IN_CHAR + * DATA_MBMAXLEN(field->col->mbminmaxlen)); dict_mem_table_add_col(new_table, heap, "first_doc_id", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 455e2669c0d..cb30122adcb 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -281,7 +282,7 @@ fts_zip_initialize( zip->last_big_block = 0; zip->word.f_len = 0; - memset(zip->word.f_str, 0, FTS_MAX_WORD_LEN); + *zip->word.f_str = 0; ib_vector_reset(zip->blocks); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f94c564c8b3..2c84530e6ac 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3539,7 +3539,6 @@ innobase_change_buffering_inited_ok: and consequently we do not need to know the ordering internally in InnoDB. */ - ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; innobase_commit_concurrency_init_default(); @@ -6149,18 +6148,16 @@ get_innobase_type_from_mysql_type( case MYSQL_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */ if (field->binary()) { return(DATA_BINARY); - } else if (strcmp(field->charset()->name, - "latin1_swedish_ci") == 0) { + } else if (field->charset() == &my_charset_latin1) { return(DATA_VARCHAR); } else { return(DATA_VARMYSQL); } case MYSQL_TYPE_BIT: - case MYSQL_TYPE_STRING: if (field->binary()) { - + case MYSQL_TYPE_STRING: + if (field->binary()) { return(DATA_FIXBINARY); - } else if (strcmp(field->charset()->name, - "latin1_swedish_ci") == 0) { + } else if (field->charset() == &my_charset_latin1) { return(DATA_CHAR); } else { return(DATA_MYSQL); diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 3e2f359bbeb..7aa7055640c 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -366,8 +367,8 @@ extern ulong fts_min_token_size; need a sync to free some memory */ extern bool fts_need_sync; -/** Maximum possible Fulltext word length */ -#define FTS_MAX_WORD_LEN HA_FT_MAXBYTELEN +/** Maximum possible Fulltext word length in bytes (assuming mbmaxlen=4) */ +#define FTS_MAX_WORD_LEN (HA_FT_MAXCHARLEN * 4) /** Maximum possible Fulltext word length (in characters) */ #define FTS_MAX_WORD_LEN_IN_CHAR HA_FT_MAXCHARLEN diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index e4a88047955..f662ef6b461 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -57,6 +57,8 @@ tokenized doc string. The index has three "fields": integer value) 3) Word's position in original doc. +@see fts_create_one_index_table() + @return dict_index_t structure for the fts sort index */ UNIV_INTERN dict_index_t* @@ -96,16 +98,12 @@ row_merge_create_fts_sort_index( field->prefix_len = 0; field->col = static_cast( mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); - field->col->len = FTS_MAX_WORD_LEN; - - if (strcmp(charset->name, "latin1_swedish_ci") == 0) { - field->col->mtype = DATA_VARCHAR; - } else { - field->col->mtype = DATA_VARMYSQL; - } - field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; + field->col->mtype = charset == &my_charset_latin1 + ? DATA_VARCHAR : DATA_VARMYSQL; field->col->mbminmaxlen = idx_field->col->mbminmaxlen; + field->col->len = HA_FT_MAXCHARLEN * DATA_MBMAXLEN(field->col->mbminmaxlen); + field->fixed_len = 0; /* Doc ID */ @@ -359,6 +357,7 @@ row_fts_free_pll_merge_buf( /*********************************************************************//** Tokenize incoming text data and add to the sort buffer. +@see row_merge_buf_encode() @return TRUE if the record passed, FALSE if out of space */ static ibool @@ -367,8 +366,6 @@ row_merge_fts_doc_tokenize( row_merge_buf_t** sort_buf, /*!< in/out: sort buffer */ doc_id_t doc_id, /*!< in: Doc ID */ fts_doc_t* doc, /*!< in: Doc to be tokenized */ - dtype_t* word_dtype, /*!< in: data structure for - word col */ merge_file_t** merge_file, /*!< in/out: merge file */ ibool opt_doc_id_size,/*!< in: whether to use 4 bytes instead of 8 bytes integer to @@ -400,7 +397,7 @@ row_merge_fts_doc_tokenize( ulint idx = 0; ib_uint32_t position; ulint offset = 0; - ulint cur_len = 0; + ulint cur_len; doc_id_t write_doc_id; inc = innobase_mysql_fts_get_token( @@ -454,14 +451,34 @@ row_merge_fts_doc_tokenize( dfield_set_data(field, t_str.f_str, t_str.f_len); len = dfield_get_len(field); - field->type.mtype = word_dtype->mtype; - field->type.prtype = word_dtype->prtype | DATA_NOT_NULL; + dict_col_copy_type(dict_index_get_nth_col(buf->index, 0), &field->type); + field->type.prtype |= DATA_NOT_NULL; + ut_ad(len <= field->type.len); - /* Variable length field, set to max size. */ - field->type.len = FTS_MAX_WORD_LEN; - field->type.mbminmaxlen = word_dtype->mbminmaxlen; + /* For the temporary file, row_merge_buf_encode() uses + 1 byte for representing the number of extra_size bytes. + This number will always be 1, because for this 3-field index + consisting of one variable-size column, extra_size will always + be 1 or 2, which can be encoded in one byte. + + The extra_size is 1 byte if the length of the + variable-length column is less than 128 bytes or the + maximum length is less than 256 bytes. */ + + /* One variable length column, word with its lenght less than + fts_max_token_size, add one extra size and one extra byte. + + Since the max length for FTS token now is larger than 255, + so we will need to signify length byte itself, so only 1 to 128 + bytes can be used for 1 bytes, larger than that 2 bytes. */ + if (len < 128 || field->type.len < 256) { + /* Extra size is one byte. */ + cur_len = 2 + len; + } else { + /* Extra size is two bytes. */ + cur_len = 3 + len; + } - cur_len += len; dfield_dup(field, buf->heap); field++; @@ -511,20 +528,6 @@ row_merge_fts_doc_tokenize( cur_len += len; dfield_dup(field, buf->heap); - /* One variable length column, word with its lenght less than - fts_max_token_size, add one extra size and one extra byte. - - Since the max length for FTS token now is larger than 255, - so we will need to signify length byte itself, so only 1 to 128 - bytes can be used for 1 bytes, larger than that 2 bytes. */ - if (t_str.f_len < 128) { - /* Extra size is one byte. */ - cur_len += 2; - } else { - /* Extra size is two bytes. */ - cur_len += 3; - } - /* Reserve one byte for the end marker of row_merge_block_t. */ if (buf->total_size + data_size[idx] + cur_len >= srv_sort_buf_size - 1) { @@ -617,7 +620,6 @@ fts_parallel_tokenization( mem_heap_t* blob_heap = NULL; fts_doc_t doc; dict_table_t* table = psort_info->psort_common->new_table; - dtype_t word_dtype; dict_field_t* idx_field; fts_tokenize_ctx_t t_ctx; ulint retried = 0; @@ -642,10 +644,6 @@ fts_parallel_tokenization( idx_field = dict_index_get_nth_field( psort_info->psort_common->dup->index, 0); - word_dtype.prtype = idx_field->col->prtype; - word_dtype.mbminmaxlen = idx_field->col->mbminmaxlen; - word_dtype.mtype = (strcmp(doc.charset->name, "latin1_swedish_ci") == 0) - ? DATA_VARCHAR : DATA_VARMYSQL; block = psort_info->merge_block; zip_size = dict_table_zip_size(table); @@ -696,7 +694,6 @@ loop: processed = row_merge_fts_doc_tokenize( buf, doc_item->doc_id, &doc, - &word_dtype, merge_file, psort_info->psort_common->opt_doc_id_size, &t_ctx); diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 4c54afae8cd..c1f0b0bd5fe 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1934,6 +1935,8 @@ func_exit: /*************************************************************//** Wrapper function of fts_create_index_tables_low(), create auxiliary tables for an FTS index + +@see row_merge_create_fts_sort_index() @return: DB_SUCCESS or error code */ static dict_table_t* @@ -1965,13 +1968,12 @@ fts_create_one_index_table( (int)(field->col->prtype & DATA_MYSQL_TYPE_MASK), (uint) dtype_get_charset_coll(field->col->prtype)); - if (strcmp(charset->name, "latin1_swedish_ci") == 0) { - dict_mem_table_add_col(new_table, heap, "word", DATA_VARCHAR, - field->col->prtype, FTS_MAX_WORD_LEN); - } else { - dict_mem_table_add_col(new_table, heap, "word", DATA_VARMYSQL, - field->col->prtype, FTS_MAX_WORD_LEN); - } + dict_mem_table_add_col(new_table, heap, "word", + charset == &my_charset_latin1 + ? DATA_VARCHAR : DATA_VARMYSQL, + field->col->prtype, + FTS_MAX_WORD_LEN_IN_CHAR + * DATA_MBMAXLEN(field->col->mbminmaxlen)); dict_mem_table_add_col(new_table, heap, "first_doc_id", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index ea937c20752..ed882d33548 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -281,7 +282,7 @@ fts_zip_initialize( zip->last_big_block = 0; zip->word.f_len = 0; - memset(zip->word.f_str, 0, FTS_MAX_WORD_LEN); + *zip->word.f_str = 0; ib_vector_reset(zip->blocks); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index ff4f218b557..1709d4e59a9 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -4003,7 +4003,6 @@ innobase_change_buffering_inited_ok: and consequently we do not need to know the ordering internally in InnoDB. */ - ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; innobase_commit_concurrency_init_default(); @@ -6839,18 +6838,16 @@ get_innobase_type_from_mysql_type( case MYSQL_TYPE_VARCHAR: /* new >= 5.0.3 true VARCHAR */ if (field->binary()) { return(DATA_BINARY); - } else if (strcmp(field->charset()->name, - "latin1_swedish_ci") == 0) { + } else if (field->charset() == &my_charset_latin1) { return(DATA_VARCHAR); } else { return(DATA_VARMYSQL); } case MYSQL_TYPE_BIT: - case MYSQL_TYPE_STRING: if (field->binary()) { - + case MYSQL_TYPE_STRING: + if (field->binary()) { return(DATA_FIXBINARY); - } else if (strcmp(field->charset()->name, - "latin1_swedish_ci") == 0) { + } else if (field->charset() == &my_charset_latin1) { return(DATA_CHAR); } else { return(DATA_MYSQL); diff --git a/storage/xtradb/include/fts0fts.h b/storage/xtradb/include/fts0fts.h index 3e2f359bbeb..7aa7055640c 100644 --- a/storage/xtradb/include/fts0fts.h +++ b/storage/xtradb/include/fts0fts.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, MariaDB Corporation. All Rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -366,8 +367,8 @@ extern ulong fts_min_token_size; need a sync to free some memory */ extern bool fts_need_sync; -/** Maximum possible Fulltext word length */ -#define FTS_MAX_WORD_LEN HA_FT_MAXBYTELEN +/** Maximum possible Fulltext word length in bytes (assuming mbmaxlen=4) */ +#define FTS_MAX_WORD_LEN (HA_FT_MAXCHARLEN * 4) /** Maximum possible Fulltext word length (in characters) */ #define FTS_MAX_WORD_LEN_IN_CHAR HA_FT_MAXCHARLEN diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index cb47d605623..ce138252a19 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -58,6 +58,8 @@ tokenized doc string. The index has three "fields": integer value) 3) Word's position in original doc. +@see fts_create_one_index_table() + @return dict_index_t structure for the fts sort index */ UNIV_INTERN dict_index_t* @@ -99,16 +101,12 @@ row_merge_create_fts_sort_index( field->prefix_len = 0; field->col = static_cast( mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); - field->col->len = FTS_MAX_WORD_LEN; - - if (strcmp(charset->name, "latin1_swedish_ci") == 0) { - field->col->mtype = DATA_VARCHAR; - } else { - field->col->mtype = DATA_VARMYSQL; - } - field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; + field->col->mtype = charset == &my_charset_latin1 + ? DATA_VARCHAR : DATA_VARMYSQL; field->col->mbminmaxlen = idx_field->col->mbminmaxlen; + field->col->len = HA_FT_MAXCHARLEN * DATA_MBMAXLEN(field->col->mbminmaxlen); + field->fixed_len = 0; /* Doc ID */ @@ -362,6 +360,7 @@ row_fts_free_pll_merge_buf( /*********************************************************************//** Tokenize incoming text data and add to the sort buffer. +@see row_merge_buf_encode() @return TRUE if the record passed, FALSE if out of space */ static ibool @@ -370,8 +369,6 @@ row_merge_fts_doc_tokenize( row_merge_buf_t** sort_buf, /*!< in/out: sort buffer */ doc_id_t doc_id, /*!< in: Doc ID */ fts_doc_t* doc, /*!< in: Doc to be tokenized */ - dtype_t* word_dtype, /*!< in: data structure for - word col */ merge_file_t** merge_file, /*!< in/out: merge file */ ibool opt_doc_id_size,/*!< in: whether to use 4 bytes instead of 8 bytes integer to @@ -403,7 +400,7 @@ row_merge_fts_doc_tokenize( ulint idx = 0; ib_uint32_t position; ulint offset = 0; - ulint cur_len = 0; + ulint cur_len; doc_id_t write_doc_id; inc = innobase_mysql_fts_get_token( @@ -457,14 +454,34 @@ row_merge_fts_doc_tokenize( dfield_set_data(field, t_str.f_str, t_str.f_len); len = dfield_get_len(field); - field->type.mtype = word_dtype->mtype; - field->type.prtype = word_dtype->prtype | DATA_NOT_NULL; + dict_col_copy_type(dict_index_get_nth_col(buf->index, 0), &field->type); + field->type.prtype |= DATA_NOT_NULL; + ut_ad(len <= field->type.len); - /* Variable length field, set to max size. */ - field->type.len = FTS_MAX_WORD_LEN; - field->type.mbminmaxlen = word_dtype->mbminmaxlen; + /* For the temporary file, row_merge_buf_encode() uses + 1 byte for representing the number of extra_size bytes. + This number will always be 1, because for this 3-field index + consisting of one variable-size column, extra_size will always + be 1 or 2, which can be encoded in one byte. + + The extra_size is 1 byte if the length of the + variable-length column is less than 128 bytes or the + maximum length is less than 256 bytes. */ + + /* One variable length column, word with its lenght less than + fts_max_token_size, add one extra size and one extra byte. + + Since the max length for FTS token now is larger than 255, + so we will need to signify length byte itself, so only 1 to 128 + bytes can be used for 1 bytes, larger than that 2 bytes. */ + if (len < 128 || field->type.len < 256) { + /* Extra size is one byte. */ + cur_len = 2 + len; + } else { + /* Extra size is two bytes. */ + cur_len = 3 + len; + } - cur_len += len; dfield_dup(field, buf->heap); field++; @@ -514,20 +531,6 @@ row_merge_fts_doc_tokenize( cur_len += len; dfield_dup(field, buf->heap); - /* One variable length column, word with its lenght less than - fts_max_token_size, add one extra size and one extra byte. - - Since the max length for FTS token now is larger than 255, - so we will need to signify length byte itself, so only 1 to 128 - bytes can be used for 1 bytes, larger than that 2 bytes. */ - if (t_str.f_len < 128) { - /* Extra size is one byte. */ - cur_len += 2; - } else { - /* Extra size is two bytes. */ - cur_len += 3; - } - /* Reserve one byte for the end marker of row_merge_block_t. */ if (buf->total_size + data_size[idx] + cur_len >= srv_sort_buf_size - 1) { @@ -620,7 +623,6 @@ fts_parallel_tokenization( mem_heap_t* blob_heap = NULL; fts_doc_t doc; dict_table_t* table = psort_info->psort_common->new_table; - dtype_t word_dtype; dict_field_t* idx_field; fts_tokenize_ctx_t t_ctx; ulint retried = 0; @@ -645,10 +647,6 @@ fts_parallel_tokenization( idx_field = dict_index_get_nth_field( psort_info->psort_common->dup->index, 0); - word_dtype.prtype = idx_field->col->prtype; - word_dtype.mbminmaxlen = idx_field->col->mbminmaxlen; - word_dtype.mtype = (strcmp(doc.charset->name, "latin1_swedish_ci") == 0) - ? DATA_VARCHAR : DATA_VARMYSQL; block = psort_info->merge_block; zip_size = dict_table_zip_size(table); @@ -699,7 +697,6 @@ loop: processed = row_merge_fts_doc_tokenize( buf, doc_item->doc_id, &doc, - &word_dtype, merge_file, psort_info->psort_common->opt_doc_id_size, &t_ctx); From ea9caea87ed873479591113ad7cc1858bf3aa7e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 27 Jan 2017 12:17:03 +0200 Subject: [PATCH 117/124] MDEV-11814 test fix Do not kill the server after call mtr.add_suppression(), because the procedure modifies a crash-unsafe table, and we do not want to corrupt that table. --- mysql-test/suite/innodb/r/log_file_size.result | 4 ---- mysql-test/suite/innodb/t/log_file_size.test | 12 +++++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/innodb/r/log_file_size.result b/mysql-test/suite/innodb/r/log_file_size.result index 1519f02a8c8..d83af099979 100644 --- a/mysql-test/suite/innodb/r/log_file_size.result +++ b/mysql-test/suite/innodb/r/log_file_size.result @@ -1,7 +1,3 @@ -call mtr.add_suppression("InnoDB: Resizing redo log"); -call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); -call mtr.add_suppression("InnoDB: New log files created"); -call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; INSERT INTO t1 VALUES (42); diff --git a/mysql-test/suite/innodb/t/log_file_size.test b/mysql-test/suite/innodb/t/log_file_size.test index 95a7bcc143a..9668e3ba056 100644 --- a/mysql-test/suite/innodb/t/log_file_size.test +++ b/mysql-test/suite/innodb/t/log_file_size.test @@ -13,11 +13,6 @@ if (`SELECT @@innodb_log_file_size = 1048576`) { --skip Test requires innodb_log_file_size>1M. } -call mtr.add_suppression("InnoDB: Resizing redo log"); -call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); -call mtr.add_suppression("InnoDB: New log files created"); -call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); - CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; INSERT INTO t1 VALUES (42); @@ -181,5 +176,12 @@ let SEARCH_PATTERN= InnoDB: Renaming log file .*ib_logfile101 to .*ib_logfile0; --let $restart_parameters= --source include/start_mysqld.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Resizing redo log"); +call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); +--enable_query_log + SELECT * FROM t1; DROP TABLE t1; From 4e82aaab2f65268e3f206db38c3f10de555f0496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 27 Jan 2017 16:03:56 +0200 Subject: [PATCH 118/124] Clean up a few tests that kill the server. As noted in MDEV-8841, any test that kills the server must issue FLUSH TABLES, so that tables of crash-unsafe storage engines will not be corrupted. Consistently issue this statement after any call mtr.add_suppression() calls. Also, do not invoke shutdown_server directly, but use helpers instead. --- .../r/innodb_blob_unrecoverable_crash.result | 5 +-- .../suite/innodb/r/innodb_bug59641.result | 3 +- mysql-test/suite/innodb/r/xa_recovery.result | 2 +- .../t/innodb_blob_unrecoverable_crash.test | 28 +++++------------ .../suite/innodb/t/innodb_bug59641.test | 31 ++++--------------- mysql-test/suite/innodb/t/log_file_size.test | 15 ++++----- mysql-test/suite/innodb/t/xa_recovery.test | 17 ++-------- 7 files changed, 26 insertions(+), 75 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_blob_unrecoverable_crash.result b/mysql-test/suite/innodb/r/innodb_blob_unrecoverable_crash.result index 9f6b7ca6a23..d69359e8978 100644 --- a/mysql-test/suite/innodb/r/innodb_blob_unrecoverable_crash.result +++ b/mysql-test/suite/innodb/r/innodb_blob_unrecoverable_crash.result @@ -1,4 +1,3 @@ -call mtr.add_suppression("InnoDB: The total blob data length"); SET GLOBAL max_allowed_packet = 100*1024*1024; # Connection big_packets: CREATE TABLE t1 (a BIGINT PRIMARY KEY, b LONGBLOB) ENGINE=InnoDB; @@ -10,9 +9,7 @@ INSERT INTO t1 (a, b) VALUES (5, '5'); start transaction; INSERT INTO t1 (a, b) VALUES (6, REPEAT('a', 20*1024*1024)); ERROR 42000: The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size. -# Connection default: -# Quick shutdown and restart server -# Connection default: +# Kill and restart SELECT a FROM t1; a 1 diff --git a/mysql-test/suite/innodb/r/innodb_bug59641.result b/mysql-test/suite/innodb/r/innodb_bug59641.result index 5062c69558b..f4c2199ae88 100644 --- a/mysql-test/suite/innodb/r/innodb_bug59641.result +++ b/mysql-test/suite/innodb/r/innodb_bug59641.result @@ -1,5 +1,3 @@ -call mtr.add_suppression("Found 3 prepared XA transactions"); -flush tables; CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; @@ -16,6 +14,7 @@ XA START '789'; UPDATE t SET b=4*a WHERE a=32; XA END '789'; XA PREPARE '789'; +# Kill and restart SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t; a b diff --git a/mysql-test/suite/innodb/r/xa_recovery.result b/mysql-test/suite/innodb/r/xa_recovery.result index 84cb37ef7c9..4441701f961 100644 --- a/mysql-test/suite/innodb/r/xa_recovery.result +++ b/mysql-test/suite/innodb/r/xa_recovery.result @@ -4,7 +4,7 @@ XA START 'x'; UPDATE t1 set a=2; XA END 'x'; XA PREPARE 'x'; -call mtr.add_suppression("Found 1 prepared XA transactions"); +# Kill and restart SELECT * FROM t1 LOCK IN SHARE MODE; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t1; diff --git a/mysql-test/suite/innodb/t/innodb_blob_unrecoverable_crash.test b/mysql-test/suite/innodb/t/innodb_blob_unrecoverable_crash.test index 16fb570737d..dc6d2f6f65c 100644 --- a/mysql-test/suite/innodb/t/innodb_blob_unrecoverable_crash.test +++ b/mysql-test/suite/innodb/t/innodb_blob_unrecoverable_crash.test @@ -2,11 +2,13 @@ --source include/not_crashrep.inc --source include/have_innodb.inc -call mtr.add_suppression("InnoDB: The total blob data length"); - -let $old_max_allowed_packet = `select @@max_allowed_packet`; SET GLOBAL max_allowed_packet = 100*1024*1024; +--disable_query_log +call mtr.add_suppression("InnoDB: The total blob data length"); +FLUSH TABLES; +--enable_query_log + --echo # Connection big_packets: connect(big_packets,localhost,root,,); connection big_packets; @@ -28,28 +30,12 @@ start transaction; --error ER_TOO_BIG_ROWSIZE INSERT INTO t1 (a, b) VALUES (6, REPEAT('a', 20*1024*1024)); ---echo # Connection default: -connection default; - -# We expect a restart. ---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - ---echo # Quick shutdown and restart server ---shutdown_server 0 - -# Wait for the server to come back up, and reconnect. ---enable_reconnect ---source include/wait_until_connected_again.inc - ---echo # Connection default: connection default; +--source include/kill_and_restart_mysqld.inc +disconnect big_packets; # We should see (1,2,3,4,5) here. SELECT a FROM t1; # Clean up. DROP TABLE t1; - ---disable_query_log -eval set global max_allowed_packet = $old_max_allowed_packet; ---enable_query_log diff --git a/mysql-test/suite/innodb/t/innodb_bug59641.test b/mysql-test/suite/innodb/t/innodb_bug59641.test index a8d35cd1029..7fa32d2ec35 100644 --- a/mysql-test/suite/innodb/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb/t/innodb_bug59641.test @@ -2,11 +2,11 @@ # Bug #59641 Prepared XA transaction causes shutdown hang after a crash -- source include/not_embedded.inc -# The server would issue this warning on restart. -call mtr.add_suppression("Found 3 prepared XA transactions"); -# Close tables used by other tests (to not get crashed myisam tables) -flush tables; +--disable_query_log +call mtr.add_suppression("Found 3 prepared XA transactions"); +FLUSH TABLES; +--enable_query_log CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); @@ -17,7 +17,6 @@ XA END '123'; XA PREPARE '123'; CONNECT (con1,localhost,root,,); -CONNECTION con1; XA START '456'; INSERT INTO t VALUES(3,47),(5,67); @@ -26,7 +25,6 @@ XA END '456'; XA PREPARE '456'; CONNECT (con2,localhost,root,,); -CONNECTION con2; XA START '789'; UPDATE t SET b=4*a WHERE a=32; @@ -34,30 +32,13 @@ XA END '789'; XA PREPARE '789'; CONNECT (con3,localhost,root,,); -CONNECTION con3; -# Kill the server without sending a shutdown command --- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server 0 --- source include/wait_until_disconnected.inc - -# Restart the server. --- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- enable_reconnect --- source include/wait_until_connected_again.inc +--source include/kill_and_restart_mysqld.inc SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t; COMMIT; -# Shut down the server. This would hang because of the bug. --- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server --- source include/wait_until_disconnected.inc - -# Restart the server. --- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- enable_reconnect --- source include/wait_until_connected_again.inc +--source include/restart_mysqld.inc SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM t; diff --git a/mysql-test/suite/innodb/t/log_file_size.test b/mysql-test/suite/innodb/t/log_file_size.test index 9668e3ba056..e1a312df59a 100644 --- a/mysql-test/suite/innodb/t/log_file_size.test +++ b/mysql-test/suite/innodb/t/log_file_size.test @@ -13,6 +13,14 @@ if (`SELECT @@innodb_log_file_size = 1048576`) { --skip Test requires innodb_log_file_size>1M. } +--disable_query_log +call mtr.add_suppression("InnoDB: Resizing redo log"); +call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); +call mtr.add_suppression("InnoDB: New log files created"); +call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); +FLUSH TABLES; +--enable_query_log + CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; INSERT INTO t1 VALUES (42); @@ -176,12 +184,5 @@ let SEARCH_PATTERN= InnoDB: Renaming log file .*ib_logfile101 to .*ib_logfile0; --let $restart_parameters= --source include/start_mysqld.inc ---disable_query_log -call mtr.add_suppression("InnoDB: Resizing redo log"); -call mtr.add_suppression("InnoDB: Starting to delete and rewrite log files"); -call mtr.add_suppression("InnoDB: New log files created"); -call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles"); ---enable_query_log - SELECT * FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/xa_recovery.test b/mysql-test/suite/innodb/t/xa_recovery.test index 2c1034f3c4d..f5c2b655545 100644 --- a/mysql-test/suite/innodb/t/xa_recovery.test +++ b/mysql-test/suite/innodb/t/xa_recovery.test @@ -1,7 +1,3 @@ -if (`select plugin_auth_version <= "5.6.24" from information_schema.plugins where plugin_name='innodb'`) -{ - --skip Not fixed in InnoDB as of 5.6.24 or earlier -} --source include/have_innodb.inc # Embedded server does not support restarting. --source include/not_embedded.inc @@ -9,6 +5,7 @@ if (`select plugin_auth_version <= "5.6.24" from information_schema.plugins wher # MDEV-8841 - close tables opened by previous tests, # so they don't get marked crashed when the server gets crashed --disable_query_log +call mtr.add_suppression("Found 1 prepared XA transactions"); FLUSH TABLES; --enable_query_log @@ -18,17 +15,7 @@ connect (con1,localhost,root); XA START 'x'; UPDATE t1 set a=2; XA END 'x'; XA PREPARE 'x'; connection default; -call mtr.add_suppression("Found 1 prepared XA transactions"); - -# Kill and restart the server. --- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server 0 --- source include/wait_until_disconnected.inc - --- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- enable_reconnect --- source include/wait_until_connected_again.inc --- disable_reconnect +--source include/kill_and_restart_mysqld.inc disconnect con1; connect (con1,localhost,root); From bb1e8e43672ecf47e99970b5b96f65d101bae752 Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Tue, 31 Jan 2017 10:02:37 +0530 Subject: [PATCH 119/124] Mdev-4774- Fix tests cases --- .../binlog_max_binlog_stmt_cache_size.result | 53 ++++++++----------- .../t/binlog_max_binlog_stmt_cache_size.test | 44 +++++++++------ 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result b/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result index cf4d7004195..00f01b59732 100644 --- a/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result +++ b/mysql-test/suite/binlog/r/binlog_max_binlog_stmt_cache_size.result @@ -1,31 +1,22 @@ -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709547520 -set global max_binlog_stmt_cache_size= 18446744073709547520; -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709547520 -set global max_binlog_stmt_cache_size= 18446744073709547519; -Warnings: -Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709547519' -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709543424 -set global max_binlog_stmt_cache_size= 18446744073709551615; -Warnings: -Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709551615' -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709547520 -set global max_binlog_stmt_cache_size= 18446744073709551614; -Warnings: -Warning 1292 Truncated incorrect max_binlog_stmt_cache_size value: '18446744073709551614' -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709547520 -set global max_binlog_stmt_cache_size= 18446744073709551616; -ERROR 42000: Incorrect argument type to variable 'max_binlog_stmt_cache_size' -select @@max_binlog_stmt_cache_size; -@@max_binlog_stmt_cache_size -18446744073709547520 -set global max_binlog_stmt_cache_size= 18446744073709547520; +# +# MDEV-4774: Strangeness with max_binlog_stmt_cache_size Settings +# +CALL mtr.add_suppression("unsigned value 18446744073709547520 adjusted to 4294963200"); +SELECT @@global.max_binlog_stmt_cache_size; +@@global.max_binlog_stmt_cache_size +MAX_BINLOG_STMT_CACHE_SIZE +SET @cache_size= @@max_binlog_stmt_cache_size; +SET @@global.max_binlog_stmt_cache_size= @cache_size+1; +SELECT @@global.max_binlog_stmt_cache_size; +@@global.max_binlog_stmt_cache_size +MAX_BINLOG_STMT_CACHE_SIZE +SET @@global.max_binlog_stmt_cache_size = @cache_size+4095; +SELECT @@global.max_binlog_stmt_cache_size; +@@global.max_binlog_stmt_cache_size +MAX_BINLOG_STMT_CACHE_SIZE +SET @@global.max_binlog_stmt_cache_size= @cache_size-1; +SELECT @@global.max_binlog_stmt_cache_size = @cache_size-4096; +@@global.max_binlog_stmt_cache_size = @cache_size-4096 +1 +SET @@global.max_binlog_stmt_cache_size= @cache_size; +# End of test diff --git a/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test index f85eed3cea8..ca3f45c154c 100644 --- a/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test +++ b/mysql-test/suite/binlog/t/binlog_max_binlog_stmt_cache_size.test @@ -1,22 +1,36 @@ -source include/have_log_bin.inc; -select @@max_binlog_stmt_cache_size; ---let $cache_size=`select @@max_binlog_stmt_cache_size;` +--echo # +--echo # MDEV-4774: Strangeness with max_binlog_stmt_cache_size Settings +--echo # -set global max_binlog_stmt_cache_size= 18446744073709547520; -select @@max_binlog_stmt_cache_size; +CALL mtr.add_suppression("unsigned value 18446744073709547520 adjusted to 4294963200"); -set global max_binlog_stmt_cache_size= 18446744073709547519; -select @@max_binlog_stmt_cache_size; +--replace_result 18446744073709547520 MAX_BINLOG_STMT_CACHE_SIZE 4294963200 MAX_BINLOG_STMT_CACHE_SIZE +SELECT @@global.max_binlog_stmt_cache_size; -set global max_binlog_stmt_cache_size= 18446744073709551615; -select @@max_binlog_stmt_cache_size; +# Save the initial value of @@global.max_binlog_stmt_cache_size. +--replace_result 18446744073709547520 MAX_BINLOG_STMT_CACHE_SIZE 4294963200 MAX_BINLOG_STMT_CACHE_SIZE +SET @cache_size= @@max_binlog_stmt_cache_size; -set global max_binlog_stmt_cache_size= 18446744073709551614; -select @@max_binlog_stmt_cache_size; +--disable_warnings +SET @@global.max_binlog_stmt_cache_size= @cache_size+1; +--enable_warnings +--replace_result 18446744073709547520 MAX_BINLOG_STMT_CACHE_SIZE 4294963200 MAX_BINLOG_STMT_CACHE_SIZE +SELECT @@global.max_binlog_stmt_cache_size; ---error ER_WRONG_TYPE_FOR_VAR -set global max_binlog_stmt_cache_size= 18446744073709551616; -select @@max_binlog_stmt_cache_size; +--disable_warnings +SET @@global.max_binlog_stmt_cache_size = @cache_size+4095; +--enable_warnings +--replace_result 4294963200 MAX_BINLOG_STMT_CACHE_SIZE 18446744073709547520 MAX_BINLOG_STMT_CACHE_SIZE +SELECT @@global.max_binlog_stmt_cache_size; + +--disable_warnings +SET @@global.max_binlog_stmt_cache_size= @cache_size-1; +--enable_warnings +SELECT @@global.max_binlog_stmt_cache_size = @cache_size-4096; + +# Restore @@global.max_binlog_stmt_cache_size to its initial value. +SET @@global.max_binlog_stmt_cache_size= @cache_size; + +--echo # End of test ---eval set global max_binlog_stmt_cache_size= $cache_size From 41997d148dc1999c202f14e82e172c1ff57c7ead Mon Sep 17 00:00:00 2001 From: Sachin Setiya Date: Fri, 27 Jan 2017 11:15:45 +0530 Subject: [PATCH 120/124] MDEV-10812 WSREP causes responses being sent to protocol commands that must not send a response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem:- When using wsrep (w/ galera) and issuing commands that can cause deadlocks, deadlock exception errors are sent in responses to commands such as close prepared statement and close connection which, by spec, must not send a response. Solution:- In dispatch_command, we will handle COM_QUIT and COM_STMT_CLOSE commands even in case of error. Patch Credit:- Jaka Močnik --- .../suite/galera/r/galera_mdev_10812.result | 11 ++++++++ .../suite/galera/t/galera_mdev_10812.test | 27 +++++++++++++++++++ sql/sql_parse.cc | 10 ++++++- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera/r/galera_mdev_10812.result create mode 100644 mysql-test/suite/galera/t/galera_mdev_10812.test diff --git a/mysql-test/suite/galera/r/galera_mdev_10812.result b/mysql-test/suite/galera/r/galera_mdev_10812.result new file mode 100644 index 00000000000..fba10004761 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_mdev_10812.result @@ -0,0 +1,11 @@ +# +# MDEV-10812: On COM_STMT_CLOSE/COM_QUIT, when wsrep_conflict_state +# is ABORTED, it causes wrong response to be sent to the client +# +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +CREATE TABLE t1(a INT PRIMARY KEY); +INSERT INTO t1 VALUES(1),(2),(3); +START TRANSACTION ; +UPDATE t1 SET a=a+100; +UPDATE t1 SET a=a+100; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_mdev_10812.test b/mysql-test/suite/galera/t/galera_mdev_10812.test new file mode 100644 index 00000000000..4539ab6c84d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_mdev_10812.test @@ -0,0 +1,27 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-10812: On COM_STMT_CLOSE/COM_QUIT, when wsrep_conflict_state +--echo # is ABORTED, it causes wrong response to be sent to the client +--echo # + +# First create a deadlock +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +CREATE TABLE t1(a INT PRIMARY KEY); +INSERT INTO t1 VALUES(1),(2),(3); +START TRANSACTION ; +UPDATE t1 SET a=a+100; + +--sleep 2 +--connection node_2 +UPDATE t1 SET a=a+100; + +--sleep 2 +--connection node_1a +# here we get deadlock error +--disconnect node_1a + +--connection node_2 +DROP TABLE t1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 033e88aa6e1..dadb03abfff 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1265,7 +1265,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { wsrep_client_rollback(thd); } - if (thd->wsrep_conflict_state== ABORTED) + /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */ + if (thd->wsrep_conflict_state == ABORTED && + command != COM_STMT_CLOSE && command != COM_QUIT) { my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); WSREP_DEBUG("Deadlock error for: %s", thd->query()); @@ -1918,6 +1920,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (WSREP(thd)) { + /* + MDEV-10812 + In the case of COM_QUIT/COM_STMT_CLOSE thread status should be disabled. + */ + DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE) + || thd->get_stmt_da()->is_disabled()); /* wsrep BF abort in query exec phase */ mysql_mutex_lock(&thd->LOCK_wsrep_thd); do_end_of_statement= thd->wsrep_conflict_state != REPLAYING && From 17cc6198479d83bd4f88e9fff197b0b342dca5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 31 Jan 2017 15:42:52 +0200 Subject: [PATCH 121/124] MDEV-11671: Duplicated [NOTE] output for changed innodb_page_size Remove duplicated output and change output level to info. --- storage/innobase/handler/ha_innodb.cc | 32 +++++++++++--------------- storage/xtradb/handler/ha_innodb.cc | 33 +++++++++++---------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 33eb352c42f..350438e0495 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3448,22 +3448,16 @@ innobase_init( } } - if (UNIV_PAGE_SIZE != UNIV_PAGE_SIZE_DEF) { + /* The buffer pool needs to be able to accommodate enough many + pages, even for larger pages */ + if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF + && innobase_buffer_pool_size < (24 * 1024 * 1024)) { ib_logf(IB_LOG_LEVEL_INFO, - "innodb_page_size has been " - "changed from default value %d to %ld.", - UNIV_PAGE_SIZE_DEF, UNIV_PAGE_SIZE); - - /* There is hang on buffer pool when trying to get a new - page if buffer pool size is too small for large page sizes */ - if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF - && innobase_buffer_pool_size < (24 * 1024 * 1024)) { - ib_logf(IB_LOG_LEVEL_ERROR, - "innodb_page_size=%lu requires " - "innodb_buffer_pool_size > 24M current %lld", - UNIV_PAGE_SIZE, innobase_buffer_pool_size); - goto error; - } + "innodb_page_size= " ULINTPF " requires " + "innodb_buffer_pool_size > 24M current %lld. ", + UNIV_PAGE_SIZE, + innobase_buffer_pool_size); + goto error; } #ifndef HAVE_LZ4 @@ -3764,11 +3758,11 @@ innobase_change_buffering_inited_ok: srv_page_size); goto mem_free_and_error; } + if (UNIV_PAGE_SIZE_DEF != srv_page_size) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: innodb-page-size has been changed" - " from the default value %d to %lu.\n", + ib_logf(IB_LOG_LEVEL_INFO, + " innodb-page-size has been changed" + " from the default value %d to " ULINTPF ".", UNIV_PAGE_SIZE_DEF, srv_page_size); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index e9d42097fd0..bef54a910e6 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -3865,23 +3865,16 @@ innobase_init( srv_log_block_size = 512; } - if (UNIV_PAGE_SIZE != UNIV_PAGE_SIZE_DEF) { + /* The buffer pool needs to be able to accommodate enough many + pages, even for larger pages */ + if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF + && innobase_buffer_pool_size < (24 * 1024 * 1024)) { ib_logf(IB_LOG_LEVEL_INFO, - "innodb_page_size has been " - "changed from default value %d to %ld.", - UNIV_PAGE_SIZE_DEF, UNIV_PAGE_SIZE); - - /* There is hang on buffer pool when trying to get a new - page if buffer pool size is too small for large page sizes */ - if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF - && innobase_buffer_pool_size < (24 * 1024 * 1024)) { - ib_logf(IB_LOG_LEVEL_ERROR, - "innodb_page_size=%lu requires " - "innodb_buffer_pool_size > 24M current %lld", - UNIV_PAGE_SIZE, innobase_buffer_pool_size); - - goto error; - } + "innodb_page_size= " ULINTPF " requires " + "innodb_buffer_pool_size > 24M current %lld. ", + UNIV_PAGE_SIZE, + innobase_buffer_pool_size); + goto error; } ut_ad (srv_log_block_size >= OS_MIN_LOG_BLOCK_SIZE); @@ -4204,11 +4197,11 @@ innobase_change_buffering_inited_ok: srv_page_size); goto mem_free_and_error; } + if (UNIV_PAGE_SIZE_DEF != srv_page_size) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: innodb-page-size has been changed" - " from the default value %d to %lu.\n", + ib_logf(IB_LOG_LEVEL_INFO, + " innodb-page-size has been changed" + " from the default value %d to " ULINTPF " .", UNIV_PAGE_SIZE_DEF, srv_page_size); } From aa9db4c162e9fa7560abb1bf8012233f30980e04 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sun, 29 Jan 2017 13:21:38 -0500 Subject: [PATCH 122/124] MDEV-11817: Altering a table with more rows than .. .. wsrep_max_ws_rows causes cluster to break when running Galera cluster in TOI mode Problem: While copying records to temporary table during ALTER TABLE, if there are more than wsrep_max_wsrep_rows records, the command fails. Fix: Since, the temporary table records are not placed into the binary log, wsrep_affected_rows must not be incremented. Added a test. --- .../galera/r/galera_var_max_ws_rows.result | 20 +++++++++++++++ .../galera/t/galera_var_max_ws_rows.test | 25 +++++++++++++++++-- sql/handler.cc | 15 ++++++++--- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_var_max_ws_rows.result b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result index 6e239c70a3e..a1deb16c5a6 100644 --- a/mysql-test/suite/galera/r/galera_var_max_ws_rows.result +++ b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result @@ -113,3 +113,23 @@ INSERT INTO t1 (f2) VALUES (2); ERROR HY000: wsrep_max_ws_rows exceeded DROP TABLE t1; DROP TABLE ten; +# +# MDEV-11817: Altering a table with more rows than +# wsrep_max_ws_rows causes cluster to break when running +# Galera cluster in TOI mode +# +CREATE TABLE t1(c1 INT)ENGINE = INNODB; +SET GLOBAL wsrep_max_ws_rows= DEFAULT; +INSERT INTO t1 VALUES(1); +INSERT INTO t1 SELECT * FROM t1; +SET GLOBAL wsrep_max_ws_rows= 1; +ALTER TABLE t1 CHANGE COLUMN c1 c1 BIGINT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SELECT COUNT(*) FROM t1; +COUNT(*) +2 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_var_max_ws_rows.test b/mysql-test/suite/galera/t/galera_var_max_ws_rows.test index 944238bf1aa..ab6a3390c06 100644 --- a/mysql-test/suite/galera/t/galera_var_max_ws_rows.test +++ b/mysql-test/suite/galera/t/galera_var_max_ws_rows.test @@ -146,10 +146,31 @@ INSERT INTO t1 (f2) VALUES (1); --error ER_ERROR_DURING_COMMIT INSERT INTO t1 (f2) VALUES (2); +DROP TABLE t1; +DROP TABLE ten; + +--echo # +--echo # MDEV-11817: Altering a table with more rows than +--echo # wsrep_max_ws_rows causes cluster to break when running +--echo # Galera cluster in TOI mode +--echo # +--connection node_1 +CREATE TABLE t1(c1 INT)ENGINE = INNODB; +SET GLOBAL wsrep_max_ws_rows= DEFAULT; +INSERT INTO t1 VALUES(1); +INSERT INTO t1 SELECT * FROM t1; +SET GLOBAL wsrep_max_ws_rows= 1; +ALTER TABLE t1 CHANGE COLUMN c1 c1 BIGINT; + +--connection node_2 +SHOW CREATE TABLE t1; +SELECT COUNT(*) FROM t1; +DROP TABLE t1; + +--connection node_1 --disable_query_log --eval SET GLOBAL wsrep_max_ws_rows = $wsrep_max_ws_rows_orig --enable_query_log -DROP TABLE t1; -DROP TABLE ten; +--source include/galera_end.inc diff --git a/sql/handler.cc b/sql/handler.cc index af06427ff19..cca77eece48 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5726,6 +5726,8 @@ static int write_locked_table_maps(THD *thd) typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*); +static int check_wsrep_max_ws_rows(); + static int binlog_log_row(TABLE* table, const uchar *before_record, const uchar *after_record, @@ -5765,6 +5767,13 @@ static int binlog_log_row(TABLE* table, bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE || table->file->has_transactions(); error= (*log_func)(thd, table, has_trans, before_record, after_record); + + /* + Now that the record has been logged, increment wsrep_affected_rows and + also check whether its within the allowable limits (wsrep_max_ws_rows). + */ + if (error == 0) + error= check_wsrep_max_ws_rows(); } } return error ? HA_ERR_RBR_LOGGING_FAILED : 0; @@ -5923,7 +5932,7 @@ int handler::ha_write_row(uchar *buf) DBUG_RETURN(error); /* purecov: inspected */ DEBUG_SYNC_C("ha_write_row_end"); - DBUG_RETURN(check_wsrep_max_ws_rows()); + DBUG_RETURN(0); } @@ -5954,7 +5963,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) rows_changed++; if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func))) return error; - return check_wsrep_max_ws_rows(); + return 0; } int handler::ha_delete_row(const uchar *buf) @@ -5981,7 +5990,7 @@ int handler::ha_delete_row(const uchar *buf) rows_changed++; if (unlikely(error= binlog_log_row(table, buf, 0, log_func))) return error; - return check_wsrep_max_ws_rows(); + return 0; } From cd8482c19e325355006adc8fc5591998be46e288 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 30 Jan 2017 14:49:44 -0500 Subject: [PATCH 123/124] MDEV-11945: Fix description for "max_statement_time" in --help max_statement_time also applies to non-SELECT queries. --- mysql-test/r/mysqld--help.result | 8 ++++---- .../suite/sys_vars/r/sysvars_server_embedded.result | 2 +- .../suite/sys_vars/r/sysvars_server_notembedded.result | 2 +- sql/sys_vars.cc | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 340fa21f0df..4b9370f2cd4 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -467,10 +467,10 @@ The following options may be given as the first argument: --max-sp-recursion-depth[=#] Maximum stored procedure recursion depth --max-statement-time=# - A SELECT query that have taken more than - max_statement_time seconds will be aborted. The argument - will be treated as a decimal value with microsecond - precision. A value of 0 (default) means no timeout + A query that has taken more than max_statement_time + seconds will be aborted. The argument will be treated as + a decimal value with microsecond precision. A value of 0 + (default) means no timeout --max-tmp-tables=# Unused, will be removed. --max-user-connections=# The maximum number of active connections for a single diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 7d728bc89dc..1d9a956b337 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2046,7 +2046,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE 0.000000 VARIABLE_SCOPE SESSION VARIABLE_TYPE DOUBLE -VARIABLE_COMMENT A SELECT query that have taken more than max_statement_time seconds will be aborted. The argument will be treated as a decimal value with microsecond precision. A value of 0 (default) means no timeout +VARIABLE_COMMENT A query that has taken more than max_statement_time seconds will be aborted. The argument will be treated as a decimal value with microsecond precision. A value of 0 (default) means no timeout NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 31536000 NUMERIC_BLOCK_SIZE NULL diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index d6c4050545d..7fe968fd496 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2242,7 +2242,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE 0.000000 VARIABLE_SCOPE SESSION VARIABLE_TYPE DOUBLE -VARIABLE_COMMENT A SELECT query that have taken more than max_statement_time seconds will be aborted. The argument will be treated as a decimal value with microsecond precision. A value of 0 (default) means no timeout +VARIABLE_COMMENT A query that has taken more than max_statement_time seconds will be aborted. The argument will be treated as a decimal value with microsecond precision. A value of 0 (default) means no timeout NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 31536000 NUMERIC_BLOCK_SIZE NULL diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 30bc045f7a1..02dad1d1ca7 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1242,9 +1242,9 @@ static bool update_cached_max_statement_time(sys_var *self, THD *thd, static Sys_var_double Sys_max_statement_time( "max_statement_time", - "A SELECT query that have taken more than max_statement_time seconds " + "A query that has taken more than max_statement_time seconds " "will be aborted. The argument will be treated as a decimal value " - "with microsecond precision. A value of 0 (default) means no timeout", + "with microsecond precision. A value of 0 (default) means no timeout", SESSION_VAR(max_statement_time_double), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, LONG_TIMEOUT), DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), From bc4686f0f4d17dc57dd727c9f5390caa3022bdca Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 30 Jan 2017 14:50:58 -0500 Subject: [PATCH 124/124] Minor test improvement --- mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result | 1 + mysql-test/suite/galera/suite.pm | 1 - mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test | 4 ++++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result index e6f37792569..0a3516e043f 100644 --- a/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result +++ b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result @@ -19,3 +19,4 @@ SET GLOBAL wsrep_certify_nonPK = 1; SET GLOBAL wsrep_certify_nonPK = 1; DROP TABLE t1; DROP TABLE t2; +call mtr.add_suppression("SQL statement was ineffective"); diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm index 151e7b7cbe9..a161301d8ff 100644 --- a/mysql-test/suite/galera/suite.pm +++ b/mysql-test/suite/galera/suite.pm @@ -32,7 +32,6 @@ push @::global_suppressions, qr(WSREP:.*down context.*), qr(WSREP: Failed to send state UUID:), qr(WSREP: last inactive check more than .* skipping check), - qr(WSREP: SQL statement was ineffective), qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.), qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|, qr(WSREP: Quorum: No node with complete state), diff --git a/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test b/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test index 3e8f3d18859..d2d16176e41 100644 --- a/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test +++ b/mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test @@ -37,3 +37,7 @@ SELECT COUNT(*) = 1 FROM t2 WHERE f1 = 3; DROP TABLE t1; DROP TABLE t2; +--connection node_1 +call mtr.add_suppression("SQL statement was ineffective"); + +--source include/galera_end.inc