From 6c08c1176f3c5ae43fd8f178922c477a7edf7c9a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Jul 2005 10:03:19 +0300 Subject: [PATCH 01/56] Added InnoDB offline file checksum utility. extra/Makefile.am: Added innochecksum utility. BitKeeper/etc/ignore: Added extra/innochecksum to the ignore list --- .bzrignore | 1 + extra/Makefile.am | 2 +- extra/innochecksum.c | 302 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 extra/innochecksum.c diff --git a/.bzrignore b/.bzrignore index 9c6cf2c965c..1a527396cd6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1117,3 +1117,4 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl ndb/src/dummy.cpp +extra/innochecksum diff --git a/extra/Makefile.am b/extra/Makefile.am index cb06e7495f9..457fddce673 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -38,7 +38,7 @@ $(top_builddir)/include/mysqld_ername.h: $(top_builddir)/include/mysqld_error.h $(top_builddir)/include/sql_state.h: $(top_builddir)/include/mysqld_error.h bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \ - resolve_stack_dump mysql_waitpid + resolve_stack_dump mysql_waitpid innochecksum noinst_PROGRAMS = charset2html # Don't update the files from bitkeeper diff --git a/extra/innochecksum.c b/extra/innochecksum.c new file mode 100644 index 00000000000..bce4214847d --- /dev/null +++ b/extra/innochecksum.c @@ -0,0 +1,302 @@ +/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + InnoDB offline file checksum utility. 85% of the code in this file + was taken wholesale fron the InnoDB codebase. + + The final 15% was originally written by Mark Smith of Danga + Interactive, Inc. + + Published with a permission. +*/ + +// needed to have access to 64 bit file functions +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include + +// all of these ripped from InnoDB code from MySQL 4.0.22 +#define UT_HASH_RANDOM_MASK 1463735687 +#define UT_HASH_RANDOM_MASK2 1653893711 +#define FIL_PAGE_LSN 16 +#define FIL_PAGE_FILE_FLUSH_LSN 26 +#define FIL_PAGE_OFFSET 4 +#define FIL_PAGE_DATA 38 +#define FIL_PAGE_END_LSN_OLD_CHKSUM 8 +#define FIL_PAGE_SPACE_OR_CHKSUM 0 +#define UNIV_PAGE_SIZE (2 * 8192) + +// command line argument to do page checks (that's it) +// another argument to specify page ranges... seek to right spot and go from there + +typedef unsigned long int ulint; +typedef unsigned char byte; + +/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */ +ulint mach_read_from_4(byte *b) { + return( ((ulint)(b[0]) << 24) + + ((ulint)(b[1]) << 16) + + ((ulint)(b[2]) << 8) + + (ulint)(b[3]) + ); +} + +ulint +ut_fold_ulint_pair( +/*===============*/ + /* out: folded value */ + ulint n1, /* in: ulint */ + ulint n2) /* in: ulint */ +{ + return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1) + ^ UT_HASH_RANDOM_MASK) + n2); +} + +ulint +ut_fold_binary( +/*===========*/ + /* out: folded value */ + byte* str, /* in: string of bytes */ + ulint len) /* in: length */ +{ + ulint i; + ulint fold = 0; + + for (i = 0; i < len; i++) { + fold = ut_fold_ulint_pair(fold, (ulint)(*str)); + + str++; + } + + return(fold); +} + +ulint +buf_calc_page_new_checksum( +/*=======================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; + + /* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO + are written outside the buffer pool to the first pages of data + files, we have to skip them in the page checksum calculation. + We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the + checksum is stored, and also the last 8 bytes of page because + there we store the old formula checksum. */ + + checksum = ut_fold_binary(page + FIL_PAGE_OFFSET, + FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET) + + ut_fold_binary(page + FIL_PAGE_DATA, + UNIV_PAGE_SIZE - FIL_PAGE_DATA + - FIL_PAGE_END_LSN_OLD_CHKSUM); + checksum = checksum & 0xFFFFFFFF; + + return(checksum); +} + +ulint +buf_calc_page_old_checksum( +/*=======================*/ + /* out: checksum */ + byte* page) /* in: buffer page */ +{ + ulint checksum; + + checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN); + + checksum = checksum & 0xFFFFFFFF; + + return(checksum); +} + + +int main(int argc, char **argv) { + FILE *f; // our input file + byte *p; // storage of pages read + int bytes; // bytes read count + ulint ct; // current page number (0 based) + int now; // current time + int lastt; // last time + ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; // ulints for checksum storage + struct stat64 st; // for stat, if you couldn't guess + unsigned long long int size; // size of file (has to be 64 bits) + ulint pages; // number of pages in file + ulint start_page = 0, end_page = 0, use_end_page = 0; // for starting and ending at certain pages + int just_count = 0; // if true, just print page count + int verbose = 0; + int debug = 0; + int c; + int fd; + + // remove arguments + while ((c = getopt(argc, argv, "cvds:e:p:")) != -1) { + switch (c) { + case 'v': + verbose = 1; + break; + case 'c': + just_count = 1; + break; + case 's': + start_page = atoi(optarg); + break; + case 'e': + end_page = atoi(optarg); + use_end_page = 1; + break; + case 'p': + start_page = atoi(optarg); + end_page = atoi(optarg); + use_end_page = 1; + break; + case 'd': + debug = 1; + break; + case ':': + fprintf(stderr, "option -%c requires an argument\n", optopt); + return 1; + break; + case '?': + fprintf(stderr, "unrecognized option: -%c\n", optopt); + return 1; + break; + } + } + + // debug implies verbose... + if (debug) verbose = 1; + + // make sure we have the right arguments + if (optind >= argc) { + printf("InnoDB offline file checksum utility.\n"); + printf("usage: %s [-c] [-s ] [-e ] [-p ] [-v] [-d] \n", argv[0]); + printf("\t-c\tprint the count of pages in the file\n"); + printf("\t-s n\tstart on this page number (0 based)\n"); + printf("\t-e n\tend at this page number (0 based)\n"); + printf("\t-p n\tcheck only this page (0 based)\n"); + printf("\t-v\tverbose (prints progress every 5 seconds)\n"); + printf("\t-d\tdebug mode (prints checksums for each page)\n"); + return 1; + } + + // stat the file to get size and page count + if (stat64(argv[optind], &st)) { + perror("error statting file"); + return 1; + } + size = st.st_size; + pages = size / UNIV_PAGE_SIZE; + if (just_count) { + printf("%lu\n", pages); + return 0; + } else if (verbose) { + printf("file %s = %llu bytes (%lu pages)...\n", argv[1], size, pages); + printf("checking pages in range %lu to %lu\n", start_page, use_end_page ? end_page : (pages - 1)); + } + + // open the file for reading + f = fopen64(argv[optind], "r"); + if (!f) { + perror("error opening file"); + return 1; + } + + // seek to the necessary position + if (start_page) { + fd = fileno(f); + if (!fd) { + perror("unable to obtain file descriptor number"); + return 1; + } + if (lseek64(fd, start_page * UNIV_PAGE_SIZE, SEEK_SET) != (start_page * UNIV_PAGE_SIZE)) { + perror("unable to seek to necessary offset"); + return 1; + } + } + + // allocate buffer for reading (so we don't realloc every time) + p = (byte *)malloc(UNIV_PAGE_SIZE); + + // main checksumming loop + ct = start_page; + lastt = 0; + while (!feof(f)) { + bytes = fread(p, 1, UNIV_PAGE_SIZE, f); + if (!bytes && feof(f)) return 0; + if (bytes != UNIV_PAGE_SIZE) { + fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE); + return 1; + } + + // check the "stored log sequence numbers" + logseq = mach_read_from_4(p + FIL_PAGE_LSN + 4); + logseqfield = mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4); + if (debug) + printf("page %lu: log sequence number: first = %lu; second = %lu\n", ct, logseq, logseqfield); + if (logseq != logseqfield) { + fprintf(stderr, "page %lu invalid (fails log sequence number check)\n", ct); + return 1; + } + + // check old method of checksumming + oldcsum = buf_calc_page_old_checksum(p); + oldcsumfield = mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM); + if (debug) + printf("page %lu: old style: calculated = %lu; recorded = %lu\n", ct, oldcsum, oldcsumfield); + if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum) { + fprintf(stderr, "page %lu invalid (fails old style checksum)\n", ct); + return 1; + } + + // now check the new method + csum = buf_calc_page_new_checksum(p); + csumfield = mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM); + if (debug) + printf("page %lu: new style: calculated = %lu; recorded = %lu\n", ct, csum, csumfield); + if (csumfield != 0 && csum != csumfield) { + fprintf(stderr, "page %lu invalid (fails new style checksum)\n", ct); + return 1; + } + + // end if this was the last page we were supposed to check + if (use_end_page && (ct >= end_page)) + return 0; + + // do counter increase and progress printing + ct++; + if (verbose) { + if (ct % 64 == 0) { + now = time(0); + if (!lastt) lastt = now; + if (now - lastt >= 1) { + printf("page %lu okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100); + lastt = now; + } + } + } + } + return 0; +} + From 5aa1b53f80ca8d27c5f48da3d58a6ae134eb0785 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 27 Aug 2005 21:02:05 -0500 Subject: [PATCH 02/56] set_var.cc: Reorder out-of-order system variables. sql/set_var.cc: Reorder out-of-order system variables. --- sql/set_var.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index aa6ddb63a04..c7d7c6fce6e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -496,18 +496,18 @@ struct show_var_st init_vars[]= { {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, {sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS}, {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR}, - {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, {"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG}, {"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG}, + {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, {"ft_stopword_file", (char*) &ft_stopword_file, SHOW_CHAR_PTR}, {"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE}, {"have_crypt", (char*) &have_crypt, SHOW_HAVE}, {"have_innodb", (char*) &have_innodb, SHOW_HAVE}, {"have_isam", (char*) &have_isam, SHOW_HAVE}, - {"have_raid", (char*) &have_raid, SHOW_HAVE}, - {"have_symlink", (char*) &have_symlink, SHOW_HAVE}, {"have_openssl", (char*) &have_openssl, SHOW_HAVE}, {"have_query_cache", (char*) &have_query_cache, SHOW_HAVE}, + {"have_raid", (char*) &have_raid, SHOW_HAVE}, + {"have_symlink", (char*) &have_symlink, SHOW_HAVE}, {"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR}, #ifdef HAVE_INNOBASE_DB {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG }, @@ -515,12 +515,11 @@ struct show_var_st init_vars[]= { {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG }, {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR}, {"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR}, - {"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG }, - {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG }, - {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG }, - {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT}, {"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL}, + {"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG }, + {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT}, {"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR}, + {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG }, {"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG }, {"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR}, {"innodb_log_archive", (char*) &innobase_log_archive, SHOW_MY_BOOL}, @@ -528,10 +527,11 @@ struct show_var_st init_vars[]= { {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONG}, {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, - {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS}, + {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, + {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG }, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, @@ -544,10 +544,11 @@ struct show_var_st init_vars[]= { {"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL}, #endif {"log", (char*) &opt_log, SHOW_BOOL}, - {"log_update", (char*) &opt_update_log, SHOW_BOOL}, {"log_bin", (char*) &opt_bin_log, SHOW_BOOL}, + {"log_error", (char*) log_error_file, SHOW_CHAR}, {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL}, {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL}, + {"log_update", (char*) &opt_update_log, SHOW_BOOL}, {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS}, {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS}, {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS}, @@ -556,27 +557,27 @@ struct show_var_st init_vars[]= { {sys_max_allowed_packet.name,(char*) &sys_max_allowed_packet, SHOW_SYS}, {sys_max_binlog_cache_size.name,(char*) &sys_max_binlog_cache_size, SHOW_SYS}, {sys_max_binlog_size.name, (char*) &sys_max_binlog_size, SHOW_SYS}, - {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS}, {sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS}, + {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS}, {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS}, + {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_insert_delayed_threads.name, (char*) &sys_max_insert_delayed_threads, SHOW_SYS}, - {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS}, {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS}, {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, - {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, + {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, {sys_myisam_max_extra_sort_file_size.name, (char*) &sys_myisam_max_extra_sort_file_size, SHOW_SYS}, {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size, SHOW_SYS}, + {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, - {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, @@ -588,7 +589,6 @@ struct show_var_st init_vars[]= { {sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS}, {"open_files_limit", (char*) &open_files_limit, SHOW_LONG}, {"pid_file", (char*) pidfile_name, SHOW_CHAR}, - {"log_error", (char*) log_error_file, SHOW_CHAR}, {"port", (char*) &mysql_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, @@ -608,10 +608,10 @@ struct show_var_st init_vars[]= { {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS}, - {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL}, + {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, {sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS}, #ifdef HAVE_SYS_UN_H {"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR}, @@ -625,7 +625,6 @@ struct show_var_st init_vars[]= { {"thread_concurrency", (char*) &concurrency, SHOW_LONG}, #endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, - {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS}, #ifdef HAVE_TZNAME {"timezone", time_zone, SHOW_CHAR}, #endif @@ -634,6 +633,7 @@ struct show_var_st init_vars[]= { {sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size, SHOW_SYS}, {sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS}, + {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS}, {"version", server_version, SHOW_CHAR}, {"version_comment", (char*) MYSQL_COMPILATION_COMMENT, SHOW_CHAR}, {sys_os.name, (char*) &sys_os, SHOW_SYS}, From fefb444caf125df44ee5cb5af607c85fe1f8f6f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 27 Aug 2005 21:04:58 -0500 Subject: [PATCH 03/56] mysqld.cc: Reorder out-of-order status variables. sql/mysqld.cc: Reorder out-of-order status variables. --- sql/mysqld.cc | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 82335e7d706..141b72b7157 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4483,6 +4483,7 @@ struct show_var_st status_vars[]= { {"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG}, {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG}, {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG}, + {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG}, {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG}, {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG}, @@ -4492,7 +4493,6 @@ struct show_var_st status_vars[]= { {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG}, {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG}, {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG}, - {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG}, {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG}, {"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG}, @@ -4503,11 +4503,11 @@ struct show_var_st status_vars[]= { {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_MULTI_UPDATE),SHOW_LONG}, {"Connections", (char*) &thread_id, SHOW_LONG_CONST}, {"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG}, - {"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG}, {"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG}, + {"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG}, + {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_CONST}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, - {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST}, {"Handler_commit", (char*) &ha_commit_count, SHOW_LONG}, {"Handler_delete", (char*) &ha_delete_count, SHOW_LONG}, @@ -4526,26 +4526,26 @@ struct show_var_st status_vars[]= { {"Key_write_requests", (char*) &_my_cache_w_requests, SHOW_LONG}, {"Key_writes", (char*) &_my_cache_write, SHOW_LONG}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, - {"Not_flushed_key_blocks", (char*) &_my_blocks_changed, SHOW_LONG_CONST}, {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST}, - {"Open_tables", (char*) 0, SHOW_OPENTABLES}, + {"Not_flushed_key_blocks", (char*) &_my_blocks_changed, SHOW_LONG_CONST}, {"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST}, {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST}, + {"Open_tables", (char*) 0, SHOW_OPENTABLES}, {"Opened_tables", (char*) &opened_tables, SHOW_LONG}, - {"Questions", (char*) 0, SHOW_QUESTION}, #ifdef HAVE_QUERY_CACHE - {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST}, - {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, - {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG}, - {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG}, - {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, - {"Qcache_free_memory", (char*) &query_cache.free_memory, - SHOW_LONG_CONST}, {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_CONST}, + {"Qcache_free_memory", (char*) &query_cache.free_memory, + SHOW_LONG_CONST}, + {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG}, + {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, + {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG}, + {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, + {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST}, {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_CONST}, #endif /*HAVE_QUERY_CACHE*/ + {"Questions", (char*) 0, SHOW_QUESTION}, {"Rpl_status", (char*) 0, SHOW_RPL_STATUS}, {"Select_full_join", (char*) &select_full_join_count, SHOW_LONG}, {"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG}, @@ -4561,35 +4561,35 @@ struct show_var_st status_vars[]= { {"Sort_rows", (char*) &filesort_rows, SHOW_LONG}, {"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG}, #ifdef HAVE_OPENSSL - {"Ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT}, - {"Ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD}, - {"Ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD}, {"Ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE}, - {"Ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE}, + {"Ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT}, {"Ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS}, - {"Ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS}, - {"Ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES}, - {"Ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS}, - {"Ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER}, - {"Ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT}, - {"Ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL}, - {"Ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE}, - {"Ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE}, - {"Ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED}, - {"Ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE}, - {"Ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH}, - {"Ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE}, - {"Ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH}, - {"Ssl_version", (char*) 0, SHOW_SSL_GET_VERSION}, {"Ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER}, {"Ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST}, + {"Ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT}, + {"Ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE}, + {"Ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH}, + {"Ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE}, {"Ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT}, + {"Ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD}, + {"Ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD}, + {"Ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS}, + {"Ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES}, + {"Ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE}, + {"Ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL}, + {"Ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE}, + {"Ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS}, + {"Ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED}, + {"Ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER}, + {"Ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH}, + {"Ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE}, + {"Ssl_version", (char*) 0, SHOW_SSL_GET_VERSION}, #endif /* HAVE_OPENSSL */ {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, {"Threads_cached", (char*) &cached_thread_count, SHOW_LONG_CONST}, - {"Threads_created", (char*) &thread_created, SHOW_LONG_CONST}, {"Threads_connected", (char*) &thread_count, SHOW_INT_CONST}, + {"Threads_created", (char*) &thread_created, SHOW_LONG_CONST}, {"Threads_running", (char*) &thread_running, SHOW_INT_CONST}, {"Uptime", (char*) 0, SHOW_STARTTIME}, {NullS, NullS, SHOW_LONG} From 472b002b7510544018a0a254b6e0fd936e20835b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Aug 2005 12:08:04 -0500 Subject: [PATCH 04/56] set_var.cc: Reorder out-of-order system variables. sql/set_var.cc: Reorder out-of-order system variables. --- sql/set_var.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index c7d7c6fce6e..f12b81f0682 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -472,10 +472,10 @@ struct show_var_st init_vars[]= { {"basedir", mysql_home, SHOW_CHAR}, #ifdef HAVE_BERKELEY_DB {"bdb_cache_size", (char*) &berkeley_cache_size, SHOW_LONG}, - {"bdb_log_buffer_size", (char*) &berkeley_log_buffer_size, SHOW_LONG}, {"bdb_home", (char*) &berkeley_home, SHOW_CHAR_PTR}, - {"bdb_max_lock", (char*) &berkeley_max_lock, SHOW_LONG}, + {"bdb_log_buffer_size", (char*) &berkeley_log_buffer_size, SHOW_LONG}, {"bdb_logdir", (char*) &berkeley_logdir, SHOW_CHAR_PTR}, + {"bdb_max_lock", (char*) &berkeley_max_lock, SHOW_LONG}, {"bdb_shared_data", (char*) &berkeley_shared_data, SHOW_BOOL}, {"bdb_tmpdir", (char*) &berkeley_tmpdir, SHOW_CHAR_PTR}, {"bdb_version", (char*) DB_VERSION_STRING, SHOW_CHAR}, From 67278665d09ac53d670c77ab5562e88f9a1c3731 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Aug 2005 22:35:48 -0500 Subject: [PATCH 05/56] fulltext_var.result: Update test result. mysql-test/r/fulltext_var.result: Update test result. --- mysql-test/r/fulltext_var.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/fulltext_var.result b/mysql-test/r/fulltext_var.result index dda8e332fba..ef666cb4577 100644 --- a/mysql-test/r/fulltext_var.result +++ b/mysql-test/r/fulltext_var.result @@ -1,7 +1,7 @@ show variables like "ft\_%"; Variable_name Value ft_boolean_syntax + -><()~*:""&| -ft_min_word_len 4 ft_max_word_len 254 ft_max_word_len_for_sort 20 +ft_min_word_len 4 ft_stopword_file (built-in) From 52758f7cd8b6d6ba9e4a652d87f142af5bda6697 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Aug 2005 15:36:47 +0500 Subject: [PATCH 06/56] Bug #12829 Cannot convert the charset of a GROUP_CONCAT result: item_sum.cc: "result" character set was not set into proper value. func_gconcat.result, func_gconcat.test: Fixing tests accordingly. sql/item_sum.cc: Bug #12829 Cannot convert the charset of a GROUP_CONCAT result: "result" character set was not set into proper value. mysql-test/t/func_gconcat.test: Bug #12829 mysql-test/r/func_gconcat.result: Bug #12829 --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 10 ++++++++++ sql/item_sum.cc | 1 + 3 files changed, 20 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 9faee3cbc01..ca615e28823 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1; ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat' drop table t1; drop table t2; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +a +À +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +À +DROP TABLE t1; CREATE TABLE t1 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 9793d0d0a2c..3fa72b364d9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -281,6 +281,16 @@ select collation(group_concat(a,b)) from t1; drop table t1; drop table t2; +# +# Bug #12829 +# Cannot convert the charset of a GROUP_CONCAT result +# +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +SELECT GROUP_CONCAT(a) FROM t1; +DROP TABLE t1; + # # bug #7769: group_concat returning null is checked in having # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 74a7fee113e..cb4107c4276 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1937,6 +1937,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args, arg_count, MY_COLL_ALLOW_CONV)) return 1; + result.set_charset(collation.collation); result_field= 0; null_value= 1; max_length= group_concat_max_len; From 969391784f305027466d0d79b271311f22bc583b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Aug 2005 13:03:24 +0500 Subject: [PATCH 07/56] bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob sql_parse.cc: mysqld.cc: Added --skip-client-character-set-handshake. When this option is activated, client side character set (which is sent in handshake) is ignored, and server side default-character-set value is used for character_set_client and character_set_results, thus reprodicing 4.0 behaviour. sql/mysqld.cc: bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob Added --skip-client-character-set-handshake, to reproduce 4.0 behaviour. sql/sql_parse.cc: bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob Added --skip-client-character-set-handshake, to reproduce 4.0 behaviour. --- sql/mysqld.cc | 7 +++++++ sql/sql_parse.cc | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 865f494bbc9..59b733b594c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -271,6 +271,7 @@ arg_cmp_func Arg_comparator::comparator_matrix[4][2] = bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool opt_skip_character_set_client_handshake= 0; bool lower_case_table_names_used= 0; bool server_id_supplied = 0; bool opt_endinfo,using_udf_functions, locked_in_memory; @@ -4216,6 +4217,7 @@ enum options_mysqld OPT_EXPIRE_LOGS_DAYS, OPT_GROUP_CONCAT_MAX_LEN, OPT_DEFAULT_COLLATION, + OPT_CHARACTER_SET_CLIENT_HANDSHAKE, OPT_INIT_CONNECT, OPT_INIT_SLAVE, OPT_SECURE_AUTH, @@ -4753,6 +4755,11 @@ Can't be set to 1 if --log-slave-updates is used.", "Show user and password in SHOW SLAVE HOSTS on this master", (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"skip-character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, + "Don't use client side character set value sent during handshake.", + (gptr*) &opt_skip_character_set_client_handshake, + (gptr*) &opt_skip_character_set_client_handshake, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-grant-tables", OPT_SKIP_GRANT, "Start without grant tables. This gives all users FULL ACCESS to all tables!", (gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index caf76b19eb2..b8eae3aac74 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -811,11 +811,13 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); /* Use server character set and collation if + - opt_skip_character_set_client_handshake is set - client has not specified a character set - client character set is the same as the servers - client character set doesn't exists in server */ - if (!(thd->variables.character_set_client= + if (opt_skip_character_set_client_handshake || + !(thd->variables.character_set_client= get_charset((uint) net->read_pos[8], MYF(0))) || !my_strcasecmp(&my_charset_latin1, global_system_variables.character_set_client->name, From d02ec2b5d9ba03c53d35b54d15091815efe63aac Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Aug 2005 14:04:54 +0500 Subject: [PATCH 08/56] Bug#12611: ESCAPE + LIKE do not work when the escape char is a multibyte one item_cmpfunc.cc: Pass unicode value as "escape" argument to my_wildcmp if a multibyte character set is used. For single byte character set nothing has changed: native (non-unicode) character code is still passed. ctype_utf8.result, ctype_utf8.test: adding test case sql/item_cmpfunc.cc: Bug#12611: ESCAPE + LIKE do not work when the escape char is a multibyte one Pass unicode code instead of native code as "escape" argument to my_wildcmp. mysql-test/t/ctype_utf8.test: adding test mysql-test/r/ctype_utf8.result: adding test --- mysql-test/r/ctype_utf8.result | 4 ++++ mysql-test/t/ctype_utf8.test | 6 ++++++ sql/item_cmpfunc.cc | 20 +++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 748361d3178..9f2d7eac700 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -955,6 +955,10 @@ char_length(a) length(a) a 2 4 ан drop table t1; set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; +'andre%' like 'andreñ%' escape 'ñ' +1 +set names utf8; select 'a\\' like 'a\\'; 'a\\' like 'a\\' 1 diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index e6342777839..0cdda648899 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -810,6 +810,12 @@ alter table t1 modify a char(2) character set utf8; select char_length(a), length(a), a from t1 order by a; drop table t1; +# +# Bugs#12611 +# ESCAPE + LIKE do not work when the escape char is a multibyte one +# +set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; # # Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0 diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9146b3c3b9e..c869e7f5c65 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2293,7 +2293,25 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); - escape= escape_str ? *(escape_str->ptr()) : '\\'; + if (escape_str) + { + CHARSET_INFO *cs= cmp.cmp_collation.collation; + if (use_mb(cs)) + { + my_wc_t wc; + int rc= cs->cset->mb_wc(cs, &wc, + (const uchar*) escape_str->ptr(), + (const uchar*) escape_str->ptr() + + escape_str->length()); + escape= (int) (rc > 0 ? wc : '\\'); + } + else + { + escape= *(escape_str->ptr()); + } + } + else + escape= '\\'; /* We could also do boyer-more for non-const items, but as we would have to From 4eff41f5921d59b76f369952080914fd2e5b3110 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Aug 2005 12:13:22 +0200 Subject: [PATCH 09/56] Clone of 4.0.26 is taken, increase version number. --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 83685009ee6..c473fb21dbd 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.26) +AM_INIT_AUTOMAKE(mysql, 4.0.27) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From eac727b55a31bb5f00fb988b000b022114d06df5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 19:09:20 +1000 Subject: [PATCH 10/56] BUG#11607 Incorrect error code returned on deletion Save error on first failure. At end of execute, if the current error is 4350 (transaction already aborted), restore the original error (if there was one). ndb/src/ndbapi/NdbConnection.cpp: In NdbConnection::execute - returning 4350 instead of correct error. Save error on first failure. At end of execute, if the current error is 4350 (transaction already aborted), restore the original error (if there was one). --- ndb/src/ndbapi/NdbConnection.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index e1f70160fb7..c9e26f8ccaf 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -280,6 +280,7 @@ NdbConnection::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { + NdbError savedError= theError; DBUG_ENTER("NdbConnection::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); @@ -309,7 +310,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tPrepOp->theBlobList; while (tBlob != NULL) { if (tBlob->preExecute(tExecType, batch) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } if (batch) { @@ -338,7 +343,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tOp->theBlobList; while (tBlob != NULL) { if (tBlob->preCommit() == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -360,7 +369,12 @@ NdbConnection::execute(ExecType aTypeOfExec, } if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } + #ifdef ndb_api_crash_on_complex_blob_abort assert(theFirstOpInList == NULL && theLastOpInList == NULL); #else @@ -375,7 +389,11 @@ NdbConnection::execute(ExecType aTypeOfExec, while (tBlob != NULL) { // may add new operations if batch if (tBlob->postExecute(tExecType) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -406,6 +424,10 @@ NdbConnection::execute(ExecType aTypeOfExec, ndbout << "completed ops: " << n << endl; } #endif + + if(savedError.code!=0 && theError.code==4350) // Trans already aborted + theError= savedError; + DBUG_RETURN(ret); } From 5d99ed0e881ba31e9608ded3ec6a8263d8696c2d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 20:07:08 +0200 Subject: [PATCH 11/56] Compile error fix. client/mysqltest.c: Have variable declarations before "DBUG_ENTER", the opposite order will fail to compile on some platforms. --- client/mysqltest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 33702e9d1d2..92735c97fea 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -812,9 +812,9 @@ int var_set(const char *var_name, const char *var_name_end, int open_file(const char *name) { + char buff[FN_REFLEN]; DBUG_ENTER("open_file"); DBUG_PRINT("enter", ("name: %s", name)); - char buff[FN_REFLEN]; if (!test_if_hard_path(name)) { strxmov(buff, opt_basedir, name, NullS); @@ -843,9 +843,9 @@ int open_file(const char *name) int check_eol_junk(const char *eol) { + const char *p= eol; DBUG_ENTER("check_eol_junk"); DBUG_PRINT("enter", ("eol: %s", eol)); - const char *p= eol; /* Remove all spacing chars except new line */ while (*p && my_isspace(charset_info, *p) && (*p != '\n')) p++; From 6189933e782a1bf79d3aee8ff1807e762dbc701c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 11:40:21 -0700 Subject: [PATCH 12/56] delete row now pulls error message from remote server. Added test cases with archive (where delete & update will always fail) http://bugs.mysql.com/bug.php?id=12659 sql/ha_federated.cc: populate the error buffer with error message from remote system --- mysql-test/r/federated_archive.result | 48 ++++++++++++++++++++++ mysql-test/t/federated_archive.test | 58 +++++++++++++++++++++++++++ sql/ha_federated.cc | 2 + 3 files changed, 108 insertions(+) create mode 100644 mysql-test/r/federated_archive.result create mode 100644 mysql-test/t/federated_archive.test diff --git a/mysql-test/r/federated_archive.result b/mysql-test/r/federated_archive.result new file mode 100644 index 00000000000..f0eded42c38 --- /dev/null +++ b/mysql-test/r/federated_archive.result @@ -0,0 +1,48 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP DATABASE IF EXISTS federated; +CREATE DATABASE federated; +DROP TABLE IF EXISTS federated.archive_table; +CREATE TABLE federated.archive_table ( +`id` int(4) NOT NULL, +`name` varchar(54) default NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int(4) NOT NULL, +`name` varchar(54) default NULL, +PRIMARY KEY (`id`) +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/archive_table'; +INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); +INSERT INTO federated.t1 (id, name) VALUES (2, 'bar'); +SELECT * FROM federated.t1; +id name +1 foo +2 bar +DELETE FROM federated.t1 WHERE id = 1; +ERROR HY000: There was a problem processing the query on the foreign data source. Data source error: ': 1031 : Table storage engine for 'archive_table' doesn't have t' +SELECT * FROM federated.t1; +id name +1 foo +2 bar +UPDATE federated.t1 SET name='baz' WHERE id = 1; +ERROR HY000: There was a problem processing the query on the foreign data source. Data source error: ': 1031 : Table storage engine for 'archive_table' doesn't have t' +SELECT * FROM federated.t1; +id name +1 foo +2 bar +DROP TABLE federated.t1; +DROP TABLE federated.archive_table; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/t/federated_archive.test b/mysql-test/t/federated_archive.test new file mode 100644 index 00000000000..facddebf558 --- /dev/null +++ b/mysql-test/t/federated_archive.test @@ -0,0 +1,58 @@ +source include/have_archive.inc; +source include/federated.inc; + + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.archive_table; +--enable_warnings + +CREATE TABLE federated.archive_table ( + `id` int(4) NOT NULL, + `name` varchar(54) default NULL + ) ENGINE=ARCHIVE DEFAULT CHARSET=latin1; + + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `id` int(4) NOT NULL, + `name` varchar(54) default NULL, + PRIMARY KEY (`id`) + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/archive_table'; + +INSERT INTO federated.t1 (id, name) VALUES (1, 'foo'); +INSERT INTO federated.t1 (id, name) VALUES (2, 'bar'); + +SELECT * FROM federated.t1; + +--error 1430 +DELETE FROM federated.t1 WHERE id = 1; + +SELECT * FROM federated.t1; + + +--error 1430 +UPDATE federated.t1 SET name='baz' WHERE id = 1; + +SELECT * FROM federated.t1; + + +# --error 1430 +# TRUNCATE federated.t1; +# +# SELECT * from federated.t1; + +DROP TABLE federated.t1; +connection slave; +DROP TABLE federated.archive_table; + + +source include/federated_cleanup.inc; + diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 639f09d10ca..96cb81fe3ec 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1960,6 +1960,8 @@ int ha_federated::delete_row(const byte *buf) { int error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); my_error(error_code, MYF(0), error_buffer); DBUG_RETURN(error_code); } From c66167d4472834ea2b6afec204c26e37c99dac97 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 22:52:52 +0200 Subject: [PATCH 13/56] fix for BUG#12958 : mysqlimport with -L option crashing on HP-UX --- client/mysqlimport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 24392fedc1f..4bf4974748b 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object, const char *statement); static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0, - replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0, + replace=0,silent=0,ignore=0,opt_compress=0, opt_low_priority= 0, tty_password= 0; +static uint opt_local_file=0; static MYSQL mysql_connection; static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, From a59a44410899029ca01787553c3a42d6008f6bbc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 17:07:05 -0700 Subject: [PATCH 14/56] Backport of JimW's localhost patch to 4.1 tree. Handle systems like default FC4 where 127.0.0.1 doesn't always map to 'localhost' first. (Bug #11822) sql/hostname.cc: Short-circuit ip_to_hostname() lookup for INADDR_LOOPBACK to allways return 'localhost'. sql/sql_parse.cc: Push special handling of 127.0.0.1 into ip_to_hostname(). --- sql/hostname.cc | 10 +++++++++- sql/sql_parse.cc | 30 ++++++++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sql/hostname.cc b/sql/hostname.cc index 39223556024..32e1d84fac3 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -130,15 +130,23 @@ void reset_host_errors(struct in_addr *in) VOID(pthread_mutex_unlock(&hostname_cache->lock)); } +/* Deal with systems that don't defined INADDR_LOOPBACK */ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001UL +#endif my_string ip_to_hostname(struct in_addr *in, uint *errors) { uint i; host_entry *entry; DBUG_ENTER("ip_to_hostname"); + *errors= 0; + + /* We always treat the loopback address as "localhost". */ + if (in->s_addr == htonl(INADDR_LOOPBACK)) + DBUG_RETURN((char *)my_localhost); /* Check first if we have name in cache */ - *errors=0; if (!(specialflag & SPECIAL_NO_HOST_CACHE)) { VOID(pthread_mutex_lock(&hostname_cache->lock)); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 297ea8fbd67..99a64e845ef 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -696,29 +696,19 @@ static int check_connection(THD *thd) return (ER_OUT_OF_RESOURCES); thd->host_or_ip= thd->ip; vio_in_addr(net->vio,&thd->remote.sin_addr); -#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) - /* Fast local hostname resolve for Win32 */ - if (!strcmp(thd->ip,"127.0.0.1")) + if (!(specialflag & SPECIAL_NO_RESOLVE)) { - thd->host= (char*) my_localhost; - thd->host_or_ip= my_localhost; - } - else -#endif - { - if (!(specialflag & SPECIAL_NO_RESOLVE)) + vio_in_addr(net->vio,&thd->remote.sin_addr); + thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + /* Cut very long hostnames to avoid possible overflows */ + if (thd->host) { - vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); - /* Cut very long hostnames to avoid possible overflows */ - if (thd->host) - { - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; - thd->host_or_ip= thd->host; - } - if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); + if (thd->host != my_localhost) + thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; + thd->host_or_ip= thd->host; } + if (connect_errors > max_connect_errors) + return(ER_HOST_IS_BLOCKED); } DBUG_PRINT("info",("Host: %s ip: %s", thd->host ? thd->host : "unknown host", From 7425899f53d31c637ee12bac68b4a2a7e1d0c74b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 4 Sep 2005 11:25:13 -0700 Subject: [PATCH 15/56] This patch disables the query cache for the federated engine. sql/ha_federated.h: Fix cache issues --- sql/ha_federated.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 58b78ab0dde..f75fa21b1d6 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -282,6 +282,7 @@ public: HA_CREATE_INFO *create_info); //required ha_rows records_in_range(uint inx, key_range *start_key, key_range *end_key); + uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; } THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); //required From c02509b17b7f9249148b9b951c33b6999b948af7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 01:13:44 +0300 Subject: [PATCH 16/56] row0mysql.c, ha_innodb.cc: Fix bug #12308 : do not roll back the whhole transaction in a lock wait timeout error, just roll back the latest SQL statement; note that the locks set in the latest SQL statements remain, as InnoDB does not know what locks were set in which SQL statement sql/ha_innodb.cc: Fix bug #12308 : do not roll back the whhole transaction in a lock wait timeout error, just roll back the latest SQL statement; note that the locks set in the latest SQL statements remain, as InnoDB does not know what locks were set in which SQL statement innobase/row/row0mysql.c: Fix bug #12308 : do not roll back the whhole transaction in a lock wait timeout error, just roll back the latest SQL statement; note that the locks set in the latest SQL statements remain, as InnoDB does not know what locks were set in which SQL statement --- innobase/row/row0mysql.c | 5 +++-- sql/ha_innodb.cc | 10 +++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 2ac0824b331..29239210183 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -513,14 +513,15 @@ handle_new_error: return(TRUE); - } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT + } else if (err == DB_DEADLOCK || err == DB_LOCK_TABLE_FULL) { /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ trx_general_rollback_for_mysql(trx, FALSE, NULL); - } else if (err == DB_OUT_OF_FILE_SPACE) { + } else if (err == DB_OUT_OF_FILE_SPACE + || err == DB_LOCK_WAIT_TIMEOUT) { if (savept) { /* Roll back the latest, possibly incomplete insertion or update */ diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 75348d39208..aa53b69a617 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -463,13 +463,9 @@ convert_error_code_to_mysql( } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) { - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ - - if (thd) { - ha_rollback(thd); - } + /* Starting from 5.0.13, we let MySQL just roll back the + latest SQL statement in a lock wait timeout. Previously, we + rolled back the whole transaction. */ return(HA_ERR_LOCK_WAIT_TIMEOUT); From 0ef858082027a636910f27492ff6b2481862ddd6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 09:13:28 +0200 Subject: [PATCH 17/56] fixed small bug in ndb redolog printer + added option to dumpe rest of page after exnd of data ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp: fixed small bug in ndb redolog printer ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp: fixed small bug in ndb redolog printer --- .../blocks/dblqh/redoLogReader/records.cpp | 4 ++- .../blocks/dblqh/redoLogReader/records.hpp | 2 +- .../dblqh/redoLogReader/redoLogFileReader.cpp | 25 ++++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp index ba6d65ca838..b7e2ab072b5 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -134,7 +134,9 @@ bool PrepareOperationRecord::check() { return true; } -Uint32 PrepareOperationRecord::getLogRecordSize() { +Uint32 PrepareOperationRecord::getLogRecordSize(Uint32 wordsRead) { + if (wordsRead < 2) + return 2; // make sure we read more return m_logRecordSize; } diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp index 11b8dc4a6fa..b2da7427f4e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -83,7 +83,7 @@ class PrepareOperationRecord { friend NdbOut& operator<<(NdbOut&, const PrepareOperationRecord&); public: bool check(); - Uint32 getLogRecordSize(); + Uint32 getLogRecordSize(Uint32 wordsRead); protected: Uint32 m_recordType; diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index aa8b1d25e4e..751d27db74e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -41,6 +41,7 @@ void doExit(); FILE * f= 0; char fileName[256]; +bool theDumpFlag = false; bool thePrintFlag = true; bool theCheckFlag = true; bool onlyPageHeaders = false; @@ -208,7 +209,7 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read case ZPREP_OP_TYPE: poRecord = (PrepareOperationRecord *) redoLogPagePos; - wordIndex += poRecord->getLogRecordSize(); + wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex); if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*poRecord); if (theCheckFlag) { @@ -277,10 +278,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl; // Print out remaining data in this page - for (int j = wordIndex; j < PAGESIZE; j++){ - Uint32 unknown = redoLogPage[i*PAGESIZE + j]; - - ndbout_c("%-30d%-12u%-12x", j, unknown, unknown); + for (int k = wordIndex; k < PAGESIZE; k++){ + Uint32 unknown = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, unknown, unknown); } doExit(); @@ -289,8 +289,19 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read if (lastPage) + { + if (theDumpFlag) + { + ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl; + for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex; + k < PAGESIZE; k++) + { + Uint32 word = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, word, word); + } + } break; - + } if (wordIndex > PAGESIZE) { words_from_previous_page = PAGESIZE - oldWordIndex; ndbout << " ----------- Record continues on next page -----------" << endl; @@ -353,6 +364,8 @@ void readArguments(int argc, const char** argv) { if (strcmp(argv[i], "-noprint") == 0) { thePrintFlag = false; + } else if (strcmp(argv[i], "-dump") == 0) { + theDumpFlag = true; } else if (strcmp(argv[i], "-nocheck") == 0) { theCheckFlag = false; } else if (strcmp(argv[i], "-mbyteheaders") == 0) { From 4345853ee29c0faa8cf1cef74ee971e395e7520f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 09:29:28 +0200 Subject: [PATCH 18/56] added timestamp to shutdown messages in ndbd --- ndb/src/kernel/main.cpp | 2 +- ndb/src/kernel/vm/Emulator.cpp | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 1e5cd5270e4..1cab3c96d19 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -57,7 +57,7 @@ int main(int argc, char** argv) NDB_INIT(argv[0]); // Print to stdout/console g_eventLogger.createConsoleHandler(); - g_eventLogger.setCategory("NDB"); + g_eventLogger.setCategory("ndbd"); g_eventLogger.enable(Logger::LL_ON, Logger::LL_CRITICAL); g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); g_eventLogger.enable(Logger::LL_ON, Logger::LL_WARNING); diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index d6ed6c0dafd..f52233fc276 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -30,13 +30,15 @@ #include #include -#include #include #include +#include + extern "C" { extern void (* ndb_new_handler)(); } +extern EventLogger g_eventLogger; /** * Declare the global variables @@ -141,23 +143,23 @@ NdbShutdown(NdbShutdownType type, switch(type){ case NST_Normal: - ndbout << "Shutdown initiated" << endl; + g_eventLogger.info("Shutdown initiated"); break; case NST_Watchdog: - ndbout << "Watchdog " << shutting << " system" << endl; + g_eventLogger.info("Watchdog %s system", shutting); break; case NST_ErrorHandler: - ndbout << "Error handler " << shutting << " system" << endl; + g_eventLogger.info("Error handler %s system", shutting); break; case NST_ErrorHandlerSignal: - ndbout << "Error handler signal " << shutting << " system" << endl; + g_eventLogger.info("Error handler signal %s system", shutting); break; case NST_Restart: - ndbout << "Restarting system" << endl; + g_eventLogger.info("Restarting system"); break; default: - ndbout << "Error handler " << shutting << " system" - << " (unknown type: " << (unsigned)type << ")" << endl; + g_eventLogger.info("Error handler %s system (unknown type: %u)", + shutting, (unsigned)type); type = NST_ErrorHandler; break; } @@ -173,7 +175,7 @@ NdbShutdown(NdbShutdownType type, /** * Very serious, don't attempt to free, just die!! */ - ndbout << "Watchdog shutdown completed - " << exitAbort << endl; + g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); @@ -227,7 +229,7 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ - ndbout << "Error handler shutdown completed - " << exitAbort << endl; + g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); #if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); @@ -243,7 +245,7 @@ NdbShutdown(NdbShutdownType type, exit(restartType); } - ndbout << "Shutdown completed - exiting" << endl; + g_eventLogger.info("Shutdown completed - exiting"); } else { /** * Shutdown is already in progress @@ -253,7 +255,7 @@ NdbShutdown(NdbShutdownType type, * If this is the watchdog, kill system the hard way */ if (type== NST_Watchdog){ - ndbout << "Watchdog is killing system the hard way" << endl; + g_eventLogger.info("Watchdog is killing system the hard way"); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); From a0ea35da309df6c82ea91784f89e53cda0a153b1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 12:09:35 +0200 Subject: [PATCH 19/56] BUG#12983 TRASH macro confliciting with TRASH in my_sys.h mysys/my_alloc.c: Rename TRASH to TRASH_MEM and use the TRASH macro from my_sys.h --- mysys/my_alloc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 5a78eb17c96..fd5a4908572 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -221,11 +221,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) #endif } -#ifdef SAFEMALLOC -#define TRASH(X) bfill(((char*)(X) + ((X)->size-(X)->left)), (X)->left, 0xa5) -#else -#define TRASH /* no-op */ -#endif +#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left) /* Mark all data in blocks free for reusage */ @@ -239,7 +235,7 @@ static inline void mark_blocks_free(MEM_ROOT* root) for (next= root->free; next; next= *(last= &next->next)) { next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(next); + TRASH_MEM(next); } /* Combine the free and the used list */ @@ -249,7 +245,7 @@ static inline void mark_blocks_free(MEM_ROOT* root) for (; next; next= next->next) { next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(next); + TRASH_MEM(next); } /* Now everything is set; Indicate that nothing is used anymore */ @@ -310,7 +306,7 @@ void free_root(MEM_ROOT *root, myf MyFlags) { root->free=root->pre_alloc; root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM)); - TRASH(root->pre_alloc); + TRASH_MEM(root->pre_alloc); root->free->next=0; } root->block_num= 4; From e93e346a244d06b0bdb91d8c83b4da46a2406ac9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 12:33:25 +0200 Subject: [PATCH 20/56] Remove extra ; mysql-test/t/openssl_1.test: Remove extra delimiter ; --- mysql-test/t/openssl_1.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 3698ab54ec1..3f398a91834 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -20,22 +20,22 @@ connect (con4,localhost,ssl_user4,,); connection con1; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con2; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con3; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con4; select * from t1; ---error 1044; +--error 1044 delete from t1; connection default; From 943f8335f11c30b6188589e484ceacd1b1b786f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 16:31:42 +0500 Subject: [PATCH 21/56] a fix (bug #4214: Table corruption with myisampack and large BLOB objects). myisam/mi_check.c: a fix (bug #4214: Table corruption with myisampack and large BLOB objects). - pass version to the save_pack_length(). myisam/mi_packrec.c: a fix (bug #4214: Table corruption with myisampack and large BLOB objects). - code cleanup: read_pack_length() and calc_pack_length() introduced, save_pack_length() modified: now the behavior depends on packing version - save packing version in the share->pack.version - pass it to the read_pack_length() myisam/mi_static.c: a fix (bug #4214: Table corruption with myisampack and large BLOB objects). - packing version set to 2 myisam/myisamdef.h: a fix (bug #4214: Table corruption with myisampack and large BLOB objects). - packing version slot introduced (see MI_PACK) myisam/myisampack.c: a fix (bug #4214: Table corruption with myisampack and large BLOB objects). - code cleanup - pass version to the calc_pack_length() and save_pack_length() --- myisam/mi_check.c | 6 ++- myisam/mi_packrec.c | 113 +++++++++++++++++++++----------------------- myisam/mi_static.c | 2 +- myisam/myisamdef.h | 5 +- myisam/myisampack.c | 25 +++------- 5 files changed, 69 insertions(+), 82 deletions(-) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 60a2b664c70..711331518a7 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3189,9 +3189,11 @@ int sort_write_record(MI_SORT_PARAM *sort_param) break; case COMPRESSED_RECORD: reclength=info->packed_length; - length=save_pack_length(block_buff,reclength); + length= save_pack_length((uint) share->pack.version, block_buff, + reclength); if (info->s->base.blobs) - length+=save_pack_length(block_buff+length,info->blob_length); + length+= save_pack_length((uint) share->pack.version, + block_buff + length, info->blob_length); if (my_b_write(&info->rec_cache,block_buff,length) || my_b_write(&info->rec_cache,(byte*) sort_param->rec_buff,reclength)) { diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 1a71d43a7f1..322420b71db 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -149,11 +149,12 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) my_errno=HA_ERR_END_OF_FILE; goto err0; } - if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4)) + if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3)) { my_errno=HA_ERR_WRONG_IN_RECORD; goto err0; } + share->pack.version= header[3]; share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); @@ -1040,38 +1041,12 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file, return BLOCK_FATAL_ERROR; DBUG_DUMP("header",(byte*) header,ref_length); } - if (header[0] < 254) - { - info->rec_len=header[0]; - head_length=1; - } - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - head_length=3; - } - else - { - info->rec_len=uint3korr(header+1); - head_length=4; - } + head_length= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[head_length] < 254) - { - info->blob_len=header[head_length]; - head_length++; - } - else if (header[head_length] == 254) - { - info->blob_len=uint2korr(header+head_length+1); - head_length+=3; - } - else - { - info->blob_len=uint3korr(header+head_length+1); - head_length+=4; - } + head_length+= read_pack_length((uint) myisam->s->pack.version, + header + head_length, &info->blob_len); if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len, &myisam->rec_buff))) return BLOCK_FATAL_ERROR; /* not enough memory */ @@ -1220,34 +1195,12 @@ void _mi_unmap_file(MI_INFO *info) static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info, uchar *header) { - if (header[0] < 254) - info->rec_len= *header++; - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - header+=3; - } - else - { - info->rec_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[0] < 254) - { - info->blob_len= *header++; - } - else if (header[0] == 254) - { - info->blob_len=uint2korr(header+1); - header+=3; - } - else - { - info->blob_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->blob_len); /* mi_alloc_rec_buff sets my_errno on error */ if (!(mi_alloc_rec_buff(myisam, info->blob_len, &myisam->rec_buff))) @@ -1319,7 +1272,7 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf, /* Save length of row */ -uint save_pack_length(byte *block_buff,ulong length) +uint save_pack_length(uint version, byte *block_buff, ulong length) { if (length < 254) { @@ -1333,6 +1286,46 @@ uint save_pack_length(byte *block_buff,ulong length) return 3; } *(uchar*) block_buff=255; - int3store(block_buff+1,(ulong) length); - return 4; + if (version == 1) /* old format */ + { + DBUG_ASSERT(length <= 0xFFFFFF); + int3store(block_buff + 1, (ulong) length); + return 4; + } + else + { + int4store(block_buff + 1, (ulong) length); + return 5; + } +} + + +uint read_pack_length(uint version, const uchar *buf, ulong *length) +{ + if (buf[0] < 254) + { + *length= buf[0]; + return 1; + } + else if (buf[0] == 254) + { + *length= uint2korr(buf + 1); + return 3; + } + if (version == 1) /* old format */ + { + *length= uint3korr(buf + 1); + return 4; + } + else + { + *length= uint4korr(buf + 1); + return 5; + } +} + + +uint calc_pack_length(uint version, ulong length) +{ + return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5; } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f41aeff8453..9725c120f44 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -27,7 +27,7 @@ LIST *myisam_open_list=0; uchar NEAR myisam_file_magic[]= { (uchar) 254, (uchar) 254,'\007', '\001', }; uchar NEAR myisam_pack_file_magic[]= -{ (uchar) 254, (uchar) 254,'\010', '\001', }; +{ (uchar) 254, (uchar) 254,'\010', '\002', }; my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index a41bcf5449b..15b310e907e 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -149,6 +149,7 @@ typedef struct st_mi_blob /* Info of record */ typedef struct st_mi_isam_pack { ulong header_length; uint ref_length; + uchar version; } MI_PACK; @@ -669,7 +670,9 @@ extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, int result); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); -extern uint save_pack_length(byte *block_buff,ulong length); +extern uint save_pack_length(uint version, byte *block_buff, ulong length); +extern uint read_pack_length(uint version, const uchar *buf, ulong *length); +extern uint calc_pack_length(uint version, ulong length); uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite); char *mi_state_info_read(char *ptr, MI_STATE_INFO *state); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 405c69544e7..60522c6f364 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -1666,6 +1666,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) HUFF_COUNTS *count,*end_count; HUFF_TREE *tree; MI_INFO *isam_file=mrg->file[0]; + uint pack_version= (uint) isam_file->s->pack.version; DBUG_ENTER("compress_isam_file"); if (!(record=(byte*) my_alloca(isam_file->s->base.reclength))) @@ -1693,23 +1694,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) huff_counts[i].tree->height+huff_counts[i].length_bits; } max_calc_length/=8; - if (max_calc_length < 254) - pack_ref_length=1; - else if (max_calc_length <= 65535) - pack_ref_length=3; - else - pack_ref_length=4; + pack_ref_length= calc_pack_length(pack_version, max_calc_length); record_count=0; - pack_blob_length=0; - if (isam_file->s->base.blobs) - { - if (mrg->max_blob_length < 254) - pack_blob_length=1; - else if (mrg->max_blob_length <= 65535) - pack_blob_length=3; - else - pack_blob_length=4; - } + pack_blob_length= isam_file->s->base.blobs ? + calc_pack_length(pack_version, mrg->max_blob_length) : 0; max_pack_length=pack_ref_length+pack_blob_length; mrg_reset(mrg); @@ -1865,9 +1853,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } flush_bits(); length=(ulong) (file_buffer.pos-record_pos)-max_pack_length; - pack_length=save_pack_length(record_pos,length); + pack_length= save_pack_length(pack_version, record_pos, length); if (pack_blob_length) - pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length); + pack_length+= save_pack_length(pack_version, record_pos + pack_length, + tot_blob_length); /* Correct file buffer if the header was smaller */ if (pack_length != max_pack_length) From 354fa102a3294fe349a428d1507433165581caec Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 15:14:44 +0200 Subject: [PATCH 22/56] Bug #12992 Cluster StopOnError = Y restarts ndbd indefinitly --- ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp | 8 ++++ ndb/src/kernel/error/ErrorReporter.cpp | 14 ++++++- ndb/src/kernel/error/ErrorReporter.hpp | 2 + ndb/src/kernel/main.cpp | 37 +++++++++++++++++++ ndb/src/kernel/vm/Emulator.cpp | 6 +++ ndb/src/kernel/vm/Emulator.hpp | 3 +- 6 files changed, 67 insertions(+), 3 deletions(-) diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 2e2c834ad9c..071a85c96da 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -2493,6 +2493,14 @@ void Ndbcntr::Missra::sendNextSTTOR(Signal* signal){ const Uint32 start = currentBlockIndex; + if (currentStartPhase == ZSTART_PHASE_6) + { + // Ndbd has passed the critical startphases. + // Change error handler from "startup" state + // to normal state. + ErrorReporter::setErrorHandlerShutdownType(); + } + for(; currentBlockIndex < ALL_BLOCKS_SZ; currentBlockIndex++){ jam(); if(ALL_BLOCKS[currentBlockIndex].NextSP == currentStartPhase){ diff --git a/ndb/src/kernel/error/ErrorReporter.cpp b/ndb/src/kernel/error/ErrorReporter.cpp index e4ead4ce34d..25409db48a8 100644 --- a/ndb/src/kernel/error/ErrorReporter.cpp +++ b/ndb/src/kernel/error/ErrorReporter.cpp @@ -152,6 +152,14 @@ ErrorReporter::formatMessage(ErrorCategory type, return; } +NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler; + +void +ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst) +{ + s_errorHandlerShutdownType = nst; +} + void ErrorReporter::handleAssert(const char* message, const char* file, int line) { @@ -170,7 +178,7 @@ ErrorReporter::handleAssert(const char* message, const char* file, int line) WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, theEmulatedJamIndex, theEmulatedJam); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); } void @@ -182,7 +190,7 @@ ErrorReporter::handleThreadAssert(const char* message, BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", file, line, message); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); }//ErrorReporter::handleThreadAssert() @@ -201,6 +209,8 @@ ErrorReporter::handleError(ErrorCategory type, int messageID, if(messageID == ERR_ERROR_INSERT){ NdbShutdown(NST_ErrorInsert); } else { + if (nst == NST_ErrorHandler) + nst = s_errorHandlerShutdownType; NdbShutdown(nst); } } diff --git a/ndb/src/kernel/error/ErrorReporter.hpp b/ndb/src/kernel/error/ErrorReporter.hpp index 2c79f242eea..c5533df46f4 100644 --- a/ndb/src/kernel/error/ErrorReporter.hpp +++ b/ndb/src/kernel/error/ErrorReporter.hpp @@ -26,6 +26,7 @@ class ErrorReporter { public: + static void setErrorHandlerShutdownType(NdbShutdownType nst = NST_ErrorHandler); static void handleAssert(const char* message, const char* file, int line); @@ -57,6 +58,7 @@ public: static const char* formatTimeStampString(); private: + static enum NdbShutdownType s_errorHandlerShutdownType; }; #endif diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 1cab3c96d19..aa220b0ae05 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -45,8 +45,14 @@ extern NdbMutex * theShutdownMutex; void catchsigs(bool ignore); // for process signal handling +#define MAX_FAILED_STARTUPS 3 +// Flag set by child through SIGUSR1 to signal a failed startup +static bool failed_startup_flag = false; +// Counter for consecutive failed startups +static Uint32 failed_startups = 0; extern "C" void handler_shutdown(int signum); // for process signal handling extern "C" void handler_error(int signum); // for process signal handling +extern "C" void handler_sigusr1(int signum); // child signalling failed restart // Shows system information void systemInfo(const Configuration & conf, @@ -92,6 +98,8 @@ int main(int argc, char** argv) } #ifndef NDB_WIN32 + signal(SIGUSR1, handler_sigusr1); + for(pid_t child = fork(); child != 0; child = fork()){ /** * Parent @@ -137,6 +145,20 @@ int main(int argc, char** argv) */ exit(0); } + if (!failed_startup_flag) + { + // Reset the counter for consecutive failed startups + failed_startups = 0; + } + else if (failed_startups >= MAX_FAILED_STARTUPS && !theConfig->stopOnError()) + { + /** + * Error shutdown && stopOnError() + */ + g_eventLogger.alert("Ndbd has failed %u consecutive startups. Not restarting", failed_startups); + exit(0); + } + failed_startup_flag = false; g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); theConfig->fetch_configuration(); } @@ -170,6 +192,9 @@ int main(int argc, char** argv) /** * Do startup */ + + ErrorReporter::setErrorHandlerShutdownType(NST_ErrorHandlerStartup); + switch(globalData.theRestartFlag){ case initial_state: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); @@ -359,3 +384,15 @@ handler_error(int signum){ BaseString::snprintf(errorData, 40, "Signal %d received", signum); ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__); } + +extern "C" +void +handler_sigusr1(int signum) +{ + if (!failed_startup_flag) + { + failed_startups++; + failed_startup_flag = true; + } + g_eventLogger.info("Received signal %d. Ndbd failed startup (%u).", signum, failed_startups); +} diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index f52233fc276..76e1c3ab483 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -154,6 +154,9 @@ NdbShutdown(NdbShutdownType type, case NST_ErrorHandlerSignal: g_eventLogger.info("Error handler signal %s system", shutting); break; + case NST_ErrorHandlerStartup: + g_eventLogger.info("Error handler startup %s system", shutting); + break; case NST_Restart: g_eventLogger.info("Restarting system"); break; @@ -229,6 +232,9 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ + // Signal parent that error occured during startup + if (type == NST_ErrorHandlerStartup) + kill(getppid(), SIGUSR1); g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); #if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); diff --git a/ndb/src/kernel/vm/Emulator.hpp b/ndb/src/kernel/vm/Emulator.hpp index dba8cb3ab9b..cd194202d85 100644 --- a/ndb/src/kernel/vm/Emulator.hpp +++ b/ndb/src/kernel/vm/Emulator.hpp @@ -83,7 +83,8 @@ enum NdbShutdownType { NST_ErrorHandler, NST_ErrorHandlerSignal, NST_Restart, - NST_ErrorInsert + NST_ErrorInsert, + NST_ErrorHandlerStartup }; enum NdbRestartType { From 5168730f6bd6b4832ddb208c7f1a1af58ff3c678 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 17:58:29 +0400 Subject: [PATCH 23/56] func_gconcat.test, func_gconcat.result: Test case for bug #12859 group_concat in subquery cause incorrect not null. mysql-test/r/func_gconcat.result: Test case for bug #12859 group_concat in subquery cause incorrect not null. mysql-test/t/func_gconcat.test: Test case for bug #12859 group_concat in subquery cause incorrect not null. --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index a6c25fcd26c..12bc5ca2582 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -551,3 +551,12 @@ DROP TABLE t1,t2; select * from (select group_concat('c') from DUAL) t; group_concat('c') NULL +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +group_concat(a) +NULL +select group_concat('x') UNION ALL select 1; +group_concat('x') +NULL +1 +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 827a2813718..9e003d19ab9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -348,4 +348,12 @@ DROP TABLE t1,t2; # select * from (select group_concat('c') from DUAL) t; +# +# Bug #12859 group_concat in subquery cause incorrect not null +# +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +select group_concat('x') UNION ALL select 1; +drop table t1; + # End of 4.1 tests From 4a584b17e81c636f4819b9923e54c0ec1efeaa84 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 16:33:40 +0200 Subject: [PATCH 24/56] added --core-file option to ndb executables added parseable printout in ndb_restore --- ndb/include/util/ndb_opts.h | 12 ++++++- ndb/src/kernel/vm/Emulator.cpp | 40 ++++++++++++--------- ndb/src/mgmsrv/ConfigInfo.cpp | 16 ++++----- ndb/src/mgmsrv/MgmtSrvr.cpp | 34 ++++++++++++------ ndb/src/mgmsrv/Services.cpp | 2 -- ndb/tools/Makefile.am | 2 +- ndb/tools/ndb_config.cpp | 1 + ndb/tools/restore/consumer_restore.cpp | 29 ++++++++++------ ndb/tools/restore/restore_main.cpp | 48 ++++++++++++++++---------- 9 files changed, 114 insertions(+), 70 deletions(-) diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index ca4ca5eac83..462d9996582 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -30,8 +30,14 @@ my_bool opt_ndb_optimized_node_selection bool opt_endinfo= 0; my_bool opt_ndb_shm; +my_bool opt_core; #define OPT_NDB_CONNECTSTRING 'c' +#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) +#define OPT_WANT_CORE_DEFAULT 1 +#else +#define OPT_WANT_CORE_DEFAULT 0 +#endif #define NDB_STD_OPTS_COMMON \ { "usage", '?', "Display this help and exit.", \ @@ -57,7 +63,10 @@ my_bool opt_ndb_shm; GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\ { "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "core-file", OPT_WANT_CORE, "Write core on errors.",\ + (gptr*) &opt_core, (gptr*) &opt_core, 0,\ + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -80,6 +89,7 @@ enum ndb_std_options { OPT_NDB_SHM= 256, OPT_NDB_SHM_SIGNUM, OPT_NDB_OPTIMIZED_NODE_SELECTION, + OPT_WANT_CORE, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ }; diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index 76e1c3ab483..058829e05e2 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -39,6 +39,7 @@ extern "C" { extern void (* ndb_new_handler)(); } extern EventLogger g_eventLogger; +extern my_bool opt_core; /** * Declare the global variables @@ -168,23 +169,25 @@ NdbShutdown(NdbShutdownType type, } const char * exitAbort = 0; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - exitAbort = "aborting"; -#else - exitAbort = "exiting"; -#endif + if (opt_core) + exitAbort = "aborting"; + else + exitAbort = "exiting"; if(type == NST_Watchdog){ /** * Very serious, don't attempt to free, just die!! */ g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } #ifndef NDB_WIN32 @@ -236,12 +239,15 @@ NdbShutdown(NdbShutdownType type, if (type == NST_ErrorHandlerStartup) kill(getppid(), SIGUSR1); g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); -#if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } /** diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index cface035174..36a72dcb975 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -25,6 +25,7 @@ #include extern my_bool opt_ndb_shm; +extern my_bool opt_core; #define MAX_LINE_LENGTH 255 #define KEY_INTERNAL 0 @@ -2140,11 +2141,10 @@ static void require(bool v) { if(!v) { -#ifndef DBUG_OFF - abort(); -#else - exit(-1); -#endif + if (opt_core) + abort(); + else + exit(-1); } } @@ -2214,7 +2214,7 @@ ConfigInfo::ConfigInfo() ndbout << "Error: Parameter " << param._fname << " defined twice in section " << param._section << "." << endl; - exit(-1); + require(false); } // Add new pinfo to section @@ -2264,7 +2264,7 @@ ConfigInfo::ConfigInfo() ndbout << "Check that each entry has a section failed." << endl; ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION) @@ -2277,7 +2277,7 @@ ConfigInfo::ConfigInfo() << "\" does not exist in section \"" << m_ParamInfo[i]._section << "\"." << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } } } diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 452dabc50e0..acab2ef9eac 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -65,6 +65,18 @@ extern int global_flag_send_heartbeat_now; extern int g_no_nodeid_checks; +extern my_bool opt_core; + +static void require(bool v) +{ + if(!v) + { + if (opt_core) + abort(); + else + exit(-1); + } +} void * MgmtSrvr::logLevelThread_C(void* m) @@ -436,14 +448,14 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if (tmp_nodeid == 0) { ndbout_c(m_config_retriever->getErrorString()); - exit(-1); + require(false); } // read config from other managent server _config= fetchConfig(); if (_config == 0) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } _ownNodeId= tmp_nodeid; } @@ -454,7 +466,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _config= readConfig(); if (_config == 0) { ndbout << "Unable to read config file" << endl; - exit(-1); + require(false); } } @@ -511,7 +523,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if ((m_node_id_mutex = NdbMutex_Create()) == 0) { ndbout << "mutex creation failed line = " << __LINE__ << endl; - exit(-1); + require(false); } if (_ownNodeId == 0) // we did not get node id from other server @@ -522,7 +534,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, 0, 0, error_string)){ ndbout << "Unable to obtain requested nodeid: " << error_string.c_str() << endl; - exit(-1); + require(false); } _ownNodeId = tmp; } @@ -533,7 +545,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _ownNodeId)) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } } @@ -2203,18 +2215,18 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, iter(*(ndb_mgm_configuration *)_config->m_configValues, CFG_SECTION_NODE); for(iter.first(); iter.valid(); iter.next()) { unsigned tmp= 0; - if(iter.get(CFG_NODE_ID, &tmp)) abort(); + if(iter.get(CFG_NODE_ID, &tmp)) require(false); if (*nodeId && *nodeId != tmp) continue; found_matching_id= true; - if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) abort(); + if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) require(false); if(type_c != (unsigned)type) continue; found_matching_type= true; if (connected_nodes.get(tmp)) continue; found_free_node= true; - if(iter.get(CFG_NODE_HOST, &config_hostname)) abort(); + if(iter.get(CFG_NODE_HOST, &config_hostname)) require(false); if (config_hostname && config_hostname[0] == 0) config_hostname= 0; else if (client_addr) { @@ -2561,7 +2573,7 @@ MgmtSrvr::backupCallback(BackupEvent & event) int MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) { - abort(); + require(false); return 0; } @@ -2715,7 +2727,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value, ndbout_c("Updating node %d param: %d to %s", node, param, val_char); break; default: - abort(); + require(false); } assert(res); } while(node == 0 && iter.next() == 0); diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 00cf6390c73..46bfb531b61 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -343,8 +343,6 @@ MgmApiSession::getConfig_old(Parser_t::Context &ctx) { } #endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */ -inline void require(bool b){ if(!b) abort(); } - void MgmApiSession::getConfig(Parser_t::Context &ctx, const class Properties &args) { diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 89830129576..795441380a8 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -30,7 +30,7 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer.cpp \ restore/consumer_restore.cpp \ restore/consumer_printer.cpp \ - restore/Restore.cpp + restore/Restore.cpp $(tools_common_sources) ndb_config_SOURCES = ndb_config.cpp \ ../src/mgmsrv/Config.cpp \ diff --git a/ndb/tools/ndb_config.cpp b/ndb/tools/ndb_config.cpp index d188aec1337..725249a5af5 100644 --- a/ndb/tools/ndb_config.cpp +++ b/ndb/tools/ndb_config.cpp @@ -42,6 +42,7 @@ static const char * g_field_delimiter=","; static const char * g_row_delimiter=" "; int g_print_full_config, opt_ndb_shm; +my_bool opt_core; typedef ndb_mgm_configuration_iterator Iter; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index d782a561e6a..70ea7460d78 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -14,9 +14,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "consumer_restore.hpp" #include +extern my_bool opt_core; + extern FilteredNdbOut err; extern FilteredNdbOut info; extern FilteredNdbOut debug; @@ -458,7 +461,11 @@ bool BackupRestore::errorHandler(restore_callback_t *cb) void BackupRestore::exitHandler() { release(); - exit(-1); + NDBT_ProgramExit(NDBT_FAILED); + if (opt_core) + abort(); + else + exit(NDBT_FAILED); } @@ -492,7 +499,7 @@ BackupRestore::logEntry(const LogEntry & tup) { // Deep shit, TODO: handle the error err << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const NdbDictionary::Table * table = get_table(tup.m_table->m_dictTable); @@ -500,7 +507,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (op == NULL) { err << "Cannot get operation: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if int check = 0; @@ -518,13 +525,13 @@ BackupRestore::logEntry(const LogEntry & tup) default: err << "Log entry has wrong operation type." << " Exiting..."; - exit(-1); + exitHandler(); } if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if Bitmask<4096> keys; @@ -553,7 +560,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if } @@ -582,7 +589,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (!ok) { err << "execute failed: " << errobj << endl; - exit(-1); + exitHandler(); } } @@ -629,7 +636,7 @@ BackupRestore::tuple(const TupleS & tup) { // Deep shit, TODO: handle the error ndbout << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const TableS * table = tup.getTable(); @@ -638,7 +645,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "Cannot get operation: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if // TODO: check return value and handle error @@ -646,7 +653,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "writeTuple call failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if for (int i = 0; i < tup.getNoOfAttributes(); i++) @@ -680,7 +687,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "execute failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } m_ndb->closeTransaction(trans); if (ret == 0) diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index 0c4419bb072..d786dffe89e 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "consumer_restore.hpp" #include "consumer_printer.hpp" @@ -116,14 +117,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (ga_nodeId == 0) { printf("Error in --nodeid,-n setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; case 'b': if (ga_backupId == 0) { printf("Error in --backupid,-b setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; } @@ -136,7 +137,7 @@ readArguments(int *pargc, char*** pargv) load_defaults("my",load_default_groups,pargc,pargv); if (handle_options(pargc, pargv, my_long_options, get_one_option)) { - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } BackupPrinter* printer = new BackupPrinter(); @@ -226,6 +227,15 @@ free_data_callback() g_consumers[i]->tuple_free(); } +static void exitHandler(int code) +{ + NDBT_ProgramExit(code); + if (opt_core) + abort(); + else + exit(code); +} + int main(int argc, char** argv) { @@ -233,7 +243,7 @@ main(int argc, char** argv) if (!readArguments(&argc, &argv)) { - return -1; + exitHandler(NDBT_FAILED); } Ndb::setConnectString(opt_connect_str); @@ -245,7 +255,7 @@ main(int argc, char** argv) if (!metaData.readHeader()) { ndbout << "Failed to read " << metaData.getFilename() << endl << endl; - return -1; + exitHandler(NDBT_FAILED); } const BackupFormat::FileHeader & tmp = metaData.getFileHeader(); @@ -263,20 +273,20 @@ main(int argc, char** argv) if (res == 0) { ndbout_c("Restore: Failed to load content"); - return -1; + exitHandler(NDBT_FAILED); } if (metaData.getNoOfTables() == 0) { ndbout_c("Restore: The backup contains no tables "); - return -1; + exitHandler(NDBT_FAILED); } if (!metaData.validateFooter()) { ndbout_c("Restore: Failed to validate footer."); - return -1; + exitHandler(NDBT_FAILED); } Uint32 i; @@ -285,7 +295,7 @@ main(int argc, char** argv) if (!g_consumers[i]->init()) { clearConsumers(); - return -11; + exitHandler(NDBT_FAILED); } } @@ -300,7 +310,7 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } @@ -309,7 +319,7 @@ main(int argc, char** argv) if (!g_consumers[i]->endOfTables()) { ndbout_c("Restore: Failed while closing tables"); - return -11; + exitHandler(NDBT_FAILED); } if (ga_restore || ga_print) @@ -322,7 +332,7 @@ main(int argc, char** argv) if (!dataIter.readHeader()) { ndbout << "Failed to read header of data file. Exiting..." ; - return -11; + exitHandler(NDBT_FAILED); } @@ -340,12 +350,12 @@ main(int argc, char** argv) { ndbout_c("Restore: An error occured while restoring data. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } if (!dataIter.validateFragmentFooter()) { ndbout_c("Restore: Error validating fragment footer. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } } // while (dataIter.readFragmentHeader(res)) @@ -353,7 +363,7 @@ main(int argc, char** argv) { err << "Restore: An error occured while restoring data. Exiting... " << "res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } @@ -366,7 +376,7 @@ main(int argc, char** argv) if (!logIter.readHeader()) { err << "Failed to read header of data file. Exiting..." << endl; - return -1; + exitHandler(NDBT_FAILED); } const LogEntry * logEntry = 0; @@ -380,7 +390,7 @@ main(int argc, char** argv) { err << "Restore: An restoring the data log. Exiting... res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } logIter.validateFooter(); //not implemented for (i= 0; i < g_consumers.size(); i++) @@ -395,14 +405,14 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to finalize restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } } } clearConsumers(); - return 0; + return NDBT_ProgramExit(NDBT_OK); } // main template class Vector; From e10b50e6f13206ec8fc320518d4460ca39a12ed2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 16:50:32 +0200 Subject: [PATCH 25/56] Bug#12959 mysqltest crashes if testcase passed with -x option client/mysqltest.c: Fixes for mysqltest -x mysql-test/t/mysqltest.test: Test mysqltest -x mysql-test/include/mysqltest-x.inc: New BitKeeper file ``mysql-test/include/mysqltest-x.inc'' --- client/mysqltest.c | 12 +++++++----- mysql-test/include/mysqltest-x.inc | 2 ++ mysql-test/t/mysqltest.test | 13 +++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 mysql-test/include/mysqltest-x.inc diff --git a/client/mysqltest.c b/client/mysqltest.c index 33702e9d1d2..78d873468c4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2169,8 +2169,10 @@ int read_line(char *buf, int size) if (feof(cur_file->file)) { found_eof: - if (cur_file->file != stdin) + if (cur_file->file != stdin){ my_fclose(cur_file->file, MYF(0)); + cur_file->file= 0; + } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; lineno--; @@ -2556,10 +2558,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), argument= buff; } fn_format(buff, argument, "", "", 4); - DBUG_ASSERT(cur_file->file == 0); + DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); if (!(cur_file->file= my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - die("Could not open %s: errno = %d", argument, errno); + die("Could not open %s: errno = %d", buff, errno); + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); break; } case 'm': @@ -3746,9 +3749,8 @@ int main(int argc, char **argv) embedded_server_args, (char**) embedded_server_groups)) die("Can't initialize MySQL server"); - if (cur_file == file_stack) + if (cur_file == file_stack && cur_file->file == 0) { - DBUG_ASSERT(cur_file->file == 0); cur_file->file= stdin; cur_file->file_name= my_strdup("", MYF(MY_WME)); } diff --git a/mysql-test/include/mysqltest-x.inc b/mysql-test/include/mysqltest-x.inc new file mode 100644 index 00000000000..dd1468aed07 --- /dev/null +++ b/mysql-test/include/mysqltest-x.inc @@ -0,0 +1,2 @@ +echo Output from mysqltest-x.inc; + diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index bfb1919e75c..4c23f915503 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -792,6 +792,19 @@ select "a" as col1, "c" as col2; --error 1 --exec echo "save_master_pos; sync_with_master a;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test mysqltest arguments +# ---------------------------------------------------------------------------- + +# -x , use the file specified after -x as the test file +--exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc +--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc +--exec $MYSQL_TEST --result_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc +--error 1 +--exec $MYSQL_TEST -x non_existing_file.inc + + # ---------------------------------------------------------------------------- # TODO Test queries, especially their errormessages... so it's easy to debug # new scripts and diagnose errors From 50c44c9b529aaa694faaacf4353e1815b6133941 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 20:00:11 +0500 Subject: [PATCH 26/56] mysqld.cc, mysql_priv.h, sql_parse.cc: bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob after review fixes sql/mysql_priv.h: bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob after review fixes sql/mysqld.cc: bug#9948 changed client-charset behavior in 4.1.x libmysql, which issue BC prob after review fixes --- sql/mysql_priv.h | 1 + sql/mysqld.cc | 12 ++++++------ sql/sql_parse.cc | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0af3ea3af63..81224bdf54d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -931,6 +931,7 @@ extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; extern bool opt_disable_networking, opt_skip_show_db; +extern bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress, grant_option; extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 59b733b594c..2d232986997 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -271,7 +271,7 @@ arg_cmp_func Arg_comparator::comparator_matrix[4][2] = bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; -bool opt_skip_character_set_client_handshake= 0; +bool opt_character_set_client_handshake= 1; bool lower_case_table_names_used= 0; bool server_id_supplied = 0; bool opt_endinfo,using_udf_functions, locked_in_memory; @@ -4297,6 +4297,11 @@ Disable with --skip-bdb (will save memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, + "Don't use client side character set value sent during handshake.", + (gptr*) &opt_character_set_client_handshake, + (gptr*) &opt_character_set_client_handshake, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"character-set-server", 'C', "Set the default character set.", (gptr*) &default_character_set_name, (gptr*) &default_character_set_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, @@ -4755,11 +4760,6 @@ Can't be set to 1 if --log-slave-updates is used.", "Show user and password in SHOW SLAVE HOSTS on this master", (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, - "Don't use client side character set value sent during handshake.", - (gptr*) &opt_skip_character_set_client_handshake, - (gptr*) &opt_skip_character_set_client_handshake, - 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-grant-tables", OPT_SKIP_GRANT, "Start without grant tables. This gives all users FULL ACCESS to all tables!", (gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b8eae3aac74..a52e6daa698 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -811,12 +811,12 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); /* Use server character set and collation if - - opt_skip_character_set_client_handshake is set + - opt_character_set_client_handshake is not set - client has not specified a character set - client character set is the same as the servers - client character set doesn't exists in server */ - if (opt_skip_character_set_client_handshake || + if (!opt_character_set_client_handshake || !(thd->variables.character_set_client= get_charset((uint) net->read_pos[8], MYF(0))) || !my_strcasecmp(&my_charset_latin1, From 8b1751e5c35bbde1af36a104f1cf7b3c2ab4e919 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 5 Sep 2005 22:40:13 +0200 Subject: [PATCH 27/56] BUG#12984 mysqltest.test: different output from "exec NonExistsinfComamdn" mysql-test/r/mysqltest.result: Disable test for failing --exec and --system since output can't be piped to /dev/null on all platforms mysql-test/t/mysqltest.test: Disable test for failing --exec and --system since output can't be piped to /dev/null on all platforms Avoid "echo -e" by using a temporary .sql file for tests that require more than one line. --- mysql-test/r/mysqltest.result | 2 -- mysql-test/t/mysqltest.test | 30 ++++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 9175bdc7250..ae44233aab6 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -179,7 +179,6 @@ source database echo message echo message mysqltest: At line 1: Empty variable -mysqltest: At line 1: command "';' 2> /dev/null" failed mysqltest: At line 1: Missing argument in exec MySQL "MySQL" @@ -301,7 +300,6 @@ mysqltest: At line 1: First argument to dec must be a variable (start with $) mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do! -mysqltest: At line 1: system command 'NonExistsinfComamdn 2> /dev/null' failed test test2 test3 diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 4c23f915503..04fed048674 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -358,8 +358,11 @@ select 3 from t1 ; # Missing delimiter # The comment will be "sucked into" the sleep command since # delimiter is missing until after "show status" +--system echo "sleep 4" > var/log/mysqltest.sql +--system echo "# A comment" >> var/log/mysqltest.sql +--system echo "show status;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "sleep 4\n # A comment\nshow status;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 # # Extra delimiter @@ -423,8 +426,9 @@ echo ; # ---------------------------------------------------------------------------- # Illegal use of exec ---error 1 ---exec echo "--exec ';' 2> /dev/null" | $MYSQL_TEST 2>&1 +# Disabled, some shells prints the failed command regardless of pipes +#--error 1 +#--exec echo "--exec ';' 2> /dev/null" | $MYSQL_TEST 2>&1 --error 1 --exec echo "--exec " | $MYSQL_TEST 2>&1 @@ -671,8 +675,9 @@ system echo "hej" > /dev/null; --exec echo "system;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 ---error 1 ---exec echo "system NonExistsinfComamdn 2> /dev/null;" | $MYSQL_TEST 2>&1 +# Disabled, some shells prints the failed command regardless of pipes +#--error 1 +#--exec echo "system NonExistsinfComamdn 2> /dev/null;" | $MYSQL_TEST 2>&1 --disable_abort_on_error system NonExistsinfComamdn; @@ -722,12 +727,21 @@ while ($i) --exec echo "end;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "{;" | $MYSQL_TEST 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0)\necho hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "{echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0)\n{echo hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0){" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0){\n echo hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 # ---------------------------------------------------------------------------- # Test error messages returned from comments starting with a command From 103458544bc3c07100dac2f22c3f857f7cff2618 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 09:36:32 +0200 Subject: [PATCH 28/56] comment out innochecksum until fixed --- extra/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/Makefile.am b/extra/Makefile.am index 457fddce673..9fac05d0160 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -38,7 +38,7 @@ $(top_builddir)/include/mysqld_ername.h: $(top_builddir)/include/mysqld_error.h $(top_builddir)/include/sql_state.h: $(top_builddir)/include/mysqld_error.h bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \ - resolve_stack_dump mysql_waitpid innochecksum + resolve_stack_dump mysql_waitpid # innochecksum noinst_PROGRAMS = charset2html # Don't update the files from bitkeeper From 3ae91695de838aad59a01f7766ee1aa43470ea6f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 09:40:42 +0200 Subject: [PATCH 29/56] BUG#12959 mysqltest crashes if testcase passed with -x option - Update test cases mysql-test/t/mysqltest.test: Uncomment the mysqltest -x test. Can't get the output to end up in the result file. --- mysql-test/t/mysqltest.test | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 04fed048674..39c1e867f28 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -812,11 +812,11 @@ select "a" as col1, "c" as col2; # ---------------------------------------------------------------------------- # -x , use the file specified after -x as the test file ---exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc ---exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc ---exec $MYSQL_TEST --result_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc ---error 1 ---exec $MYSQL_TEST -x non_existing_file.inc +#--exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--exec $MYSQL_TEST --result_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--error 1 +#--exec $MYSQL_TEST -x non_existing_file.inc 2>&1 # ---------------------------------------------------------------------------- From f5f896b4b96f18927864a70cbf23b09d922842fa Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 11:16:53 +0300 Subject: [PATCH 30/56] support of concurent query cache resizing (BUG#12848) sql/mysql_priv.h: initialisation moved to mysqld.cc sql/mysqld.cc: initialisation moved to mysqld.cc sql/sql_cache.cc: support of concurent query cache resizing: - resizing made atomic - check stack size after each quard mutex lock sql/sql_cache.h: initialisation moved to mysqld.cc removed uneed parameter (now it is always under guard mutex protection or called from destruction) --- sql/mysql_priv.h | 2 + sql/mysqld.cc | 1 + sql/sql_cache.cc | 116 +++++++++++++++++++++++++++++++++-------------- sql/sql_cache.h | 5 +- 4 files changed, 87 insertions(+), 37 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9b9edd905ad..21d7afbd6cb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -318,6 +318,7 @@ inline THD *_current_thd(void) #define query_cache_store_query(A, B) query_cache.store_query(A, B) #define query_cache_destroy() query_cache.destroy() #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) +#define query_cache_init() query_cache.init() #define query_cache_resize(A) query_cache.resize(A) #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) #define query_cache_invalidate1(A) query_cache.invalidate(A) @@ -329,6 +330,7 @@ inline THD *_current_thd(void) #define query_cache_store_query(A, B) #define query_cache_destroy() #define query_cache_result_size_limit(A) +#define query_cache_init() #define query_cache_resize(A) #define query_cache_invalidate3(A, B, C) #define query_cache_invalidate1(A) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 17157d0ebe2..5d6e270150e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2461,6 +2461,7 @@ You should consider changing lower_case_table_names to 1 or 2", unireg_abort(1); } query_cache_result_size_limit(query_cache_limit); + query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 667b6e546d3..071dac0d3c5 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -563,13 +563,18 @@ void query_cache_insert(NET *net, const char *packet, ulong length) { DBUG_ENTER("query_cache_insert"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) - DBUG_VOID_RETURN; -#endif - STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) @@ -612,14 +617,20 @@ void query_cache_abort(NET *net) { DBUG_ENTER("query_cache_abort"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) - DBUG_VOID_RETURN; -#endif if (net->query_cache_query != 0) // Quick check on unlocked structure { STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) // Test if changed by other thread @@ -641,14 +652,20 @@ void query_cache_end_of_result(NET *net) { DBUG_ENTER("query_cache_end_of_result"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; -#endif - if (net->query_cache_query != 0) // Quick check on unlocked structure { STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) @@ -728,9 +745,14 @@ ulong Query_cache::resize(ulong query_cache_size_arg) DBUG_ENTER("Query_cache::resize"); DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size, query_cache_size_arg)); - free_cache(0); + DBUG_ASSERT(initialized); + STRUCT_LOCK(&structure_guard_mutex); + if (query_cache_size > 0) + free_cache(); query_cache_size= query_cache_size_arg; - DBUG_RETURN(::query_cache_size= init_cache()); + ::query_cache_size= init_cache(); + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(::query_cache_size); } @@ -1307,7 +1329,7 @@ void Query_cache::destroy() } else { - free_cache(1); + free_cache(); pthread_mutex_destroy(&structure_guard_mutex); initialized = 0; } @@ -1336,8 +1358,6 @@ ulong Query_cache::init_cache() int align; DBUG_ENTER("Query_cache::init_cache"); - if (!initialized) - init(); approx_additional_data_size = (sizeof(Query_cache) + sizeof(gptr)*(def_query_hash_size+ def_table_hash_size)); @@ -1395,14 +1415,9 @@ ulong Query_cache::init_cache() goto err; query_cache_size -= additional_data_size; - STRUCT_LOCK(&structure_guard_mutex); - - if (!(cache = (byte *) - my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) - { - STRUCT_UNLOCK(&structure_guard_mutex); + if (!(cache= (byte *) + my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) goto err; - } DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins", query_cache_size, min_allocation_unit, mem_bin_num)); @@ -1482,7 +1497,6 @@ ulong Query_cache::init_cache() queries_in_cache = 0; queries_blocks = 0; - STRUCT_UNLOCK(&structure_guard_mutex); DBUG_RETURN(query_cache_size + additional_data_size + approx_additional_data_size); @@ -1498,6 +1512,7 @@ void Query_cache::make_disabled() { DBUG_ENTER("Query_cache::make_disabled"); query_cache_size= 0; + queries_blocks= 0; free_memory= 0; bins= 0; steps= 0; @@ -1509,14 +1524,11 @@ void Query_cache::make_disabled() } -void Query_cache::free_cache(my_bool destruction) +void Query_cache::free_cache() { DBUG_ENTER("Query_cache::free_cache"); if (query_cache_size > 0) { - if (!destruction) - STRUCT_LOCK(&structure_guard_mutex); - flush_cache(); #ifndef DBUG_OFF if (bins[0].free_blocks == 0) @@ -1538,8 +1550,6 @@ void Query_cache::free_cache(my_bool destruction) make_disabled(); hash_free(&queries); hash_free(&tables); - if (!destruction) - STRUCT_UNLOCK(&structure_guard_mutex); } DBUG_VOID_RETURN; } @@ -2149,7 +2159,19 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min, } if (!under_guard) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(0); + } + } /* Free old queries until we have enough memory to store this block */ Query_cache_block *block; @@ -2606,6 +2628,17 @@ void Query_cache::pack_cache() { DBUG_ENTER("Query_cache::pack_cache"); STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_VOID_RETURN; + } + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); byte *border = 0; @@ -2915,6 +2948,7 @@ my_bool Query_cache::join_results(ulong join_limit) STRUCT_LOCK(&structure_guard_mutex); if (queries_blocks != 0) { + DBUG_ASSERT(query_cache_size > 0); Query_cache_block *block = queries_blocks; do { @@ -3209,7 +3243,19 @@ my_bool Query_cache::check_integrity(bool not_locked) DBUG_RETURN(0); } if (!not_locked) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_RETURN(0); + } + } if (hash_check(&queries)) { diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 454f0318c12..854937d0158 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -310,10 +310,9 @@ protected: Following function control structure_guard_mutex by themself or don't need structure_guard_mutex */ - void init(); ulong init_cache(); void make_disabled(); - void free_cache(my_bool destruction); + void free_cache(); Query_cache_block *write_block_data(ulong data_len, gptr data, ulong header_len, Query_cache_block::block_type type, @@ -346,6 +345,8 @@ protected: uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); + /* initialize cache (mutex) */ + void init(); /* resize query cache (return real query size, 0 if disabled) */ ulong resize(ulong query_cache_size); inline void result_size_limit(ulong limit){query_cache_limit=limit;} From e254105bec21fc101326ca366ef85cd0d8d4ed98 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 14:48:18 +0500 Subject: [PATCH 31/56] item_cmpfunc.h: Bug 12611 : ESCAPE + LIKE do not work when the escape char is a multibyte one Forgot to commit this file in the previous changeset, together with other files. sql/item_cmpfunc.h: Bug 12611 : ESCAPE + LIKE do not work when the escape char is a multibyte one Forgot to commit this file in the previous changeset, together with other files. --- sql/item_cmpfunc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..697b26bb1ae 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -879,7 +879,7 @@ class Item_func_like :public Item_bool_func2 Item *escape_item; public: - char escape; + int escape; Item_func_like(Item *a,Item *b, Item *escape_arg) :Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), From 94c98b516aab22f13f2c5fb4a86546edd201eeba Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 15:23:03 +0500 Subject: [PATCH 32/56] mysqld.cc: after merge fix sql/mysqld.cc: after merge fix --- sql/mysqld.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 919f7c3d2e2..76ee08d73a3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -339,7 +339,6 @@ bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; bool opt_character_set_client_handshake= 1; -bool lower_case_table_names_used= 0; bool server_id_supplied = 0; bool opt_endinfo,using_udf_functions, locked_in_memory; bool opt_using_transactions, using_update_log; From 8bb920586e85685c242e5a4cbde533cd60cf792c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 12:33:36 +0200 Subject: [PATCH 33/56] Detect comment with command using extra delimiter mysql-test/include/have_lowercase0.inc: Remove extra ; at end of command(causing it to be skipped) mysql-test/r/mysqltest.result: Update test results mysql-test/t/mysqltest.test: Add test to detect "comment with command" with extra ; delimiter Fix extra ; delimiter --- client/mysqltest.c | 16 ++++++++++++++++ mysql-test/include/have_lowercase0.inc | 4 ++-- mysql-test/r/mysqltest.result | 1 + mysql-test/t/mysqltest.test | 4 +++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index da9d165e519..212f9b64ea1 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3901,6 +3901,22 @@ void get_query_type(struct st_query* q) q->type != Q_DISABLE_PARSING) q->type= Q_COMMENT; } + else if (q->type == Q_COMMENT_WITH_COMMAND && + q->query[q->first_word_len-1] == ';') + { + /* + Detect comment with command using extra delimiter + Ex --disable_query_log; + ^ Extra delimiter causing the command + to be skipped + */ + save= q->query[q->first_word_len-1]; + q->query[q->first_word_len-1]= 0; + type= find_type(q->query, &command_typelib, 1+2); + q->query[q->first_word_len-1]= save; + if (type > 0) + die("Extra delimiter \";\" found"); + } DBUG_VOID_RETURN; } diff --git a/mysql-test/include/have_lowercase0.inc b/mysql-test/include/have_lowercase0.inc index f967c18928b..8d3ae02f61e 100644 --- a/mysql-test/include/have_lowercase0.inc +++ b/mysql-test/include/have_lowercase0.inc @@ -1,4 +1,4 @@ --require r/lowercase0.require ---disable_query_log; +--disable_query_log show variables like "lower_case_%"; ---enable_query_log; +--enable_query_log diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 4757d8b1a03..c643a5ae647 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -152,6 +152,7 @@ mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: Missing delimiter mysqltest: At line 1: Extra delimiter ";" found +mysqltest: At line 1: Extra delimiter ";" found MySQL "MySQL" MySQL: The world''s most popular open source database diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 2a90e2be8d1..c903749839d 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -369,6 +369,8 @@ select 3 from t1 ; # --error 1 --exec echo "--sleep 4;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--disable_query_log;" | $MYSQL_TEST 2>&1 # Allow trailing # comment @@ -592,7 +594,7 @@ while ($num) --source var/tmp/sourced1.sql dec $num; } ---enable_abort_on_error; +--enable_abort_on_error --enable_query_log # ---------------------------------------------------------------------------- From 965afd45a18f0af3395c4750c072788e1f9b2ee1 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 16:16:10 +0500 Subject: [PATCH 34/56] func_like.result, func_like.test: adding test case. item_cmpfunc.cc: Bug#12611 ESCAPE + LIKE do not work when the escape char is a multibyte one Additional fix for 8bit character sets: escape character must be converted into operation character set. sql/item_cmpfunc.cc: Bug#12611 ESCAPE + LIKE do not work when the escape char is a multibyte one Additional fix for 8bit character sets: escape character must be converted into operation character set. mysql-test/t/func_like.test: adding test case. mysql-test/r/func_like.result: adding test case. --- mysql-test/r/func_like.result | 7 +++++++ mysql-test/t/func_like.test | 17 +++++++++++++++++ sql/item_cmpfunc.cc | 19 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index a58432cb06e..bc658f9f7de 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -158,3 +158,10 @@ DROP TABLE t1; select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin 1 +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; +'andre%' like 'andreÊ%' escape 'Ê' +1 +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; +_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' +1 diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 684d7032038..4e1183afeff 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -96,4 +96,21 @@ DROP TABLE t1; # select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +# +# Check 8bit escape character +# +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; + +# Check 8bit escape character with charset conversion: +# For "a LIKE b ESCAPE c" expressions, +# escape character is converted into the operation character set, +# which is result of aggregation of character sets of "a" and "b". +# "c" itself doesn't take part in aggregation, because its collation +# doesn't matter, escape character is always compared binary. +# In the example below, escape character is converted from koi8r into cp1251: +# +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; + +# # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c869e7f5c65..ead07892bee 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2307,7 +2307,24 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) } else { - escape= *(escape_str->ptr()); + /* + In the case of 8bit character set, we pass native + code instead of Unicode code as "escape" argument. + Convert to "cs" if charset of escape differs. + */ + uint32 unused; + if (escape_str->needs_conversion(escape_str->length(), + escape_str->charset(), cs, &unused)) + { + char ch; + uint errors; + uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(), + escape_str->length(), + escape_str->charset(), &errors); + escape= cnvlen ? ch : '\\'; + } + else + escape= *(escape_str->ptr()); } } else From 61a5fac1cc0e2cddcc98db8396f06b719cfcad1a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 16:19:59 +0500 Subject: [PATCH 35/56] Bug #6172 RAND(a) should only accept constant values as arguments(2nd version) Argument of RAND function can be constant value only --- mysql-test/r/func_math.result | 5 ++++ mysql-test/r/ps.result | 48 +++++++++++++++++------------------ mysql-test/t/func_math.test | 9 +++++++ mysql-test/t/ps.test | 4 +-- sql/item_func.cc | 5 ++++ 5 files changed, 43 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 80b15d1d3c8..b36902d7872 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -140,3 +140,8 @@ drop table t1; select abs(-2) * -2; abs(-2) * -2 -4 +create table t1 (i int); +insert into t1 values (1); +select rand(i) from t1; +ERROR HY000: Incorrect arguments to RAND +drop table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index c17015df757..f5bf3ffa96d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -334,39 +334,37 @@ create table t1 (a int); insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; select rand(), -cast(rand(10)*@precision as unsigned integer), -cast(rand(a)*@precision as unsigned integer) from t1; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) +cast(rand(10)*@precision as unsigned integer) from t1; +rand() cast(rand(10)*@precision as unsigned integer) +- 6570515219 +- 1282061302 +- 6698761160 +- 9647622201 +prepare stmt from +"select rand(), + cast(rand(10)*@precision as unsigned integer), + cast(rand(?)*@precision as unsigned integer) from t1"; +set @var=1; +execute stmt using @var; +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) - 6570515219 - - 1282061302 - - 6698761160 - - 9647622201 - -prepare stmt from -"select rand(), - cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), - cast(rand(?)*@precision as unsigned integer) from t1"; -set @var=1; -execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 - 4054035371 -- 1282061302 - 8716141803 -- 6698761160 - 1418603212 -- 9647622201 - 944590960 set @var=2; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 6555866465 -- 1282061302 6238114970 1223466192 -- 6698761160 6511989195 6449731873 -- 9647622201 3845601374 8578261098 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 6555866465 +- 1282061302 1223466192 +- 6698761160 6449731873 +- 9647622201 8578261098 set @var=3; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 9057697559 -- 1282061302 6238114970 3730790581 -- 6698761160 6511989195 1480860534 -- 9647622201 3845601374 6211931236 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 9057697559 +- 1282061302 3730790581 +- 6698761160 1480860534 +- 9647622201 6211931236 drop table t1; deallocate prepare stmt; create database mysqltest1; diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index ebbc594952c..c75454a96d4 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -77,4 +77,13 @@ drop table t1; # select abs(-2) * -2; +# +# Bug #6172 RAND(a) should only accept constant values as arguments +# +create table t1 (i int); +insert into t1 values (1); +--error 1210 +select rand(i) from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 5a2e469fbc4..c4cb0056763 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -368,12 +368,10 @@ insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; --replace_column 1 - 3 - select rand(), - cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer) from t1; + cast(rand(10)*@precision as unsigned integer) from t1; prepare stmt from "select rand(), cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), cast(rand(?)*@precision as unsigned integer) from t1"; set @var=1; --replace_column 1 - 3 - diff --git a/sql/item_func.cc b/sql/item_func.cc index 41573406949..ebb200ec4da 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1038,6 +1038,11 @@ bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, used_tables_cache|= RAND_TABLE_BIT; if (arg_count) { // Only use argument once in query + if (!args[0]->const_during_execution()) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND"); + return TRUE; + } /* Allocate rand structure once: we must use thd->current_arena to create rand in proper mem_root if it's a prepared statement or From 2d1c26cc61f83a6d3522fa677c8e7d6d0a89732c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 14:38:21 +0300 Subject: [PATCH 36/56] InnoDB: Reject foreign keys in temporary tables. Closes bug #12084. innobase/dict/dict0dict.c: Add reject_fks parameter to dict_create_foreign_constraints_low and dict_create_foreign_constraints. innobase/include/dict0dict.h: Add reject_fks parameter to dict_create_foreign_constraints. innobase/include/row0mysql.h: Add reject_fks parameter to row_table_add_foreign_constraints. innobase/row/row0mysql.c: Add reject_fks parameter to row_table_add_foreign_constraints. sql/ha_innodb.cc: In create, pass correct reject_fks argument to row_table_add_foreign_constraints depending on whether we're creating a temporary table or not. Also move duplicated cleanup code to a single place. --- innobase/dict/dict0dict.c | 26 +++++++++++++-- innobase/include/dict0dict.h | 5 ++- innobase/include/row0mysql.h | 6 +++- innobase/row/row0mysql.c | 8 +++-- sql/ha_innodb.cc | 63 +++++++++++++----------------------- 5 files changed, 60 insertions(+), 48 deletions(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9580a80e7e7..5eee57c250b 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2871,8 +2871,12 @@ dict_create_foreign_constraints_low( table2 can be written also with the database name before it: test.table2; the default database is the database of parameter name */ - const char* name) /* in: table full name in the normalized form + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) + /* in: if TRUE, fail with error code + DB_CANNOT_ADD_CONSTRAINT if any foreign + keys are found. */ { dict_table_t* table; dict_table_t* referenced_table; @@ -2994,6 +2998,18 @@ loop: } if (*ptr == '\0') { + /* The proper way to reject foreign keys for temporary + tables would be to split the lexing and syntactical + analysis of foreign key clauses from the actual adding + of them, so that ha_innodb.cc could first parse the SQL + command, determine if there are any foreign keys, and + if so, immediately reject the command if the table is a + temporary one. For now, this kludge will work. */ + if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) + { + return DB_CANNOT_ADD_CONSTRAINT; + } + /**********************************************************/ /* The following call adds the foreign key constraints to the data dictionary system tables on disk */ @@ -3417,9 +3433,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { char* str; ulint err; @@ -3428,7 +3447,8 @@ dict_create_foreign_constraints( str = dict_strip_comments(sql_string); heap = mem_heap_create(10000); - err = dict_create_foreign_constraints_low(trx, heap, str, name); + err = dict_create_foreign_constraints_low(trx, heap, str, name, + reject_fks); mem_heap_free(heap); mem_free(str); diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index d9cda402bac..a1232acdca7 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -228,9 +228,12 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ /************************************************************************** Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 4e6ff73b0f8..a61705b90be 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -355,9 +355,13 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name); /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks); /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ + /************************************************************************* The master thread in srv0srv.c calls this regularly to drop tables which we must drop in background after queries to them have ended. Such lazy diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 29239210183..26aae117d1d 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2088,9 +2088,12 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ - const char* name) /* in: table full name in the + const char* name, /* in: table full name in the normalized form database_name/table_name */ + ibool reject_fks) /* in: if TRUE, fail with error + code DB_CANNOT_ADD_CONSTRAINT if + any foreign keys are found. */ { ulint err; @@ -2111,7 +2114,8 @@ row_table_add_foreign_constraints( trx->dict_operation = TRUE; - err = dict_create_foreign_constraints(trx, sql_string, name); + err = dict_create_foreign_constraints(trx, sql_string, name, + reject_fks); if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index aa53b69a617..4ed5fadb603 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4687,13 +4687,7 @@ ha_innobase::create( form->s->row_type != ROW_TYPE_REDUNDANT); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } /* Look for a primary key */ @@ -4717,13 +4711,7 @@ ha_innobase::create( error = create_clustered_index_when_no_primary(trx, norm_name); if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4732,13 +4720,7 @@ ha_innobase::create( first */ if ((error = create_index(trx, form, norm_name, (uint) primary_key_no))) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4747,14 +4729,7 @@ ha_innobase::create( if (i != (uint) primary_key_no) { if ((error = create_index(trx, form, norm_name, i))) { - - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } } @@ -4767,21 +4742,18 @@ ha_innobase::create( current_thd->query_length, current_thd->charset())) { error = HA_ERR_OUT_OF_MEM; - } else { - error = row_table_add_foreign_constraints(trx, - q.str, norm_name); - - error = convert_error_code_to_mysql(error, NULL); + + goto cleanup; } + error = row_table_add_foreign_constraints(trx, + q.str, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE); + + error = convert_error_code_to_mysql(error, NULL); + if (error) { - innobase_commit_low(trx); - - row_mysql_unlock_data_dictionary(trx); - - trx_free_for_mysql(trx); - - DBUG_RETURN(error); + goto cleanup; } } @@ -4821,6 +4793,15 @@ ha_innobase::create( trx_free_for_mysql(trx); DBUG_RETURN(0); + +cleanup: + innobase_commit_low(trx); + + row_mysql_unlock_data_dictionary(trx); + + trx_free_for_mysql(trx); + + DBUG_RETURN(error); } /********************************************************************* From d17b361e8e2127f19930c709bfeb02f3201e6a57 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 16:08:05 +0300 Subject: [PATCH 37/56] Add testcase for bug #12084. --- mysql-test/r/innodb.result | 12 ++++++++++++ mysql-test/t/innodb.test | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d7f7536d401..cc074c8ebf5 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2527,3 +2527,15 @@ SELECT * FROM t1; id 1 DROP TABLE t2, t1; +CREATE TABLE t1 +( +id INT PRIMARY KEY +) ENGINE=InnoDB; +CREATE TEMPORARY TABLE t2 +( +id INT NOT NULL PRIMARY KEY, +b INT, +FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +Got one of the listed errors +DROP TABLE t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 0bd3d8137a3..7d449ac9261 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1451,3 +1451,18 @@ TRUNCATE t1; INSERT INTO t1 (id) VALUES (NULL); SELECT * FROM t1; DROP TABLE t2, t1; + +-- Test that foreign keys in temporary tables are not accepted (bug #12084) +CREATE TABLE t1 +( + id INT PRIMARY KEY +) ENGINE=InnoDB; + +--error 1005,1005 +CREATE TEMPORARY TABLE t2 +( + id INT NOT NULL PRIMARY KEY, + b INT, + FOREIGN KEY (b) REFERENCES test.t1(id) +) ENGINE=InnoDB; +DROP TABLE t1; From 050d992bcdb7a16cd7d75577c0d3e9ad5ed5688c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 15:41:13 +0200 Subject: [PATCH 38/56] Bug #12984 mysqltest.test: different output from "exec NonExistsinfComamdn" - Common error handling regardless of --ps-protocol or not. client/mysqltest.c: Merge normal_handle_error and run_query_stmt_handle_error to get consistent functionality and error messages regardless if --ps-protocol is used or not Call handle_error when error occured to check for expected error codes/states Call handle_no_error when no error ahs occured to check if an error was expected --- client/mysqltest.c | 239 +++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 152 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 212f9b64ea1..a01322181e0 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -481,9 +481,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); -static int normal_handle_error(const char *query, struct st_query *q, - MYSQL *mysql, DYNAMIC_STRING *ds); -static int normal_handle_no_error(struct st_query *q); +static int handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds); +static int handle_no_error(struct st_query *q); static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { @@ -2071,11 +2072,12 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, CLIENT_MULTI_STATEMENTS)) { - error= normal_handle_error("connect", q, con, ds); + error= handle_error("connect", q, mysql_errno(con), mysql_error(con), + mysql_sqlstate(con), ds); *create_conn= 0; goto err; } - else if (normal_handle_no_error(q)) + else if (handle_no_error(q)) { /* Fail if there was no error but we expected it. @@ -2964,8 +2966,6 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds); static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, DYNAMIC_STRING *ds); @@ -3049,12 +3049,13 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) (!(last_result= res= mysql_store_result(mysql)) && mysql_field_count(mysql))) { - if (normal_handle_error(query, q, mysql, ds)) + if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds)) error= 1; goto end; } - if (normal_handle_no_error(q)) + if (handle_no_error(q)) { error= 1; goto end; @@ -3169,14 +3170,15 @@ end: /* - Handle errors which occurred after execution of conventional (non-prepared) - statement. + Handle errors which occurred after execution SYNOPSIS - normal_handle_error() + handle_error() query - query string q - query context - mysql - connection through which query was sent to server + err_errno - error number + err_error - error message + err_sqlstate - sql state ds - dynamic string which is used for output buffer NOTE @@ -3188,85 +3190,83 @@ end: 1 - Some other error was expected. */ -static int normal_handle_error(const char *query, struct st_query *q, - MYSQL *mysql, DYNAMIC_STRING *ds) +static int handle_error(const char *query, struct st_query *q, + unsigned int err_errno, const char *err_error, + const char* err_sqlstate, DYNAMIC_STRING *ds) { uint i; - - DBUG_ENTER("normal_handle_error"); + + DBUG_ENTER("handle_error"); if (q->require_file) abort_not_supported_test(); - + if (q->abort_on_error) die("query '%s' failed: %d: %s", query, - mysql_errno(mysql), mysql_error(mysql)); - else + err_errno, err_error); + + for (i= 0 ; (uint) i < q->expected_errors ; i++) { - for (i= 0 ; (uint) i < q->expected_errors ; i++) + if (((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == err_errno)) || + ((q->expected_errno[i].type == ERR_SQLSTATE) && + (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, mysql_sqlstate(mysql)) == 0))) + if (q->expected_errors == 1) { - if (q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds, "ERROR ", 6); - replace_dynstr_append(ds, mysql_sqlstate(mysql)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, mysql_error(mysql)); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - /* OK */ - DBUG_RETURN(0); + /* Only log error if there is one possible error */ + dynstr_append_mem(ds, "ERROR ", 6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds,"\n",1); } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0].type == ERR_SQLSTATE || + (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0)) + dynstr_append(ds,"Got one of the listed errors\n"); + /* OK */ + DBUG_RETURN(0); } - - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); - - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, mysql_sqlstate(mysql)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds, mysql_error(mysql)); - dynstr_append_mem(ds, "\n", 1); - - if (i) - { - if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), - q->expected_errno[0].code.errnum); - else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, mysql_sqlstate(mysql), - q->expected_errno[0].code.sqlstate); - DBUG_RETURN(1); - } - - /* - If we do not abort on error, failure to run the query does not fail the - whole test case. - */ - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), - mysql_error(mysql)); - DBUG_RETURN(0); } - return 0; /* Keep compiler happy */ + + DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds, "\n", 1); + + if (i) + { + if (q->expected_errno[0].type == ERR_ERRNO) + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, err_errno, + q->expected_errno[0].code.errnum); + else + verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, err_sqlstate, + q->expected_errno[0].code.sqlstate); + DBUG_RETURN(1); + } + + /* + If we do not abort on error, failure to run the query does not fail the + whole test case. + */ + verbose_msg("query '%s' failed: %d: %s", q->query, err_errno, + err_error); + DBUG_RETURN(0); } /* - Handle absence of errors after execution of convetional statement. + Handle absence of errors after execution SYNOPSIS - normal_handle_error() + handle_no_error() q - context of query RETURN VALUE @@ -3274,9 +3274,9 @@ static int normal_handle_error(const char *query, struct st_query *q, 1 - Some error was expected from this query. */ -static int normal_handle_no_error(struct st_query *q) +static int handle_no_error(struct st_query *q) { - DBUG_ENTER("normal_handle_no_error"); + DBUG_ENTER("handle_no_error"); if (q->expected_errno[0].type == ERR_ERRNO && q->expected_errno[0].code.errnum != 0) @@ -3370,17 +3370,17 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { if (q->abort_on_error) { - die("unable to prepare statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + die("query '%s' failed: %d: %s", query, + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } else { /* Preparing is part of normal execution and some errors may be expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); + error= handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), + ds); goto end; } } @@ -3413,7 +3413,9 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) else { /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); + error= handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), + ds); goto end; } } @@ -3449,18 +3451,16 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) else { /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); + error= handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), + ds); goto end; } } /* If we got here the statement was both executed and read succeesfully */ - - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (handle_no_error(q)) { - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); error= 1; goto end; } @@ -3740,71 +3740,6 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) } -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds) -{ - if (q->require_file) /* FIXME don't understand this one */ - { - abort_not_supported_test(); - } - - if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - else - { - int i; - - for (i=0 ; (uint) i < q->expected_errors ; i++) - { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_stmt_errno(stmt))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, - mysql_stmt_sqlstate(stmt)) == 0))) - { - if (i == 0 && q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt)); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append(ds,mysql_stmt_error(stmt)); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - return 0; /* Ok */ - } - } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, - q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt)); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append(ds, mysql_stmt_error(stmt)); - dynstr_append_mem(ds,"\n",1); - if (i) - { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); - return 1; /* Error */ - } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - return 0; - } - - return 0; -} - /****************************************************************************\ * Functions to match SQL statements that can be prepared \****************************************************************************/ From f1cc5049810a0bcf701fe994aa3c4f6c5bbae8ab Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 18:03:08 +0400 Subject: [PATCH 39/56] item_cmpfunc.h: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The classes Item_func_between, Item_func_if, Item_func_in are modified. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. The class Item_func_opt_neg is added to factor out the functionality common for the modified classes Item_func_between and Item_func_in. item_cmpfunc.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Added Item_func_between::fix_fields(), Item_func_if::fix_fields(), Item_func_in::fix_fields(). They correct generic calculation of the not_null_tables attribute when it is needed. Modified Item_func_between::val_int(), Item_func_in::val_int(). opt_range.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The function get_mm_tree() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql_yacc.yy: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions. join_outer.result: Fixed some testcases results (bugs #12101, #12102) join_outer.test: Added testcases for bugs #12101, #12102 mysql-test/t/join_outer.test: Added testcases for bugs #12101, #12102 mysql-test/r/join_outer.result: Fixed some testcases results (bugs #12101, #12102) sql/sql_yacc.yy: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions. sql/opt_range.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The function get_mm_tree() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/item_cmpfunc.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Added Item_func_between::fix_fields(), Item_func_if::fix_fields(), Item_func_in::fix_fields(). They correct generic calculation of the not_null_tables attribute when it is needed. Modified Item_func_between::val_int(), Item_func_in::val_int(). sql/item_cmpfunc.h: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The classes Item_func_between, Item_func_if, Item_func_in are modified. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. The class Item_func_opt_neg is added to factor out the functionality common for the modified classes Item_func_between and Item_func_in. --- mysql-test/r/join_outer.result | 133 +++++++++++++++++++++++++++ mysql-test/t/join_outer.test | 46 ++++++++++ sql/item_cmpfunc.cc | 158 +++++++++++++++++++++++++++++++-- sql/item_cmpfunc.h | 55 ++++++++---- sql/opt_range.cc | 5 +- sql/sql_yacc.yy | 32 +++++-- 6 files changed, 397 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index b6265aac4a3..d5ae1a58e83 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -883,3 +883,136 @@ Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() drop table t1, t2; set group_concat_max_len=default; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index fa2dd93c9ba..05cd2fb152e 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -625,4 +625,50 @@ select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; drop table t1, t2; set group_concat_max_len=default; +# +# Test for bugs +# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN +# #12102: erroneously missing outer join elimination in case of WHERE IN/IF +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); + +DROP TABLE t1,t2; + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9146b3c3b9e..99ca0df355b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -820,6 +820,54 @@ longlong Item_func_interval::val_int() return i-1; } + +/* + Perform context analysis of a BETWEEN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_between as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2)) + T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_between::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) +{ + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ + if (pred_level && !negated) + return 0; + + /* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */ + not_null_tables_cache= args[0]->not_null_tables() | + (args[1]->not_null_tables() & args[2]->not_null_tables()); + + return 0; +} + + void Item_func_between::fix_length_and_dec() { max_length= 1; @@ -871,8 +919,9 @@ longlong Item_func_between::val_int() a=args[1]->val_str(&value1); b=args[2]->val_str(&value2); if (!args[1]->null_value && !args[2]->null_value) - return (sortcmp(value,a,cmp_collation.collation) >= 0 && - sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0; + return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && + sortcmp(value,b,cmp_collation.collation) <= 0) != + negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -894,7 +943,7 @@ longlong Item_func_between::val_int() a=args[1]->val_int(); b=args[2]->val_int(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -914,7 +963,7 @@ longlong Item_func_between::val_int() a=args[1]->val(); b=args[2]->val(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -926,7 +975,7 @@ longlong Item_func_between::val_int() null_value= value >= a; } } - return 0; + return (longlong) (!null_value && negated); } @@ -1019,6 +1068,49 @@ Item_func_ifnull::val_str(String *str) } +/* + Perform context analysis of an IF item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_if as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(IF(e,e1,e2) = T1(IF(e,e1,e2)) + T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2)) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_if::fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + args[0]->top_level_item(); + + if (Item_func::fix_fields(thd, tlist, ref)) + return 1; + + not_null_tables_cache= (args[1]->not_null_tables() + & args[2]->not_null_tables()); + + return 0; +} + + void Item_func_if::fix_length_and_dec() { @@ -1750,6 +1842,56 @@ bool Item_func_in::nulls_in_row() } +/* + Perform context analysis of an IN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_in as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei))) + T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_in::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + Item **arg, **arg_end; + + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ + if (pred_level && negated) + return 0; + + /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */ + not_null_tables_cache= ~(table_map) 0; + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++) + not_null_tables_cache&= (*arg)->not_null_tables(); + not_null_tables_cache|= (*args)->not_null_tables(); + return 0; +} + + static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, @@ -1840,7 +1982,7 @@ longlong Item_func_in::val_int() { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); - return tmp; + return (longlong) (!null_value && tmp != negated); } in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) @@ -1849,11 +1991,11 @@ longlong Item_func_in::val_int() for (uint i=1 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) - return 1; // Would maybe be nice with i ? + return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; - return 0; + return (longlong) (!null_value && negated); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..2ebf794f0a8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -358,17 +358,49 @@ public: }; -class Item_func_between :public Item_int_func +/* + The class Item_func_opt_neg is defined to factor out the functionality + common for the classes Item_func_between and Item_func_in. The objects + of these classes can express predicates or there negations. + The alternative approach would be to create pairs Item_func_between, + Item_func_notbetween and Item_func_in, Item_func_notin. + +*/ + +class Item_func_opt_neg :public Item_int_func +{ +public: + bool negated; /* <=> the item represents NOT */ + bool pred_level; /* <=> [NOT] is used on a predicate level */ +public: + Item_func_opt_neg(Item *a, Item *b, Item *c) + :Item_int_func(a, b, c), negated(0), pred_level(0) {} + Item_func_opt_neg(List &list) + :Item_int_func(list), negated(0), pred_level(0) {} +public: + inline void negate() { negated= !negated; } + inline void top_level_item() { pred_level= 1; } + Item *neg_transformer(THD *thd) + { + negated= !negated; + return this; + } +}; + + +class Item_func_between :public Item_func_opt_neg { DTCollation cmp_collation; public: Item_result cmp_type; String value0,value1,value2; - Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} + Item_func_between(Item *a, Item *b, Item *c) + :Item_func_opt_neg(a, b, c) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void print(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -433,15 +465,9 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) - { - DBUG_ASSERT(fixed == 0); - args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); - } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); const char *func_name() const { return "if"; } - table_map not_null_tables() const { return 0; } }; @@ -736,7 +762,7 @@ public: } }; -class Item_func_in :public Item_int_func +class Item_func_in :public Item_func_opt_neg { Item_result cmp_type; in_vector *array; @@ -745,11 +771,12 @@ class Item_func_in :public Item_int_func DTCollation cmp_collation; public: Item_func_in(List &list) - :Item_int_func(list), array(0), in_item(0), have_null(0) + :Item_func_opt_neg(list), array(0), in_item(0), have_null(0) { allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void cleanup() { @@ -769,12 +796,6 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } - /* - IN() protect from NULL only first argument, if construction like - "expression IN ()" will be allowed, we will need to check number of - argument here, because "NOT(NULL IN ())" is TRUE. - */ - table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2dd097cbaab..5cb330100f8 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -849,7 +849,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::BETWEEN) { - if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) + if (!((Item_func_between *)(cond_func))->negated && + cond_func->arguments()[0]->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (cond_func->arguments()[0]))->field; Item_result cmp_type=field->cmp_type(); @@ -866,7 +867,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::IN_FUNC) { // COND OR Item_func_in *func=(Item_func_in*) cond_func; - if (func->key_item()->type() == Item::FIELD_ITEM) + if (!func->negated && func->key_item()->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (func->key_item()))->field; Item_result cmp_type=field->cmp_type(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index be8ead8e157..6283cad7cc8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2598,7 +2598,12 @@ expr_expr: expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | expr NOT IN_SYM in_subselect @@ -2608,7 +2613,11 @@ expr_expr: | expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2656,7 +2665,11 @@ no_in_expr: no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2704,7 +2717,12 @@ no_and_expr: no_and_expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | no_and_expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | no_and_expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | no_and_expr NOT IN_SYM in_subselect @@ -2714,7 +2732,11 @@ no_and_expr: | no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } From 2f886b93388bc2d1076adaaad03ca0720016cb69 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 18:57:21 +0200 Subject: [PATCH 40/56] Bug #12715 Compilation of yassl/algebra.ccp fails on buildqnx2 - Workaround extra/yassl/mySTL/helpers.hpp: Workaround for QNX extra/yassl/mySTL/list.hpp: Use workaround for placement new extra/yassl/taocrypt/src/misc.cpp: Don't include --- extra/yassl/mySTL/helpers.hpp | 8 +------- extra/yassl/mySTL/list.hpp | 4 ++-- extra/yassl/taocrypt/src/misc.cpp | 1 - 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/extra/yassl/mySTL/helpers.hpp b/extra/yassl/mySTL/helpers.hpp index 8d2061fc4f1..de825c23fec 100644 --- a/extra/yassl/mySTL/helpers.hpp +++ b/extra/yassl/mySTL/helpers.hpp @@ -28,14 +28,11 @@ #define mySTL_HELPERS_HPP #include -#include // placement new - - -#ifdef __IBMCPP__ /* Workaround for the lack of operator new(size_t, void*) in IBM VA C++ 6.0 + Also used as a workaround to avoid including */ struct Dummy {}; @@ -45,9 +42,6 @@ } typedef Dummy* yassl_pointer; -#else - typedef void* yassl_pointer; -#endif namespace mySTL { diff --git a/extra/yassl/mySTL/list.hpp b/extra/yassl/mySTL/list.hpp index 8aaeefaafe8..dd8485f48a7 100644 --- a/extra/yassl/mySTL/list.hpp +++ b/extra/yassl/mySTL/list.hpp @@ -164,7 +164,7 @@ void list::push_front(T t) { void* mem = malloc(sizeof(node)); if (!mem) abort(); - node* add = new (mem) node(t); + node* add = new (reinterpret_cast(mem)) node(t); if (head_) { add->next_ = head_; @@ -210,7 +210,7 @@ void list::push_back(T t) { void* mem = malloc(sizeof(node)); if (!mem) abort(); - node* add = new (mem) node(t); + node* add = new (reinterpret_cast(mem)) node(t); if (tail_) { tail_->next_ = add; diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp index ef051332098..0b33bb38aea 100644 --- a/extra/yassl/taocrypt/src/misc.cpp +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -24,7 +24,6 @@ #include "runtime.hpp" #include "misc.hpp" -#include // for NewHandler void* operator new(size_t sz, TaoCrypt::new_t) From 87544d67ccb11f163db3ec2d729bc73d5d36c6a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 20:19:49 +0300 Subject: [PATCH 41/56] Added possibility to use string values 'true' and 'false' case insensitively with boolean options. Added a warning if given value is invalid and skips the option handling in that case. --- mysys/my_getopt.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 68bf65b2abe..e9e20fe4024 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -342,11 +342,23 @@ int handle_options(int *argc, char ***argv, --enable-'option-name'. *optend was set to '0' if one used --disable-option */ - my_bool tmp= (my_bool) (!optend || *optend == '1'); - *((my_bool*) value)= tmp; (*argc)--; + if (!optend || *optend == '1' || + !my_strcasecmp(&my_charset_latin1, optend, "true")) + *((my_bool*) value)= (my_bool) 1; + else if (*optend == '0' || + !my_strcasecmp(&my_charset_latin1, optend, "false")) + *((my_bool*) value)= (my_bool) 0; + else + { + my_getopt_error_reporter(WARNING_LEVEL, + "%s: ignoring option '--%s' due to \ +invalid value '%s'\n", + my_progname, optp->name, optend); + continue; + } get_one_option(optp->id, optp, - tmp ? (char*) "1" : disabled_my_option); + value ? (char*) "1" : disabled_my_option); continue; } argument= optend; From b89205880f6ce80ccba6e5c43be7af77828b2342 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 21:43:06 +0400 Subject: [PATCH 42/56] Fix for Bug#12953 "Stored procedures: crash if OPTIMIZE TABLE in function" OPTIMIZE TABLE statement is forbidden from usage in stored procedures/functions. NOTE: OPTIMIZE TABLE statement can be useful in stored procedures. The idea is that the user/administrator can create a stored procedure for admin tasks (optimizing, backing up, etc). This procedure can be scheduled to run automatically (by mean of internal cron (WL#1034)). So, once we can make this statement work, it is worth doing it. mysql-test/r/sp-error.result: Results for the test case for Bug#12953 added. mysql-test/t/sp-error.test: Test case for Bug#12953 "Stored procedures: crash if OPTIMIZE TABLE in function" added. sql/sql_yacc.yy: Forbid "OPTIMIZE TABLE" statement from use in stored procedures/functions. --- mysql-test/r/sp-error.result | 7 +++++++ mysql-test/t/sp-error.test | 17 +++++++++++++++-- sql/sql_yacc.yy | 5 +++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 61e931e146c..1a061529fb0 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -758,3 +758,10 @@ execute stmt; ERROR 42000: FUNCTION test.bug11834_1 does not exist deallocate prepare stmt; drop function bug11834_2; +DROP FUNCTION IF EXISTS bug12953| +CREATE FUNCTION bug12953() RETURNS INT +BEGIN +OPTIMIZE TABLE t1; +RETURN 1; +END| +ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index e289748ba2f..abb927ab3b8 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1085,6 +1085,21 @@ drop function bug11834_1; execute stmt; deallocate prepare stmt; drop function bug11834_2; + +# +# Bug#12953 "Stored procedures: crash if OPTIMIZE TABLE in function" +# +delimiter |; +--disable_warnings +DROP FUNCTION IF EXISTS bug12953| +--enable_warnings +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12953() RETURNS INT +BEGIN + OPTIMIZE TABLE t1; + RETURN 1; +END| + # # BUG#NNNN: New bug synopsis # @@ -1092,5 +1107,3 @@ drop function bug11834_2; #drop procedure if exists bugNNNN| #--enable_warnings #create procedure bugNNNN... - - diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c9b41cb495b..cc286e4ff45 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3826,6 +3826,11 @@ optimize: OPTIMIZE opt_no_write_to_binlog table_or_tables { LEX *lex=Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "OPTIMIZE TABLE"); + YYABORT; + } lex->sql_command = SQLCOM_OPTIMIZE; lex->no_write_to_binlog= $2; lex->check_opt.init(); From 981e5226bba0bb1201d0b35f25f7ce67f19d4772 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 21:18:44 +0300 Subject: [PATCH 43/56] postmerge fix --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 09c2eb1a769..8db4b27169a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2705,6 +2705,7 @@ static int init_server_components() query_cache_result_size_limit(query_cache_limit); query_cache_set_min_res_unit(query_cache_min_res_unit); + query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); From a353608359405709b39f33fdc0fafbcca3c2147f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 22:03:12 +0200 Subject: [PATCH 44/56] Backport fixes for mysqltest.test from 5.0 client/mysqltest.c: Backport from 5.0 mysql-test/t/mysqltest.test: Remove the extra ; --- client/mysqltest.c | 77 ++++++++++++++++++++++++------------- mysql-test/t/mysqltest.test | 2 +- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 24e05ab084b..3e2cde92aa9 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -456,6 +456,7 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); +static int handle_no_error(struct st_query *q); static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { @@ -2907,22 +2908,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) } - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (handle_no_error(q)) { - /* Error code we wanted was != 0, i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); - error = 1; - goto end; - } - else if (q->expected_errno[0].type == ERR_SQLSTATE && - strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) - { - /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); - error = 1; + error= 1; goto end; } @@ -3102,10 +3090,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { if (q->abort_on_error) { - die("unable to prepare statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + die("query '%s' failed: %d: %s", query, + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } else { @@ -3186,12 +3172,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) } /* If we got here the statement was both executed and read succeesfully */ - - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (handle_no_error(q)) { - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); error= 1; goto end; } @@ -3518,8 +3500,14 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, dynstr_append_mem(ds,"\n",1); if (i) { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); + if (q->expected_errno[0].type == ERR_ERRNO) + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_stmt_errno(stmt), + q->expected_errno[0].code.errnum); + else + verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, mysql_stmt_sqlstate(stmt), + q->expected_errno[0].code.sqlstate); return 1; /* Error */ } verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), @@ -3534,6 +3522,43 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, return 0; } + +/* + Handle absence of errors after execution + + SYNOPSIS + handle_no_error() + q - context of query + + RETURN VALUE + 0 - OK + 1 - Some error was expected from this query. +*/ + +static int handle_no_error(struct st_query *q) +{ + DBUG_ENTER("handle_no_error"); + + if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); + DBUG_RETURN(1); + } + else if (q->expected_errno[0].type == ERR_SQLSTATE && + strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + { + /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ + verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); + DBUG_RETURN(1); + } + + DBUG_RETURN(0); +} + /****************************************************************************\ * Functions to match SQL statements that can be prepared \****************************************************************************/ diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 39c1e867f28..4d3bcc037d1 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -592,7 +592,7 @@ while ($num) --source var/tmp/sourced1.sql dec $num; } ---enable_abort_on_error; +--enable_abort_on_error --enable_query_log # ---------------------------------------------------------------------------- From d877cdf3e7fa6c176a2dea418deaa0bb2d9500ff Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 22:20:11 -0700 Subject: [PATCH 45/56] func_gconcat.result, func_gconcat.test: Added test cases for bug #12863. item_sum.cc, item_sum.h: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. sql/item_sum.h: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. sql/item_sum.cc: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. mysql-test/t/func_gconcat.test: Added test cases for bug #12863. mysql-test/r/func_gconcat.result: Added test cases for bug #12863. --- mysql-test/r/func_gconcat.result | 20 ++++++++++++++++++++ mysql-test/t/func_gconcat.test | 16 ++++++++++++++++ sql/item_sum.cc | 8 +++++--- sql/item_sum.h | 1 + 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 12bc5ca2582..9c0c05ae296 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -560,3 +560,23 @@ group_concat('x') NULL 1 drop table t1; +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES +(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +,,x,y,z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; +GROUP_CONCAT(a ORDER BY a) +,,,x,y,z +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +GROUP_CONCAT(a) +,y +,x +z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; +GROUP_CONCAT(a ORDER BY a) +,y +,x +,z +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 9e003d19ab9..aa8ce0f4bdc 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -356,4 +356,20 @@ select * from (select group_concat(a) from t1) t2; select group_concat('x') UNION ALL select 1; drop table t1; +# +# Bug #12863 : missing separators after first empty cancatanated elements +# + +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES + (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); + +SELECT GROUP_CONCAT(a) FROM t1; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; + +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 000dcdb4997..7f13fdf82b2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1664,7 +1664,9 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), char buff[MAX_FIELD_WIDTH]; String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2; - if (item->result.length()) + if (item->no_appended) + item->no_appended= FALSE; + else item->result.append(*item->separator); tmp.length(0); @@ -1856,6 +1858,7 @@ void Item_func_group_concat::clear() result.copy(); null_value= TRUE; warning_for_row= FALSE; + no_appended= TRUE; if (tree_mode) reset_tree(tree); } @@ -1898,8 +1901,7 @@ bool Item_func_group_concat::add() void Item_func_group_concat::reset_field() { - if (tree_mode) - reset_tree(tree); + DBUG_ASSERT(0); } diff --git a/sql/item_sum.h b/sql/item_sum.h index a3b422565d1..d53d8d861ae 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -709,6 +709,7 @@ class Item_func_group_concat : public Item_sum uint arg_count_field; uint field_list_offset; uint count_cut_values; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) From b025657bcab0ed0529cc0fa6c43ea87025e894a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 23:32:00 -0700 Subject: [PATCH 46/56] Fixed a typo in the configure --help menu. config/ac-macros/ha_federated.m4: Fixed typo --- config/ac-macros/ha_federated.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/ac-macros/ha_federated.m4 b/config/ac-macros/ha_federated.m4 index 4383a9d8d55..5c991f31666 100644 --- a/config/ac-macros/ha_federated.m4 +++ b/config/ac-macros/ha_federated.m4 @@ -6,7 +6,7 @@ AC_DEFUN([MYSQL_CHECK_FEDERATED], [ AC_ARG_WITH([federated-storage-engine], [ --with-federated-storage-engine - Enable the MySQL Storage Engine], + Enable the MySQL Federated Storage Engine], [federateddb="$withval"], [federateddb=no]) AC_MSG_CHECKING([for MySQL federated storage engine]) From 3003e5a0eb66ce221968cf8ac6199800bba1eedd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 11:50:41 +0400 Subject: [PATCH 47/56] Fix for BUG#12941: in create_tmp_field(), if the passed item is an Item_ref, put newly created item into item->result_field, not *(item->ref)->result_field. mysql-test/r/view.result: Tescase for BUG#12941 mysql-test/t/view.test: Tescase for BUG#12941 --- mysql-test/r/view.result | 26 ++++++++++++++++++++++++++ mysql-test/t/view.test | 33 +++++++++++++++++++++++++++++++++ sql/sql_select.cc | 30 ++++++++++++++++++++---------- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a544fb4b020..e141393176c 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2151,3 +2151,29 @@ select * from v1; strcmp(f1,'a') drop view v1; drop table t1; +create table t1 ( +r_object_id char(16) NOT NULL, +group_name varchar(32) NOT NULL +) engine = InnoDB; +create table t2 ( +r_object_id char(16) NOT NULL, +i_position int(11) NOT NULL, +users_names varchar(32) default NULL +) Engine = InnoDB; +create view v1 as select r_object_id, group_name from t1; +create view v2 as select r_object_id, i_position, users_names from t2; +create unique index r_object_id on t1(r_object_id); +create index group_name on t1(group_name); +create unique index r_object_id_i_position on t2(r_object_id,i_position); +create index users_names on t2(users_names); +insert into t1 values('120001a080000542','tstgroup1'); +insert into t2 values('120001a080000542',-1, 'guser01'); +insert into t2 values('120001a080000542',-2, 'guser02'); +select v1.r_object_id, v2.users_names from v1, v2 +where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id +order by users_names; +r_object_id users_names +120001a080000542 guser01 +120001a080000542 guser02 +drop view v1, v2; +drop table t1, t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 97625632618..c5984f726f4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2018,3 +2018,36 @@ create view v1 as select strcmp(f1,'a') from t1; select * from v1; drop view v1; drop table t1; + +# +# BUG#12941 +# +create table t1 ( + r_object_id char(16) NOT NULL, + group_name varchar(32) NOT NULL +) engine = InnoDB; + +create table t2 ( + r_object_id char(16) NOT NULL, + i_position int(11) NOT NULL, + users_names varchar(32) default NULL +) Engine = InnoDB; + +create view v1 as select r_object_id, group_name from t1; +create view v2 as select r_object_id, i_position, users_names from t2; + +create unique index r_object_id on t1(r_object_id); +create index group_name on t1(group_name); +create unique index r_object_id_i_position on t2(r_object_id,i_position); +create index users_names on t2(users_names); + +insert into t1 values('120001a080000542','tstgroup1'); +insert into t2 values('120001a080000542',-1, 'guser01'); +insert into t2 values('120001a080000542',-2, 'guser02'); + +select v1.r_object_id, v2.users_names from v1, v2 +where (v1.group_name='tstgroup1') and v2.r_object_id=v1.r_object_id +order by users_names; + +drop view v1, v2; +drop table t1, t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0de06ea395a..e86af23d5fa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8054,12 +8054,17 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool table_cant_handle_bit_fields, uint convert_blob_length) { + Item::Type orig_type; + Item *orig_item; + if (type != Item::FIELD_ITEM && item->real_item()->type() == Item::FIELD_ITEM && (item->type() != Item::REF_ITEM || !((Item_ref *) item)->depended_from)) { + orig_item= item; item= item->real_item(); + orig_type= type; type= Item::FIELD_ITEM; } switch (type) { @@ -8075,29 +8080,34 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::DEFAULT_VALUE_ITEM: { Item_field *field= (Item_field*) item; + bool orig_modify= modify_item; + Field *result; + if (orig_type == Item::REF_ITEM) + modify_item= 0; /* If item have to be able to store NULLs but underlaid field can't do it, create_tmp_field_from_field() can't be used for tmp field creation. */ if (field->maybe_null && !field->field->maybe_null()) { - Field *res= create_tmp_field_from_item(thd, item, table, NULL, + result= create_tmp_field_from_item(thd, item, table, NULL, modify_item, convert_blob_length); *from_field= field->field; - if (res && modify_item) - ((Item_field*)item)->result_field= res; - return res; - } - - if (table_cant_handle_bit_fields && - field->field->type() == FIELD_TYPE_BIT) - return create_tmp_field_from_item(thd, item, table, copy_func, + if (result && modify_item) + ((Item_field*)item)->result_field= result; + } + else if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT) + result= create_tmp_field_from_item(thd, item, table, copy_func, modify_item, convert_blob_length); - return create_tmp_field_from_field(thd, (*from_field= field->field), + else + result= create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, modify_item ? (Item_field*) item : NULL, convert_blob_length); + if (orig_type == Item::REF_ITEM && orig_modify) + ((Item_ref*)orig_item)->set_result_field(result); + return result; } /* Fall through */ case Item::FUNC_ITEM: From a777907a51510cec8ab4a502d0924e072b47665d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 15:38:09 +0500 Subject: [PATCH 48/56] Fix for bug#11775 Variable character_set_system does not exist (sometimes). Variable character_set_system is selectable now More accurate error message results during update of character_set_system and some other read only variables mysql-test/r/variables.result: Fix for bug#11775 Variable character_set_system does not exist (sometimes). test case mysql-test/t/variables.test: Fix for bug#11775 Variable character_set_system does not exist (sometimes). test case --- mysql-test/r/variables.result | 7 +++++++ mysql-test/t/variables.test | 9 +++++++++ sql/set_var.cc | 29 +++-------------------------- sql/set_var.h | 3 ++- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index a5b76c03b29..265f353ae3c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -545,3 +545,10 @@ select @@max_heap_table_size > 0; select @@have_innodb; @@have_innodb # +select @@character_set_system; +@@character_set_system +utf8 +set global character_set_system = latin1; +ERROR HY000: Variable 'character_set_system' is a read only variable +set @@global.version_compile_os='234'; +ERROR HY000: Variable 'version_compile_os' is a read only variable diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 372e865467e..afd0fe23805 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -435,3 +435,12 @@ select @@max_heap_table_size > 0; --replace_column 1 # select @@have_innodb; + +# +# Bug #11775 Variable character_set_system does not exist (sometimes) +# +select @@character_set_system; +--error 1238 +set global character_set_system = latin1; +--error 1238 +set @@global.version_compile_os='234'; diff --git a/sql/set_var.cc b/sql/set_var.cc index ea4c08cea27..774062dedf2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -142,11 +142,8 @@ sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", &SV::bulk_insert_buff_size); sys_var_character_set_server sys_character_set_server("character_set_server"); -sys_var_str sys_charset_system("character_set_system", - sys_check_charset, - sys_update_charset, - sys_set_default_charset, - (char *)my_charset_utf8_general_ci.name); +sys_var_const_str sys_charset_system("character_set_system", + (char *)my_charset_utf8_general_ci.name); sys_var_character_set_database sys_character_set_database("character_set_database"); sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); @@ -569,6 +566,7 @@ sys_var *sys_variables[]= &sys_character_set_client, &sys_character_set_connection, &sys_character_set_results, + &sys_charset_system, &sys_collation_connection, &sys_collation_database, &sys_collation_server, @@ -1117,27 +1115,6 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type) sizeof(ft_boolean_syntax)-1); } -/* - The following 3 functions need to be changed in 4.1 when we allow - one to change character sets -*/ - -static int sys_check_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static bool sys_update_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static void sys_set_default_charset(THD *thd, enum_var_type type) -{ -} - /* If one sets the LOW_PRIORIY UPDATES flag, we also must change the diff --git a/sql/set_var.h b/sql/set_var.h index c8b075ddd35..40ff4c8583f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -190,6 +190,7 @@ public: return 1; } bool check_default(enum_var_type type) { return 1; } + bool is_readonly() const { return 1; } }; @@ -900,7 +901,7 @@ int sql_set_variables(THD *thd, List *var_list); bool not_all_support_one_shot(List *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); ulong fix_sql_mode(ulong sql_mode); -extern sys_var_str sys_charset_system; +extern sys_var_const_str sys_charset_system; extern sys_var_str sys_init_connect; extern sys_var_str sys_init_slave; extern sys_var_thd_time_zone sys_time_zone; From 48c3c329b3916ef6a710d5221b8bd4671817fd3c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 16:11:53 +0500 Subject: [PATCH 49/56] Fix for bug#12905 show fields from view behaving erratically with current database use saved view db name in case of view --- mysql-test/r/information_schema.result | 11 +++++++++++ mysql-test/t/information_schema.test | 14 +++++++++++++- sql/sql_show.cc | 21 +++++++++++++++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 20b2f12f0a8..9a7a0b48f47 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -979,3 +979,14 @@ WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +DROP TABLE t1,t2; +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +select database(); +database() +NULL +show fields from test.v1; +Field Type Null Key Default Extra +c int(11) YES NULL +drop view v1; +drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 6be193e0e0c..aa1b632f919 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -665,4 +665,16 @@ SHOW TABLE STATUS FROM test WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); -DROP TABLE t1,t2 +DROP TABLE t1,t2; + +# +# Bug #12905 show fields from view behaving erratically with current database +# +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +connect (con5,localhost,root,,*NO-ONE*); +select database(); +show fields from test.v1; +connection default; +drop view v1; +drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bc3c8fbdc5d..51330a6109b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1988,10 +1988,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() + + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case(this part of code is used only for + 'show columns' & 'show statistics' commands). */ error= test(schema_table->process_table(thd, show_table_list, - table, res, show_table_list->db, - show_table_list->alias)); + table, res, + (show_table_list->view ? + show_table_list->view_db.str : + show_table_list->db), + show_table_list->alias)); close_thread_tables(thd); show_table_list->table= 0; goto err; @@ -2092,6 +2102,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->derived_tables= 0; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + /* + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case. + */ res= schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias); From 0a61c3abda74efa51bf697dfcaa16d80ff874fcd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 17:42:47 +0400 Subject: [PATCH 50/56] join_outer.result, opt_range.cc, item_cmpfunc.cc: Post merge changes sql_yacc.yy: Post merge changes sql_select.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions (post merge changes). The function add_key_fields() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/item_cmpfunc.cc: Post merge changes sql/opt_range.cc: Post merge changes sql/sql_select.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions (post merge changes). The function add_key_fields() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/sql_yacc.yy: Post merge changes. mysql-test/r/join_outer.result: Post merge changes --- mysql-test/r/join_outer.result | 10 +++++----- sql/item_cmpfunc.cc | 16 ++++++++-------- sql/opt_range.cc | 16 ++++------------ sql/sql_select.cc | 13 ------------- sql/sql_yacc.yy | 16 ++++++++-------- 5 files changed, 25 insertions(+), 46 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 6295356b800..92b352aa608 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1123,14 +1123,14 @@ a b a b 7 8 7 5 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 DROP TABLE t1,t2; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 46284c422c2..dfdc7319d4d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1018,9 +1018,9 @@ longlong Item_func_interval::val_int() */ bool -Item_func_between::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) +Item_func_between::fix_fields(THD *thd, Item **ref) { - if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + if (Item_func_opt_neg::fix_fields(thd, ref)) return 1; /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ @@ -1132,8 +1132,8 @@ longlong Item_func_between::val_int() a_dec= args[1]->val_decimal(&a_buf); b_dec= args[2]->val_decimal(&b_buf); if (!args[1]->null_value && !args[2]->null_value) - return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0); - + return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && + my_decimal_cmp(dec, b_dec) <= 0) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1320,12 +1320,12 @@ Item_func_ifnull::str_op(String *str) */ bool -Item_func_if::fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) +Item_func_if::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); args[0]->top_level_item(); - if (Item_func::fix_fields(thd, tlist, ref)) + if (Item_func::fix_fields(thd, ref)) return 1; not_null_tables_cache= (args[1]->not_null_tables() @@ -2305,11 +2305,11 @@ bool Item_func_in::nulls_in_row() */ bool -Item_func_in::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_in::fix_fields(THD *thd, Item **ref) { Item **arg, **arg_end; - if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + if (Item_func_opt_neg::fix_fields(thd, ref)) return 1; /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ecf4b5de1cb..cb250251155 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3524,20 +3524,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) } Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - /* Optimize NOT BETWEEN and NOT IN */ - Item *arg= cond_func->arguments()[0]; - if (arg->type() != Item::FUNC_ITEM) - DBUG_RETURN(0); - cond_func= (Item_func*) arg; - if (cond_func->functype() != Item_func::BETWEEN && - cond_func->functype() != Item_func::IN_FUNC) - DBUG_RETURN(0); - inv= TRUE; - } + if (cond_func->functype() == Item_func::BETWEEN || + cond_func->functype() == Item_func::IN_FUNC) + inv= ((Item_func_opt_neg *) cond_func)->negated; else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); + param->cond= cond; switch (cond_func->functype()) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0de06ea395a..83a4cd4bbf3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2862,19 +2862,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, if (cond->type() != Item::FUNC_ITEM) return; Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - Item *item= cond_func->arguments()[0]; - /* - At this moment all NOT before simple comparison predicates - are eliminated. NOT IN and NOT BETWEEN are treated similar - IN and BETWEEN respectively. - */ - if (item->type() == Item::FUNC_ITEM && - ((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY) - add_key_fields(key_fields,and_level,item,usable_tables); - return; - } switch (cond_func->select_optimize()) { case Item_func::OPTIMIZE_NONE: break; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8723c558df3..ad1fd68ddcd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4274,7 +4274,9 @@ predicate: else { $5->push_front($1); - $$= negate_expression(YYTHD, new Item_func_in(*$5)); + Item_func_in *item = new Item_func_in(*$5); + item->negate(); + $$= item; } } | bit_expr IN_SYM in_subselect @@ -4284,7 +4286,11 @@ predicate: | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate { $$= new Item_func_between($1,$3,$5); } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate - { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } @@ -4350,12 +4356,6 @@ all_or_any: ALL { $$ = 1; } | ANY_SYM { $$ = 0; } ; - - - - - - interval_expr: INTERVAL_SYM expr { $$=$2; } ; From 1ac26b4a6cfd5cf72b39e4fda31d2bb114463ad8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 10:30:06 -0700 Subject: [PATCH 51/56] Small tweak for random read performance (we shouldn't always tell the OS that we will be doing a linear scan). sql/examples/ha_tina.cc: Small tweak for random read performance. --- sql/examples/ha_tina.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index bbcdfb0dafb..8a9aa91c680 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -609,7 +609,8 @@ int ha_tina::rnd_init(bool scan) records= 0; chain_ptr= chain; #ifdef HAVE_MADVISE - (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); + if (scan) + (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); #endif DBUG_RETURN(0); From 792221e36579dbbec0f4335b49198a25d2a2ffd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 22:38:36 +0400 Subject: [PATCH 52/56] Fix bug #12922 if(sum(),...) with group from view returns wrong results Fields of view represented by Item_direct_view_ref. When complex expression such as if(sum()>...,...) is splited in simpler parts by refs was ignored. Beside this direct ref doesn't use it's result_field and thus can't store it's result in tmp table which is needed for sum() ... group. All this results in reported bug. Item::split_sum_func2() now converts Item_direct_view_ref to Item_ref to make fields from view being storable in tmp table. sql/item.h: Fix bug #12922 if(sum(),...) with group from view returns wrong results Added function ref_type() to distinguish Item_ref subclasses sql/item.cc: Fix bug #12922 if(sum(),...) with group from view returns wrong results Item::split_sum_func2() now converts Item_direct_view_ref to Item_ref to make fields from view being storable in tmp table. mysql-test/t/view.test: Test case for bug#12922 if(sum(),...) with group from view returns wrong results mysql-test/r/view.result: Test case for bug#12922 if(sum(),...) with group from view returns wrong results --- mysql-test/r/view.result | 9 +++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item.cc | 16 +++++++++------- sql/item.h | 4 ++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a544fb4b020..88c635509f5 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2151,3 +2151,12 @@ select * from v1; strcmp(f1,'a') drop view v1; drop table t1; +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +if(sum(f1)>1,f2,f3) +20 +0 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 97625632618..0e6fddf58ae 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2018,3 +2018,13 @@ create view v1 as select strcmp(f1,'a') from t1; select * from v1; drop view v1; drop table t1; + +# +# Bug #12922 if(sum(),...) with group from view returns wrong results +# +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +drop view v1; +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index b4992faa65e..1edf0a470d3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1022,9 +1022,9 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, /* Will split complicated items and ignore simple ones */ split_sum_func(thd, ref_pointer_array, fields); } - else if ((type() == SUM_FUNC_ITEM || - (used_tables() & ~PARAM_TABLE_BIT)) && - type() != REF_ITEM) + else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) && + (type() != REF_ITEM || + ((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF)) { /* Replace item with a reference so that we can easily calculate @@ -1033,15 +1033,17 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, The test above is to ensure we don't do a reference for things that are constants (PARAM_TABLE_BIT is in effect a constant) or already referenced (for example an item in HAVING) + Exception is Item_direct_view_ref which we need to convert to + Item_ref to allow fields from view being stored in tmp table. */ uint el= fields.elements; - Item *new_item; - ref_pointer_array[el]= this; + Item *new_item, *real_item= real_item(); + + ref_pointer_array[el]= real_item; if (!(new_item= new Item_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set - fields.push_front(this); - ref_pointer_array[el]= this; + fields.push_front(real_item); thd->change_item_tree(ref, new_item); } } diff --git a/sql/item.h b/sql/item.h index b934e1f9f3f..f128c72413d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1537,6 +1537,7 @@ class Item_ref :public Item_ident protected: void set_properties(); public: + enum Ref_Type { REF, DIRECT_REF, VIEW_REF }; Field *result_field; /* Save result here */ Item **ref; Item_ref(Name_resolution_context *context_arg, @@ -1617,6 +1618,7 @@ public: void cleanup(); Item_field *filed_for_view_update() { return (*ref)->filed_for_view_update(); } + virtual Ref_Type ref_type() { return REF; } }; @@ -1641,6 +1643,7 @@ public: bool val_bool(); bool is_null(); bool get_date(TIME *ltime,uint fuzzydate); + virtual Ref_Type ref_type() { return DIRECT_REF; } }; /* @@ -1660,6 +1663,7 @@ public: bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; + virtual Ref_Type ref_type() { return VIEW_REF; } }; From eb061b654fb2a2aaef09e2bf8e7b3a8f300447be Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 23:03:56 +0400 Subject: [PATCH 53/56] Fix for Bug#12995: Inside function "Table 't4' was not locked with LOCK TABLES" Any form of HANDLER statement is forbidden from usage in stored procedures/functions. mysql-test/r/sp-error.result: Results for the test case for Bug#12995 added. mysql-test/t/sp-error.test: Test case for Bug#12995 added. sql/sql_yacc.yy: Forbid any form of "HANDLER" statement from use in stored procedures/functions. --- mysql-test/r/sp-error.result | 21 +++++++++++++++++++++ mysql-test/t/sp-error.test | 30 ++++++++++++++++++++++++++++++ sql/sql_yacc.yy | 15 +++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 1a061529fb0..09d829e9d12 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -765,3 +765,24 @@ OPTIMIZE TABLE t1; RETURN 1; END| ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures +DROP FUNCTION IF EXISTS bug12995| +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 OPEN; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 READ FIRST; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 CLOSE; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +SELECT bug12995()| +ERROR 42000: FUNCTION test.bug12995 does not exist diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index abb927ab3b8..9f91c32c104 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1099,6 +1099,36 @@ BEGIN OPTIMIZE TABLE t1; RETURN 1; END| +delimiter ;| + +# +# Bug##12995 "Inside function "Table 't4' was not locked with LOCK TABLES" +# +delimiter |; +--disable_warnings +DROP FUNCTION IF EXISTS bug12995| +--enable_warnings +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 OPEN; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 READ FIRST; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 CLOSE; + RETURN 1; +END| +--error 1305 +SELECT bug12995()| +delimiter ;| # # BUG#NNNN: New bug synopsis diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cc286e4ff45..71adab4853c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8157,6 +8157,11 @@ handler: HANDLER_SYM table_ident OPEN_SYM opt_table_alias { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_OPEN; if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) YYABORT; @@ -8164,6 +8169,11 @@ handler: | HANDLER_SYM table_ident_nodb CLOSE_SYM { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_CLOSE; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; @@ -8171,6 +8181,11 @@ handler: | HANDLER_SYM table_ident_nodb READ_SYM { LEX *lex=Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ lex->current_select->select_limit= new Item_int((int32) 1); From d319c8ffbd95d885e3f64a3ab29c397b57be272d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 23:32:39 +0400 Subject: [PATCH 54/56] item.cc: Fix for fix bug#12922. sql/item.cc: Fix for fix bug#12922. --- sql/item.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 1edf0a470d3..56b03055968 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1037,13 +1037,13 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, Item_ref to allow fields from view being stored in tmp table. */ uint el= fields.elements; - Item *new_item, *real_item= real_item(); + Item *new_item, *real_itm= real_item(); - ref_pointer_array[el]= real_item; + ref_pointer_array[el]= real_itm; if (!(new_item= new Item_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set - fields.push_front(real_item); + fields.push_front(real_itm); thd->change_item_tree(ref, new_item); } } From f56d8901ece30131dd78bbc6c9f956a6035d954b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 18:07:51 -0700 Subject: [PATCH 55/56] Manual merge --- sql/item_sum.h | 515 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 364 insertions(+), 151 deletions(-) diff --git a/sql/item_sum.h b/sql/item_sum.h index d53d8d861ae..a1a232c4308 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -27,9 +27,9 @@ class Item_sum :public Item_result_field { public: enum Sumfunctype - { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, - MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, - UDF_SUM_FUNC, GROUP_CONCAT_FUNC + { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, + AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, + VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; Item **args, *tmp_args[2]; @@ -66,6 +66,9 @@ public: a temporary table. Similar to reset(), but must also store value in result_field. Like reset() it is supposed to reset start value to default. + This set of methods (reult_field(), reset_field, update_field()) of + Item_sum is used only if quick_group is not null. Otherwise + copy_or_same() is used to obtain a copy of this item. */ virtual void reset_field()=0; /* @@ -76,9 +79,24 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - virtual const char *func_name() const { return "?"; } + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print(), where it is applicable. + To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + + NOTE: for Items inherited from Item_sum, func_name() return part of + function name till first argument (including '(') to make difference in + names for functions with 'distinct' clause and without 'distinct' and + also to make printing of items inherited from Item_sum uniform. + */ + virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) - { return new Item_field(field);} + { return new Item_field(field); } table_map used_tables() const { return ~(table_map) 0; } /* Not used */ bool const_item() const { return 0; } bool is_null() { return null_value; } @@ -90,7 +108,8 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); - + virtual Field *create_tmp_field(bool group, TABLE *table, + uint convert_blob_length); bool walk (Item_processor processor, byte *argument); }; @@ -103,10 +122,14 @@ public: Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) val(); } /* Real as default */ + { + DBUG_ASSERT(fixed == 1); + return (longlong) val_real(); /* Real as default */ + } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void reset_field(); }; @@ -117,8 +140,9 @@ public: Item_sum_int(Item *item_par) :Item_sum_num(item_par) {} Item_sum_int(List &list) :Item_sum_num(list) {} Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} - double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } + double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; maybe_null=null_value=0; } @@ -127,25 +151,115 @@ public: class Item_sum_sum :public Item_sum_num { +protected: + Item_result hybrid_type; double sum; - void fix_length_and_dec() { maybe_null=null_value=1; } + my_decimal dec_buffs[2]; + uint curr_dec_buff; + void fix_length_and_dec(); - public: - Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {} - Item_sum_sum(THD *thd, Item_sum_sum *item) - :Item_sum_num(thd, item), sum(item->sum) {} +public: + Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {} + Item_sum_sum(THD *thd, Item_sum_sum *item); enum Sumfunctype sum_func () const {return SUM_FUNC;} void clear(); bool add(); - double val(); + double val_real(); + longlong val_int(); + String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return hybrid_type; } void reset_field(); void update_field(); void no_rows_in_result() {} - const char *func_name() const { return "sum"; } + const char *func_name() const { return "sum("; } Item *copy_or_same(THD* thd); }; + +/* Common class for SUM(DISTINCT), AVG(DISTINCT) */ + +class Unique; + +class Item_sum_distinct :public Item_sum_num +{ +protected: + /* storage for the summation result */ + ulonglong count; + Hybrid_type val; + /* storage for unique elements */ + Unique *tree; + TABLE *table; + enum enum_field_types table_field_type; + uint tree_key_length; +protected: + Item_sum_distinct(THD *thd, Item_sum_distinct *item); +public: + Item_sum_distinct(Item *item_par); + ~Item_sum_distinct(); + + bool setup(THD *thd); + void clear(); + void cleanup(); + bool add(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + longlong val_int(); + String *val_str(String *str); + + /* XXX: does it need make_unique? */ + + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } + void reset_field() {} // not used + void update_field() {} // not used + virtual void no_rows_in_result() {} + void fix_length_and_dec(); + enum Item_result result_type () const { return val.traits->type(); } + virtual void calculate_val_and_count(); + virtual bool unique_walk_function(void *elem); +}; + + +/* + Item_sum_sum_distinct - implementation of SUM(DISTINCT expr). + See also: MySQL manual, chapter 'Adding New Functions To MySQL' + and comments in item_sum.cc. +*/ + +class Item_sum_sum_distinct :public Item_sum_distinct +{ +private: + Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item) + :Item_sum_distinct(thd, item) {} +public: + Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {} + + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } + const char *func_name() const { return "sum(distinct "; } + Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); } +}; + + +/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */ + +class Item_sum_avg_distinct: public Item_sum_distinct +{ +private: + Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original) + :Item_sum_distinct(thd, original) {} +public: + uint prec_increment; + Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {} + + void fix_length_and_dec(); + virtual void calculate_val_and_count(); + enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; } + const char *func_name() const { return "avg(distinct "; } + Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); } +}; + + class Item_sum_count :public Item_sum_int { longlong count; @@ -170,7 +284,7 @@ class Item_sum_count :public Item_sum_int void reset_field(); void cleanup(); void update_field(); - const char *func_name() const { return "count"; } + const char *func_name() const { return "count("; } Item *copy_or_same(THD* thd); }; @@ -180,80 +294,55 @@ class TMP_TABLE_PARAM; class Item_sum_count_distinct :public Item_sum_int { TABLE *table; - table_map used_table_cache; uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; - TREE tree_base; - TREE *tree; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_sum_count_distinct *original; - - uint key_length; - CHARSET_INFO *key_charset; - - /* - Calculated based on max_heap_table_size. If reached, - walk the tree and dump it into MyISAM table - */ - uint max_elements_in_tree; - - /* - The first few bytes of record ( at least one) - are just markers for deleted and NULLs. We want to skip them since - they will just bloat the tree without providing any valuable info - */ - int rec_offset; - /* If there are no blobs, we can use a tree, which is faster than heap table. In that case, we still use the table to help get things set up, but we insert nothing in it */ - bool use_tree; + Unique *tree; + /* + Following is 0 normal object and pointer to original one for copy + (to correctly free resources) + */ + Item_sum_count_distinct *original; + uint tree_key_length; + + bool always_null; // Set to 1 if the result is always NULL - int tree_to_myisam(); friend int composite_key_cmp(void* arg, byte* key1, byte* key2); friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2); - friend int simple_raw_key_cmp(void* arg, byte* key1, byte* key2); - friend int dump_leaf(byte* key, uint32 count __attribute__((unused)), - Item_sum_count_distinct* item); - public: +public: Item_sum_count_distinct(List &list) - :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0), - tmp_table_param(0), tree(&tree_base), original(0), use_tree(0), - always_null(0) + :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), + tree(0), original(0), always_null(FALSE) { quick_group= 0; } Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) :Item_sum_int(thd, item), table(item->table), - used_table_cache(item->used_table_cache), field_lengths(item->field_lengths), tmp_table_param(item->tmp_table_param), - tree(item->tree), original(item), key_length(item->key_length), - max_elements_in_tree(item->max_elements_in_tree), - rec_offset(item->rec_offset), use_tree(item->use_tree), + tree(item->tree), original(item), tree_key_length(item->tree_key_length), always_null(item->always_null) {} + ~Item_sum_count_distinct(); + void cleanup(); - table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } void clear(); bool add(); longlong val_int(); void reset_field() { return ;} // Never called void update_field() { return ; } // Never called - const char *func_name() const { return "count_distinct"; } + const char *func_name() const { return "count(distinct "; } bool setup(THD *thd); void make_unique(); Item *copy_or_same(THD* thd); void no_rows_in_result() {} - void print(String *str); }; @@ -265,43 +354,55 @@ class Item_avg_field :public Item_result_field { public: Field *field; - Item_avg_field(Item_sum_avg *item); + Item_result hybrid_type; + uint f_precision, f_scale, dec_bin_size; + uint prec_increment; + Item_avg_field(Item_result res_type, Item_sum_avg *item); enum Type type() const { return FIELD_AVG_ITEM; } - double val(); - longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; -class Item_sum_avg :public Item_sum_num +class Item_sum_avg :public Item_sum_sum { - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } - - double sum; +public: ulonglong count; + uint prec_increment; + uint f_precision, f_scale, dec_bin_size; - public: - Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {} + Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} Item_sum_avg(THD *thd, Item_sum_avg *item) - :Item_sum_num(thd, item), sum(item->sum), count(item->count) {} + :Item_sum_sum(thd, item), count(item->count), + prec_increment(item->prec_increment) {} + + void fix_length_and_dec(); enum Sumfunctype sum_func () const {return AVG_FUNC;} void clear(); bool add(); - double val(); + double val_real(); + // In SPs we might force the "wrong" type with select into a declare variable + longlong val_int() { return (longlong)val_real(); } + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); void reset_field(); void update_field(); Item *result_item(Field *field) - { return new Item_avg_field(this); } + { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} - const char *func_name() const { return "avg"; } + const char *func_name() const { return "avg("; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; class Item_sum_variance; @@ -310,14 +411,27 @@ class Item_variance_field :public Item_result_field { public: Field *field; + Item_result hybrid_type; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; + uint sample; + uint prec_increment; Item_variance_field(Item_sum_variance *item); enum Type type() const {return FIELD_VARIANCE_ITEM; } - double val(); - longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); } + double val_real(); + longlong val_int() + { /* can't be fix_fields()ed */ return (longlong) val_real(); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; @@ -335,30 +449,39 @@ public: class Item_sum_variance : public Item_sum_num { - double sum, sum_sqr; - ulonglong count; - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } + void fix_length_and_dec(); - public: - Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} - Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr), - count(item->count) {} +public: + Item_result hybrid_type; + double sum, sum_sqr; + my_decimal dec_sum[2], dec_sqr[2]; + int cur_dec; + ulonglong count; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; + uint sample; + uint prec_increment; + + Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par), + hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg) + {} + Item_sum_variance(THD *thd, Item_sum_variance *item); enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void clear(); bool add(); - double val(); + double val_real(); + my_decimal *val_decimal(my_decimal *); void reset_field(); void update_field(); Item *result_item(Field *field) { return new Item_variance_field(this); } void no_rows_in_result() {} - const char *func_name() const { return "variance"; } + const char *func_name() const + { return sample ? "var_samp(" : "variance("; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); + enum Item_result result_type () const { return hybrid_type; } }; class Item_sum_std; @@ -368,7 +491,10 @@ class Item_std_field :public Item_variance_field public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } - double val(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; /* @@ -378,26 +504,30 @@ public: class Item_sum_std :public Item_sum_variance { public: - Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {} + Item_sum_std(Item *item_par, uint sample_arg) + :Item_sum_variance(item_par, sample_arg) {} Item_sum_std(THD *thd, Item_sum_std *item) :Item_sum_variance(thd, item) {} enum Sumfunctype sum_func () const { return STD_FUNC; } - double val(); + double val_real(); Item *result_item(Field *field) { return new Item_std_field(this); } - const char *func_name() const { return "std"; } + const char *func_name() const { return "std("; } Item *copy_or_same(THD* thd); + enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; // This class is a string or number function depending on num_func class Item_sum_hybrid :public Item_sum { - protected: +protected: String value,tmp_value; double sum; longlong sum_int; + my_decimal sum_dec; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -408,22 +538,18 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), - cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item): - Item_sum(thd, item), value(item->value), - sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), - used_table_cache(item->used_table_cache), + cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(item->collation); } - bool fix_fields(THD *, TABLE_LIST *, Item **); + { collation.set(&my_charset_bin); } + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); + bool fix_fields(THD *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } void clear(); - double val(); + double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); void make_const() { used_table_cache=0; } @@ -434,9 +560,12 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(); void min_max_update_real_field(); void min_max_update_int_field(); + void min_max_update_decimal_field(); void cleanup(); bool any_value() { return was_values; } void no_rows_in_result(); + Field *create_tmp_field(bool group, TABLE *table, + uint convert_blob_length); }; @@ -448,7 +577,7 @@ public: enum Sumfunctype sum_func () const {return MIN_FUNC;} bool add(); - const char *func_name() const { return "min"; } + const char *func_name() const { return "min("; } Item *copy_or_same(THD* thd); }; @@ -461,7 +590,7 @@ public: enum Sumfunctype sum_func () const {return MAX_FUNC;} bool add(); - const char *func_name() const { return "max"; } + const char *func_name() const { return "max("; } Item *copy_or_same(THD* thd); }; @@ -482,7 +611,7 @@ public: void reset_field(); void update_field(); void fix_length_and_dec() - { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } + { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } }; @@ -492,7 +621,7 @@ public: Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_or"; } + const char *func_name() const { return "bit_or("; } Item *copy_or_same(THD* thd); }; @@ -503,7 +632,7 @@ class Item_sum_and :public Item_sum_bit Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {} Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_and"; } + const char *func_name() const { return "bit_and("; } Item *copy_or_same(THD* thd); }; @@ -513,7 +642,7 @@ class Item_sum_xor :public Item_sum_bit Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_xor"; } + const char *func_name() const { return "bit_xor("; } Item *copy_or_same(THD* thd); }; @@ -530,18 +659,21 @@ protected: udf_handler udf; public: - Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;} - Item_udf_sum( udf_func *udf_arg, List &list ) - :Item_sum( list ), udf(udf_arg) + Item_udf_sum(udf_func *udf_arg) + :Item_sum(), udf(udf_arg) + { quick_group=0; } + Item_udf_sum(udf_func *udf_arg, List &list) + :Item_sum(list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } + :Item_sum(thd, item), udf(item->udf) + { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; - return udf.fix_fields(thd,tables,this,this->arg_count,this->args); + return udf.fix_fields(thd, this, this->arg_count, this->args); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } @@ -551,21 +683,27 @@ public: void reset_field() {}; void update_field() {}; void cleanup(); + void print(String *str); }; class Item_sum_udf_float :public Item_udf_sum { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) Item_sum_udf_float::val(); } - double val(); + { + DBUG_ASSERT(fixed == 1); + return (longlong) Item_sum_udf_float::val_real(); + } + double val_real(); String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec() { fix_num_length_and_dec(); } Item *copy_or_same(THD* thd); }; @@ -574,15 +712,17 @@ class Item_sum_udf_float :public Item_udf_sum class Item_sum_udf_int :public Item_udf_sum { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int(); - double val() + double val_real() { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } Item *copy_or_same(THD* thd); @@ -592,43 +732,72 @@ public: class Item_sum_udf_str :public Item_udf_sum { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List &list) :Item_udf_sum(udf_arg,list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_udf_sum(thd, item) {} String *val_str(String *); - double val() + double val_real() { - int err; + int err_not_used; char *end_not_used; String *res; res=val_str(&str_value); return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(), - &end_not_used, &err) : 0.0; + &end_not_used, &err_not_used) : 0.0; } longlong val_int() { - int err; - String *res; res=val_str(&str_value); - return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0; + int err_not_used; + char *end; + String *res; + CHARSET_INFO *cs; + + if (!(res= val_str(&str_value))) + return 0; /* Null value */ + cs= res->charset(); + end= (char*) res->ptr()+res->length(); + return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used); } + my_decimal *val_decimal(my_decimal *dec); enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); Item *copy_or_same(THD* thd); }; + +class Item_sum_udf_decimal :public Item_udf_sum +{ +public: + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) + :Item_udf_sum(udf_arg, list) {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) + :Item_udf_sum(thd, item) {} + String *val_str(String *); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec() { fix_num_length_and_dec(); } + Item *copy_or_same(THD* thd); +}; + #else /* Dummy functions to get sql_yacc.cc compiled */ class Item_sum_udf_float :public Item_sum_num { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List &list) :Item_sum_num() {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - double val() { DBUG_ASSERT(fixed == 1); return 0.0; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void clear() {} bool add() { return 0; } void update_field() {} @@ -638,29 +807,50 @@ class Item_sum_udf_float :public Item_sum_num class Item_sum_udf_int :public Item_sum_num { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List &list) :Item_sum_num() {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } - double val() { DBUG_ASSERT(fixed == 1); return 0; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0; } void clear() {} bool add() { return 0; } void update_field() {} }; +class Item_sum_udf_decimal :public Item_sum_num +{ + public: + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) + :Item_sum_num() {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) + :Item_sum_num(thd, item) {} + enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } + void clear() {} + bool add() { return 0; } + void update_field() {} +}; + + class Item_sum_udf_str :public Item_sum_num { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_str(udf_func *udf_arg, List &list) :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg, List &list) + :Item_sum_num() {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_num(thd, item) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - double val() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } + double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { maybe_null=1; max_length=0; } @@ -676,15 +866,26 @@ class MYSQL_ERROR; class Item_func_group_concat : public Item_sum { - THD *item_thd; TMP_TABLE_PARAM *tmp_table_param; - uint max_elements_in_tree; MYSQL_ERROR *warning; - uint key_length; - bool tree_mode; + String result; + String *separator; + TREE tree_base; + TREE *tree; + TABLE *table; + ORDER **order; + Name_resolution_context *context; + uint arg_count_order; // total count of ORDER BY items + uint arg_count_field; // count of arguments + uint count_cut_values; bool distinct; bool warning_for_row; bool always_null; + /* + Following is 0 normal object and pointer to original one for copy + (to correctly free resources) + */ + Item_func_group_concat *original; friend int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2); @@ -693,7 +894,8 @@ class Item_func_group_concat : public Item_sum friend int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2); - friend int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), + friend int dump_leaf_key(byte* key, + element_count count __attribute__((unused)), Item_func_group_concat *group_concat_item); public: @@ -719,8 +921,13 @@ class Item_func_group_concat : public Item_sum Item_func_group_concat(bool is_distinct,List *is_select, SQL_LIST *is_order,String *is_separator); +public: + Item_func_group_concat(Name_resolution_context *context_arg, + bool is_distinct, List *is_select, + SQL_LIST *is_order, String *is_separator); + Item_func_group_concat(THD *thd, Item_func_group_concat *item); - ~Item_func_group_concat(); + ~Item_func_group_concat() {} void cleanup(); enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} @@ -728,12 +935,12 @@ class Item_func_group_concat : public Item_sum virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); - void reset_field(); - bool fix_fields(THD *, TABLE_LIST *, Item **); + void reset_field() {} // not used + void update_field() {} // not used + bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); - virtual void update_field() {} - double val() + double val_real() { String *res; res=val_str(&str_value); return res ? my_atof(res->c_ptr()) : 0.0; @@ -748,8 +955,14 @@ class Item_func_group_concat : public Item_sum end_ptr= (char*) res->ptr()+ res->length(); return my_strtoll10(res->ptr(), &end_ptr, &error); } + my_decimal *val_decimal(my_decimal *decimal_value) + { + return val_decimal_from_string(decimal_value); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; From c2c2adfdfd7471d18c6258d258ac71b8667d3411 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 21:38:27 -0700 Subject: [PATCH 56/56] item_sum.cc, item_sum.h: Post-merge fix. sql/item_sum.h: Post-merge fix. sql/item_sum.cc: Post-merge fix. --- sql/item_sum.cc | 6 ------ sql/item_sum.h | 28 +++------------------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2ed1a18c3b0..13587d8a4c3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2972,12 +2972,6 @@ bool Item_func_group_concat::add() } -void Item_func_group_concat::reset_field() -{ - DBUG_ASSERT(0); -} - - bool Item_func_group_concat::fix_fields(THD *thd, Item **ref) { diff --git a/sql/item_sum.h b/sql/item_sum.h index a1a232c4308..87cc248e5e4 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -881,6 +881,7 @@ class Item_func_group_concat : public Item_sum bool distinct; bool warning_for_row; bool always_null; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) @@ -898,29 +899,6 @@ class Item_func_group_concat : public Item_sum element_count count __attribute__((unused)), Item_func_group_concat *group_concat_item); - public: - String result; - String *separator; - TREE tree_base; - TREE *tree; - TABLE *table; - ORDER **order; - TABLE_LIST *tables_list; - ulong group_concat_max_len; - uint arg_count_order; - uint arg_count_field; - uint field_list_offset; - uint count_cut_values; - bool no_appended; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_func_group_concat *original; - - Item_func_group_concat(bool is_distinct,List *is_select, - SQL_LIST *is_order,String *is_separator); - public: Item_func_group_concat(Name_resolution_context *context_arg, bool is_distinct, List *is_select, @@ -935,8 +913,8 @@ public: virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); - void reset_field() {} // not used - void update_field() {} // not used + void reset_field() { DBUG_ASSERT(0); } // not used + void update_field() { DBUG_ASSERT(0); } // not used bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique();