diff options
673 files changed, 12485 insertions, 4698 deletions
diff --git a/.bzrignore b/.bzrignore index 9c6cf2c965c..2c20c4daf22 100644 --- a/.bzrignore +++ b/.bzrignore @@ -357,6 +357,7 @@ innobase/conftest.s1 innobase/conftest.subs innobase/ib_config.h innobase/ib_config.h.in +innobase/mkinstalldirs innobase/stamp-h1 insert_test install @@ -537,6 +538,7 @@ mit-pthreads/machdep.c mit-pthreads/pg++ mit-pthreads/pgcc mit-pthreads/syscall.S +mkinstalldirs myisam/FT1.MYD myisam/FT1.MYI myisam/ft_dump @@ -639,6 +641,7 @@ mysql-test/r/slave-stopped.eval mysql-test/share/mysql mysql-test/std_data/*.pem mysql-test/t/index_merge.load +mysql-test/var mysql-test/var/* mysql.kdevprj mysql.proj @@ -793,6 +796,7 @@ ndb/src/common/portlib/libportlib.dsp ndb/src/common/transporter/libtransporter.dsp ndb/src/common/util/libgeneral.dsp ndb/src/cw/cpcd/ndb_cpcd +ndb/src/dummy.cpp ndb/src/kernel/blocks/backup/libbackup.dsp ndb/src/kernel/blocks/backup/restore/ndb_restore ndb/src/kernel/blocks/cmvmi/libcmvmi.dsp @@ -879,6 +883,7 @@ ndb/test/tools/hugoScanUpdate ndb/test/tools/ndb_cpcc ndb/test/tools/restart ndb/test/tools/verify_index +ndb/tools/ndb_config ndb/tools/ndb_delete_all ndb/tools/ndb_delete_all.dsp ndb/tools/ndb_desc @@ -1116,4 +1121,3 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl -ndb/src/dummy.cpp diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh index 3adfafb0ce6..47a80a709a8 100755 --- a/BUILD/autorun.sh +++ b/BUILD/autorun.sh @@ -1,21 +1,21 @@ #!/bin/sh # Create MySQL autotools infrastructure -aclocal || (echo "Can't execute aclocal" && exit 1) -autoheader || (echo "Can't execute autoheader" && exit 1) +die() { echo "$@"; exit 1; } + +aclocal || die "Can't execute aclocal" +autoheader || die "Can't execute autoheader" # --force means overwrite ltmain.sh script if it already exists # Added glibtoolize reference to make native OSX autotools work if [ -f /usr/bin/glibtoolize ] ; then - glibtoolize --automake --force \ - || (echo "Can't execute glibtoolize" && exit 1) + glibtoolize --automake --force || die "Can't execute glibtoolize" else - libtoolize --automake --force \ - || (echo "Can't execute libtoolize" && exit 1) + libtoolize --automake --force || die "Can't execute libtoolize" fi + # --add-missing instructs automake to install missing auxiliary files # and --force to overwrite them if they already exist -automake --add-missing --force \ - || (echo "Can't execute automake" && exit 1) -autoconf || (echo "Can't execute autoconf" && exit 1) +automake --add-missing --force || die "Can't execute automake" +autoconf || die "Can't execute autoconf" (cd bdb/dist && sh s_all) (cd innobase && aclocal && autoheader && aclocal && automake && autoconf) diff --git a/VC++Files/client/mysqlclient.dsp b/VC++Files/client/mysqlclient.dsp index c0d891b1c9a..5499379be8d 100644 --- a/VC++Files/client/mysqlclient.dsp +++ b/VC++Files/client/mysqlclient.dsp @@ -451,10 +451,6 @@ SOURCE=..\mysys\my_symlink2.c # End Source File # Begin Source File -SOURCE=..\mysys\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=..\libmysql\my_time.c # End Source File # Begin Source File diff --git a/VC++Files/client/mysqlclient_ia64.dsp b/VC++Files/client/mysqlclient_ia64.dsp index e38f37d61e6..bafe729cf6b 100644 --- a/VC++Files/client/mysqlclient_ia64.dsp +++ b/VC++Files/client/mysqlclient_ia64.dsp @@ -155,7 +155,7 @@ SOURCE="..\strings\ctype-czech.c" # End Source File # Begin Source File -SOURCE="..\strings\ctype-cp963.c" +SOURCE="..\strings\ctype-cp932.c" # End Source File # Begin Source File @@ -436,10 +436,6 @@ SOURCE=..\mysys\my_symlink2.c # End Source File # Begin Source File -SOURCE=..\mysys\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=..\mysys\my_thr_init.c # End Source File # Begin Source File diff --git a/VC++Files/libmysql/libmysql.dsp b/VC++Files/libmysql/libmysql.dsp index 356aac3563f..883557e7b63 100644 --- a/VC++Files/libmysql/libmysql.dsp +++ b/VC++Files/libmysql/libmysql.dsp @@ -419,10 +419,6 @@ SOURCE=..\mysys\my_symlink2.c # End Source File # Begin Source File -SOURCE=..\mysys\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=..\mysys\my_thr_init.c # End Source File # Begin Source File diff --git a/VC++Files/libmysql/libmysql_ia64.dsp b/VC++Files/libmysql/libmysql_ia64.dsp index 75586ef2cf6..717125d5497 100644 --- a/VC++Files/libmysql/libmysql_ia64.dsp +++ b/VC++Files/libmysql/libmysql_ia64.dsp @@ -406,10 +406,6 @@ SOURCE=..\mysys\my_symlink2.c # End Source File # Begin Source File -SOURCE=..\mysys\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=..\mysys\my_thr_init.c # End Source File # Begin Source File diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp index 85bd8ca023e..49ecedfa055 100644 --- a/VC++Files/libmysqld/libmysqld.dsp +++ b/VC++Files/libmysqld/libmysqld.dsp @@ -72,7 +72,7 @@ LINK32=xilink6.exe # PROP Intermediate_Dir "debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBMYSQLD_EXPORTS" /YX /FD /GZ /c
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBMYSQLD_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MT /W3 /Z7 /Od /I "../include" /I "../libmysqld" /I "../sql" /I "../regex" /I "../extra/yassl/include" /I "../bdb/build_win32" /I "../zlib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "SAFEMALLOC" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c # SUBTRACT CPP /X /Fr # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index ab5077810b2..e239318d54d 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -533,10 +533,6 @@ SOURCE=.\my_sync.c # End Source File # Begin Source File -SOURCE=.\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=.\my_thr_init.c # End Source File # Begin Source File diff --git a/VC++Files/mysys/mysys_ia64.dsp b/VC++Files/mysys/mysys_ia64.dsp index a0877457286..b0ce2b4c579 100644 --- a/VC++Files/mysys/mysys_ia64.dsp +++ b/VC++Files/mysys/mysys_ia64.dsp @@ -526,10 +526,6 @@ SOURCE=.\my_sync.c # End Source File # Begin Source File -SOURCE=.\my_tempnam.c -# End Source File -# Begin Source File - SOURCE=.\my_thr_init.c # End Source File # Begin Source File diff --git a/client/client_priv.h b/client/client_priv.h index c8aa7385276..27e0f838995 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -49,5 +49,6 @@ enum options_client #ifdef HAVE_NDBCLUSTER_DB OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, #endif - OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE + OPT_IGNORE_TABLE, OPT_INSERT_IGNORE, OPT_SHOW_WARNINGS, OPT_DROP_DATABASE, + OPT_TRIGGER }; diff --git a/client/mysql.cc b/client/mysql.cc index f98bf467588..871936d7800 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -44,7 +44,7 @@ #include <locale.h> #endif -const char *VER= "14.11"; +const char *VER= "14.12"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -340,16 +340,15 @@ static sig_handler mysql_end(int sig); int main(int argc,char *argv[]) { char buff[80]; - char *defaults, *extra_defaults; - char *emb_argv[3]; - int emb_argc= 1; + char *defaults, *extra_defaults, *group_suffix; + char *emb_argv[4]; + int emb_argc; - emb_argv[0]= argv[0]; - get_defaults_files(argc, argv, &defaults, &extra_defaults); - if (defaults) - emb_argv[emb_argc++]= defaults; - if (extra_defaults) - emb_argv[emb_argc++]= extra_defaults; + /* Get --defaults-xxx args for mysql_server_init() */ + emb_argc= get_defaults_options(argc, argv, &defaults, &extra_defaults, + &group_suffix)+1; + memcpy((char*) emb_argv, (char*) argv, emb_argc * sizeof(*argv)); + emb_argv[emb_argc]= 0; MY_INIT(argv[0]); DBUG_ENTER("main"); @@ -2060,6 +2059,7 @@ static void end_tee() return; } + static int com_ego(String *buffer,char *line) { @@ -2071,8 +2071,10 @@ com_ego(String *buffer,char *line) return result; } -static char *fieldtype2str(enum enum_field_types type) { - switch(type) { + +static const char *fieldtype2str(enum enum_field_types type) +{ + switch (type) { case FIELD_TYPE_BIT: return "BIT"; case FIELD_TYPE_BLOB: return "BLOB"; case FIELD_TYPE_DATE: return "DATE"; diff --git a/client/mysqldump.c b/client/mysqldump.c index 5705571777a..48e5d8c52dd 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -86,7 +86,8 @@ static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, opt_delete_master_logs=0, tty_password=0, opt_single_transaction=0, opt_comments= 0, opt_compact= 0, opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, - opt_complete_insert= 0, opt_drop_database= 0; + opt_complete_insert= 0, opt_drop_database= 0, + opt_dump_triggers= 0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*sock=0; static my_bool insert_pat_inited=0; @@ -371,6 +372,9 @@ static struct my_option my_long_options[] = (gptr*) &path, (gptr*) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tables", OPT_TABLES, "Overrides option --databases (-B).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"triggers", OPT_TRIGGER, "Dump triggers for each dumped table", + (gptr*) &opt_dump_triggers, (gptr*) &opt_dump_triggers, 0, GET_BOOL, + NO_ARG, 1, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE {"user", 'u', "User for login if not current user.", (gptr*) ¤t_user, (gptr*) ¤t_user, 0, GET_STR, REQUIRED_ARG, @@ -1212,7 +1216,7 @@ static uint get_table_structure(char *table, char *db) opt_quoted_table= quote_name(table, table_buff2, 0); if (opt_order_by_primary) - order_by = primary_key_fields(opt_quoted_table); + order_by = primary_key_fields(result_table); if (!opt_xml && !mysql_query_with_error_report(sock, 0, query_buff)) { @@ -1272,7 +1276,7 @@ static uint get_table_structure(char *table, char *db) /* Create temp table by selecting from the view */ my_snprintf(query_buff, sizeof(query_buff), - "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0", + "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0", result_table, result_table); if (mysql_query_with_error_report(sock, 0, query_buff)) { @@ -1292,10 +1296,11 @@ static uint get_table_structure(char *table, char *db) row= mysql_fetch_row(tableRes); if (opt_drop) - fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table); + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", + opt_quoted_table); /* Print CREATE statement but remove TEMPORARY */ - fprintf(sql_file, "CREATE %s;\n", row[1]+17); + fprintf(sql_file, "/*!50001 CREATE %s*/;\n", row[1]+17); check_io(sql_file); mysql_free_result(tableRes); @@ -1315,6 +1320,41 @@ static uint get_table_structure(char *table, char *db) fprintf(sql_file, "%s;\n", row[1]); check_io(sql_file); mysql_free_result(tableRes); + if (opt_dump_triggers && + mysql_get_server_version(sock) >= 50009) + { + my_snprintf(query_buff, sizeof(query_buff), + "SHOW TRIGGERS LIKE %s", + quote_for_like(table, name_buff)); + + + if (mysql_query_with_error_report(sock, &tableRes, query_buff)) + { + if (path) + my_fclose(sql_file, MYF(MY_WME)); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + if (mysql_num_rows(tableRes)) + fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n\ +DELIMITER //;\n"); + while ((row=mysql_fetch_row(tableRes))) + { + fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/ //\n\ +/*!50003 CREATE TRIGGER %s %s %s ON %s FOR EACH ROW%s*/ //\n\n", + row[6], /* sql_mode */ + quote_name(row[0], name_buff, 0), /* Trigger */ + row[4], /* Timing */ + row[1], /* Event */ + result_table, + row[3] /* Statement */); + } + if (mysql_num_rows(tableRes)) + fprintf(sql_file, + "DELIMITER ;//\n\ +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;"); + mysql_free_result(tableRes); + } } my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", result_table); @@ -1391,7 +1431,7 @@ static uint get_table_structure(char *table, char *db) fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", result_table); if (opt_drop) - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table); + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table); if (!opt_xml) fprintf(sql_file, "CREATE TABLE %s (\n", result_table); else @@ -2782,6 +2822,7 @@ static const char *check_if_ignore_table(const char *table_name) or if there is some failure. It is better to continue to dump the table unsorted, rather than exit without dumping the data. */ + static char *primary_key_fields(const char *table_name) { MYSQL_RES *res = NULL; @@ -2818,11 +2859,13 @@ static char *primary_key_fields(const char *table_name) } /* Build the ORDER BY clause result */ - if (result_length) { + if (result_length) + { char *end; /* result (terminating \0 is already in result_length) */ result = my_malloc(result_length + 10, MYF(MY_WME)); - if (!result) { + if (!result) + { fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n"); goto cleanup; } @@ -2919,13 +2962,15 @@ static my_bool get_view_structure(char *table, char* db) } if (opt_drop) { - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); - fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table); + fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n", + opt_quoted_table); + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", + opt_quoted_table); check_io(sql_file); } row= mysql_fetch_row(table_res); - fprintf(sql_file, "%s;\n", row[1]); + fprintf(sql_file, "/*!50001 %s*/;\n", row[1]); check_io(sql_file); mysql_free_result(table_res); diff --git a/client/mysqltest.c b/client/mysqltest.c index 67fa931a3f3..4b8bb047e47 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3393,10 +3393,10 @@ static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, int10_to_str((int) field->type, buff, 10); dynstr_append(ds, buff); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->length, buff, 10); + longlong10_to_str((unsigned int) field->length, buff, 10); dynstr_append(ds, buff); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->max_length, buff, 10); + longlong10_to_str((unsigned int) field->max_length, buff, 10); dynstr_append(ds, buff); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c index 40093d6647f..051f3e8e42e 100644 --- a/cmd-line-utils/libedit/read.c +++ b/cmd-line-utils/libedit/read.c @@ -478,7 +478,7 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ break; } - if ((uint)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ + if ((unsigned int)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, "ERROR: illegal command from key 0%o\r\n", ch); diff --git a/cmd-line-utils/readline/INSTALL b/cmd-line-utils/readline/INSTALL index adb27a9f222..cb4a06fb701 100644 --- a/cmd-line-utils/readline/INSTALL +++ b/cmd-line-utils/readline/INSTALL @@ -1,7 +1,7 @@ Basic Installation ================== -These are installation instructions for Readline-4.3. +These are installation instructions for Readline-5.0. The simplest way to compile readline is: diff --git a/cmd-line-utils/readline/Makefile.am b/cmd-line-utils/readline/Makefile.am index 14d25ff62c0..f5e41b7e2e9 100644 --- a/cmd-line-utils/readline/Makefile.am +++ b/cmd-line-utils/readline/Makefile.am @@ -17,7 +17,8 @@ libreadline_a_SOURCES = readline.c funmap.c keymaps.c \ callback.c terminal.c xmalloc.c \ history.c histsearch.c histexpand.c \ histfile.c nls.c search.c \ - shell.c tilde.c misc.c text.c mbutil.c + shell.c tilde.c misc.c text.c mbutil.c \ + compat.c savestring.c pkginclude_HEADERS = readline.h chardefs.h keymaps.h \ history.h tilde.h rlmbutil.h rltypedefs.h rlprivate.h \ diff --git a/cmd-line-utils/readline/README b/cmd-line-utils/readline/README index 7aa939452fb..ac4e3a767f9 100644 --- a/cmd-line-utils/readline/README +++ b/cmd-line-utils/readline/README @@ -1,7 +1,7 @@ Introduction ============ -This is the Gnu Readline library, version 4.3. +This is the Gnu Readline library, version 5.0. The Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in. Both diff --git a/cmd-line-utils/readline/bind.c b/cmd-line-utils/readline/bind.c index 0e8efc5c636..17f61d1df08 100644 --- a/cmd-line-utils/readline/bind.c +++ b/cmd-line-utils/readline/bind.c @@ -19,8 +19,13 @@ is generally kept in a file called COPYING or LICENSE. If you do not have a copy of the license, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + #define READLINE_LIBRARY +#if defined (__TANDEM) +# include <floss.h> +#endif + #include "config_readline.h" #include <stdio.h> @@ -146,6 +151,34 @@ rl_bind_key_in_map (key, function, map) return (result); } +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ +int +rl_bind_key_if_unbound_in_map (key, default_func, kmap) + int key; + rl_command_func_t *default_func; + Keymap kmap; +{ + char keyseq[2]; + + keyseq[0] = (unsigned char)key; + keyseq[1] = '\0'; + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap)); +} + +int +rl_bind_key_if_unbound (key, default_func) + int key; + rl_command_func_t *default_func; +{ + char keyseq[2]; + + keyseq[0] = (unsigned char)key; + keyseq[1] = '\0'; + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); +} + /* Make KEY do nothing in the currently selected keymap. Returns non-zero in case of error. */ int @@ -198,9 +231,30 @@ rl_unbind_command_in_map (command, map) } /* Bind the key sequence represented by the string KEYSEQ to + FUNCTION, starting in the current keymap. This makes new + keymaps as necessary. */ +int +rl_bind_keyseq (keyseq, function) + const char *keyseq; + rl_command_func_t *function; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap)); +} + +/* Bind the key sequence represented by the string KEYSEQ to FUNCTION. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ int +rl_bind_keyseq_in_map (keyseq, function, map) + const char *keyseq; + rl_command_func_t *function; + Keymap map; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); +} + +/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */ +int rl_set_key (keyseq, function, map) const char *keyseq; rl_command_func_t *function; @@ -209,6 +263,40 @@ rl_set_key (keyseq, function, map) return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); } +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ +int +rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap) + const char *keyseq; + rl_command_func_t *default_func; + Keymap kmap; +{ + rl_command_func_t *func; + + if (keyseq) + { + func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL); +#if defined (VI_MODE) + if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) +#else + if (!func || func == rl_do_lowercase_version) +#endif + return (rl_bind_keyseq_in_map (keyseq, default_func, kmap)); + else + return 1; + } + return 0; +} + +int +rl_bind_keyseq_if_unbound (keyseq, default_func) + const char *keyseq; + rl_command_func_t *default_func; +{ + return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap)); +} + /* Bind the key sequence represented by the string KEYSEQ to the string of characters MACRO. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */ @@ -346,7 +434,7 @@ rl_translate_keyseq (seq, array, len) { register int i, c, l, temp; - for (i = l = 0; (c = seq[i]); i++) + for (i = l = 0; c = seq[i]; i++) { if (c == '\\') { @@ -678,7 +766,7 @@ _rl_read_file (filename, sizep) /* Re-read the current keybindings file. */ int rl_re_read_init_file (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { int r; r = rl_read_init_file ((const char *)NULL); @@ -900,7 +988,7 @@ parser_if (args) /* Invert the current parser state if there is anything on the stack. */ static int parser_else (args) - char *args __attribute__((unused)); + char *args; { register int i; @@ -910,9 +998,15 @@ parser_else (args) return 0; } +#if 0 /* Check the previous (n - 1) levels of the stack to make sure that we haven't previously turned off parsing. */ for (i = 0; i < if_stack_depth - 1; i++) +#else + /* Check the previous (n) levels of the stack to make sure that + we haven't previously turned off parsing. */ + for (i = 0; i < if_stack_depth; i++) +#endif if (if_stack[i] == 1) return 0; @@ -925,7 +1019,7 @@ parser_else (args) _rl_parsing_conditionalized_out from the stack. */ static int parser_endif (args) - char *args __attribute__((unused)); + char *args; { if (if_stack_depth) _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; @@ -1048,7 +1142,7 @@ rl_parse_and_bind (string) { int passc = 0; - for (i = 1; (c = string[i]); i++) + for (i = 1; c = string[i]; i++) { if (passc) { @@ -1124,7 +1218,7 @@ rl_parse_and_bind (string) { int delimiter = string[i++], passc; - for (passc = 0; (c = string[i]); i++) + for (passc = 0; c = string[i]; i++) { if (passc) { @@ -1159,7 +1253,7 @@ rl_parse_and_bind (string) } /* If this is a new-style key-binding, then do the binding with - rl_set_key (). Otherwise, let the older code deal with it. */ + rl_bind_keyseq (). Otherwise, let the older code deal with it. */ if (*string == '"') { char *seq; @@ -1198,7 +1292,7 @@ rl_parse_and_bind (string) rl_macro_bind (seq, &funname[1], _rl_keymap); } else - rl_set_key (seq, rl_named_function (funname), _rl_keymap); + rl_bind_keyseq (seq, rl_named_function (funname)); free (seq); return 0; @@ -1279,10 +1373,11 @@ static struct { { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, + { "show-all-if-unmodified", &_rl_complete_show_unmodified, 0 }, #if defined (VISIBLE_STATS) { "visible-stats", &rl_visible_stats, 0 }, #endif /* VISIBLE_STATS */ - { (char *)NULL, (int *)NULL, 0 } + { (char *)NULL, (int *)NULL } }; static int @@ -1351,7 +1446,7 @@ static struct { { "editing-mode", V_STRING, sv_editmode }, { "isearch-terminators", V_STRING, sv_isrchterm }, { "keymap", V_STRING, sv_keymap }, - { (char *)NULL, 0, 0 } + { (char *)NULL, 0 } }; static int @@ -1626,8 +1721,7 @@ rl_set_keymap_from_edit_mode () #endif /* VI_MODE */ } - -const char * +char * rl_get_keymap_name_from_edit_mode () { if (rl_editing_mode == emacs_mode) @@ -1637,7 +1731,7 @@ rl_get_keymap_name_from_edit_mode () return "vi"; #endif /* VI_MODE */ else - return "nope"; + return "none"; } /* **************************************************************** */ @@ -1649,7 +1743,7 @@ rl_get_keymap_name_from_edit_mode () /* Each of the following functions produces information about the state of keybindings and functions known to Readline. The info is always printed to rl_outstream, and in such a way that it can - be read back in (i.e., passed to rl_parse_and_bind (). */ + be read back in (i.e., passed to rl_parse_and_bind ()). */ /* Print the names of functions known to Readline. */ void @@ -1872,7 +1966,7 @@ rl_function_dumper (print_readably) fprintf (rl_outstream, "\n"); - for (i = 0; (name = names[i]); i++) + for (i = 0; name = names[i]; i++) { rl_command_func_t *function; char **invokers; @@ -1932,7 +2026,7 @@ rl_function_dumper (print_readably) the output in such a way that it can be read back in. */ int rl_dump_functions (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (rl_dispatching) fprintf (rl_outstream, "\r\n"); @@ -2012,7 +2106,7 @@ rl_macro_dumper (print_readably) int rl_dump_macros (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (rl_dispatching) fprintf (rl_outstream, "\r\n"); @@ -2102,7 +2196,7 @@ rl_variable_dumper (print_readably) the output in such a way that it can be read back in. */ int rl_dump_variables (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (rl_dispatching) fprintf (rl_outstream, "\r\n"); @@ -2111,28 +2205,6 @@ rl_dump_variables (count, key) return (0); } -/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right - now, this is always used to attempt to bind the arrow keys, hence the - check for rl_vi_movement_mode. */ -void -_rl_bind_if_unbound (keyseq, default_func) - const char *keyseq; - rl_command_func_t *default_func; -{ - rl_command_func_t *func; - - if (keyseq) - { - func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL); -#if defined (VI_MODE) - if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) -#else - if (!func || func == rl_do_lowercase_version) -#endif - rl_set_key (keyseq, default_func, _rl_keymap); - } -} - /* Return non-zero if any members of ARRAY are a substring in STRING. */ static int substring_member_of_array (string, array) diff --git a/cmd-line-utils/readline/callback.c b/cmd-line-utils/readline/callback.c index 737f483eed0..0807f137b92 100644 --- a/cmd-line-utils/readline/callback.c +++ b/cmd-line-utils/readline/callback.c @@ -129,7 +129,7 @@ rl_callback_read_char () if (in_handler == 0 && rl_linefunc) _rl_callback_newline (); } - if (rl_pending_input) + if (rl_pending_input || _rl_pushed_input_available ()) eof = readline_internal_char (); else break; diff --git a/cmd-line-utils/readline/chardefs.h b/cmd-line-utils/readline/chardefs.h index a537be220b0..cb04c982343 100644 --- a/cmd-line-utils/readline/chardefs.h +++ b/cmd-line-utils/readline/chardefs.h @@ -77,7 +77,11 @@ # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) #endif -#define NON_NEGATIVE(c) ((unsigned char)(c) == (c)) +#if defined (CTYPE_NON_ASCII) +# define NON_NEGATIVE(c) 1 +#else +# define NON_NEGATIVE(c) ((unsigned char)(c) == (c)) +#endif /* Some systems define these; we want our definitions. */ #undef ISPRINT diff --git a/cmd-line-utils/readline/compat.c b/cmd-line-utils/readline/compat.c new file mode 100644 index 00000000000..e4fbc322cee --- /dev/null +++ b/cmd-line-utils/readline/compat.c @@ -0,0 +1,111 @@ +/* compat.c -- backwards compatibility functions. */ + +/* Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library 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, or + (at your option) any later version. + + The GNU Readline Library 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. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#include "config_readline.h" + +#include <stdio.h> + +#include "rlstdc.h" +#include "rltypedefs.h" + +extern void rl_free_undo_list PARAMS((void)); +extern int rl_maybe_save_line PARAMS((void)); +extern int rl_maybe_unsave_line PARAMS((void)); +extern int rl_maybe_replace_line PARAMS((void)); + +extern int rl_crlf PARAMS((void)); +extern int rl_ding PARAMS((void)); +extern int rl_alphabetic PARAMS((int)); + +extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *)); +extern char *rl_username_completion_function PARAMS((const char *, int)); +extern char *rl_filename_completion_function PARAMS((const char *, int)); + +/* Provide backwards-compatible entry points for old function names. */ + +void +free_undo_list () +{ + rl_free_undo_list (); +} + +int +maybe_replace_line () +{ + return rl_maybe_replace_line (); +} + +int +maybe_save_line () +{ + return rl_maybe_save_line (); +} + +int +maybe_unsave_line () +{ + return rl_maybe_unsave_line (); +} + +int +ding () +{ + return rl_ding (); +} + +int +crlf () +{ + return rl_crlf (); +} + +int +alphabetic (c) + int c; +{ + return rl_alphabetic (c); +} + +char ** +completion_matches (s, f) + const char *s; + rl_compentry_func_t *f; +{ + return rl_completion_matches (s, f); +} + +char * +username_completion_function (s, i) + const char *s; + int i; +{ + return rl_username_completion_function (s, i); +} + +char * +filename_completion_function (s, i) + const char *s; + int i; +{ + return rl_filename_completion_function (s, i); +} diff --git a/cmd-line-utils/readline/complete.c b/cmd-line-utils/readline/complete.c index 749875e0e5e..2196c66a54c 100644 --- a/cmd-line-utils/readline/complete.c +++ b/cmd-line-utils/readline/complete.c @@ -1,6 +1,6 @@ /* complete.c -- filename completion for readline. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -26,7 +26,7 @@ #include <sys/types.h> #include <fcntl.h> #if defined (HAVE_SYS_FILE_H) -#include <sys/file.h> +# include <sys/file.h> #endif #if defined (HAVE_UNISTD_H) @@ -97,12 +97,16 @@ rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)N static int stat_char PARAMS((char *)); #endif +static int path_isdir PARAMS((const char *)); + static char *rl_quote_filename PARAMS((char *, int, char *)); static void set_completion_defaults PARAMS((int)); static int get_y_or_n PARAMS((int)); static int _rl_internal_pager PARAMS((int)); static char *printable_part PARAMS((char *)); +static int fnwidth PARAMS((const char *)); +static int fnprint PARAMS((const char *)); static int print_filename PARAMS((char *, char *)); static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int)); @@ -128,6 +132,10 @@ static char *make_quoted_replacement PARAMS((char *, int, char *)); /* If non-zero, non-unique completions always show the list of matches. */ int _rl_complete_show_all = 0; +/* If non-zero, non-unique completions show the list of matches, unless it + is not possible to do partial completion and modify the line. */ +int _rl_complete_show_unmodified = 0; + /* If non-zero, completed directory names have a slash appended. */ int _rl_complete_mark_directories = 1; @@ -212,7 +220,12 @@ const char *rl_basic_quote_characters = "\"'"; /* The list of characters that signal a break between words for rl_complete_internal. The default list is the contents of rl_basic_word_break_characters. */ -const char *rl_completer_word_break_characters = (const char *)NULL; +/*const*/ char *rl_completer_word_break_characters = (/*const*/ char *)NULL; + +/* Hook function to allow an application to set the completion word + break characters before readline breaks up the line. Allows + position-dependent word break characters. */ +rl_cpvfunc_t *rl_completion_word_break_hook = (rl_cpvfunc_t *)NULL; /* List of characters which can be used to quote a substring of the line. Completion occurs on the entire substring, and within the substring @@ -280,6 +293,19 @@ int rl_completion_suppress_append = 0; default is a space. */ int rl_completion_append_character = ' '; +/* If non-zero, the completion functions don't append any closing quote. + This is set to 0 by rl_complete_internal and may be changed by an + application-specific completion function. */ +int rl_completion_suppress_quote = 0; + +/* Set to any quote character readline thinks it finds before any application + completion function is called. */ +int rl_completion_quote_character; + +/* Set to a non-zero value if readline found quoting anywhere in the word to + be completed; set before any application completion function is called. */ +int rl_completion_found_quote; + /* If non-zero, a slash will be appended to completed filenames that are symbolic links to directory names, subject to the value of the mark-directories variable (which is user-settable). This exists so @@ -318,6 +344,8 @@ rl_complete (ignore, invoking_key) return (rl_complete_internal ('?')); else if (_rl_complete_show_all) return (rl_complete_internal ('!')); + else if (_rl_complete_show_unmodified) + return (rl_complete_internal ('@')); else return (rl_complete_internal (TAB)); } @@ -325,14 +353,14 @@ rl_complete (ignore, invoking_key) /* List the possible completions. See description of rl_complete (). */ int rl_possible_completions (ignore, invoking_key) - int ignore __attribute__((unused)), invoking_key __attribute__((unused)); + int ignore, invoking_key; { return (rl_complete_internal ('?')); } int rl_insert_completions (ignore, invoking_key) - int ignore __attribute__((unused)), invoking_key __attribute__((unused)); + int ignore, invoking_key; { return (rl_complete_internal ('*')); } @@ -350,6 +378,8 @@ rl_completion_mode (cfunc) return '?'; else if (_rl_complete_show_all) return '!'; + else if (_rl_complete_show_unmodified) + return '@'; else return TAB; } @@ -370,7 +400,7 @@ set_completion_defaults (what_to_do) rl_filename_completion_desired = 0; rl_filename_quoting_desired = 1; rl_completion_type = what_to_do; - rl_completion_suppress_append = 0; + rl_completion_suppress_append = rl_completion_suppress_quote = 0; /* The completion entry function may optionally change this. */ rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs; @@ -421,6 +451,15 @@ _rl_internal_pager (lines) return 0; } +static int +path_isdir (filename) + const char *filename; +{ + struct stat finfo; + + return (stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)); +} + #if defined (VISIBLE_STATS) /* Return the character which best describes FILENAME. `@' for symbolic links @@ -518,53 +557,140 @@ printable_part (pathname) return ++temp; } +/* Compute width of STRING when displayed on screen by print_filename */ +static int +fnwidth (string) + const char *string; +{ + int width, pos; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + int left, w; + size_t clen; + wchar_t wc; + + left = strlen (string) + 1; + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + width = pos = 0; + while (string[pos]) + { + if (CTRL_CHAR (*string) || *string == RUBOUT) + { + width += 2; + pos++; + } + else + { +#if defined (HANDLE_MULTIBYTE) + clen = mbrtowc (&wc, string + pos, left - pos, &ps); + if (MB_INVALIDCH (clen)) + { + width++; + pos++; + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (MB_NULLWCH (clen)) + break; + else + { + pos += clen; + w = wcwidth (wc); + width += (w >= 0) ? w : 1; + } +#else + width++; + pos++; +#endif + } + } + + return width; +} + +static int +fnprint (to_print) + const char *to_print; +{ + int printed_len; + const char *s; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + const char *end; + size_t tlen; + + end = to_print + strlen (to_print) + 1; + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + printed_len = 0; + s = to_print; + while (*s) + { + if (CTRL_CHAR (*s)) + { + putc ('^', rl_outstream); + putc (UNCTRL (*s), rl_outstream); + printed_len += 2; + s++; +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); +#endif + } + else if (*s == RUBOUT) + { + putc ('^', rl_outstream); + putc ('?', rl_outstream); + printed_len += 2; + s++; +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); +#endif + } + else + { +#if defined (HANDLE_MULTIBYTE) + tlen = mbrlen (s, end - s, &ps); + if (MB_INVALIDCH (tlen)) + { + tlen = 1; + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (MB_NULLWCH (tlen)) + break; + fwrite (s, 1, tlen, rl_outstream); + s += tlen; +#else + putc (*s, rl_outstream); + s++; +#endif + printed_len++; + } + } + + return printed_len; +} + /* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we are using it, check for and output a single character for `special' filenames. Return the number of characters we output. */ -#define PUTX(c) \ - do { \ - if (CTRL_CHAR (c)) \ - { \ - putc ('^', rl_outstream); \ - putc (UNCTRL (c), rl_outstream); \ - printed_len += 2; \ - } \ - else if (c == RUBOUT) \ - { \ - putc ('^', rl_outstream); \ - putc ('?', rl_outstream); \ - printed_len += 2; \ - } \ - else \ - { \ - putc (c, rl_outstream); \ - printed_len++; \ - } \ - } while (0) - static int print_filename (to_print, full_pathname) char *to_print, *full_pathname; { - int printed_len = 0; -#if !defined (VISIBLE_STATS) - char *s; - - for (s = to_print; *s; s++) - { - PUTX (*s); - } -#else + int printed_len, extension_char, slen, tlen; char *s, c, *new_full_pathname; - int extension_char, slen, tlen; - for (s = to_print; *s; s++) - { - PUTX (*s); - } + extension_char = 0; + printed_len = fnprint (to_print); - if (rl_filename_completion_desired && rl_visible_stats) +#if defined (VISIBLE_STATS) + if (rl_filename_completion_desired && (rl_visible_stats || _rl_complete_mark_directories)) +#else + if (rl_filename_completion_desired && _rl_complete_mark_directories) +#endif { /* If to_print != full_pathname, to_print is the basename of the path passed. In this case, we try to expand the directory @@ -591,7 +717,13 @@ print_filename (to_print, full_pathname) new_full_pathname[slen] = '/'; strcpy (new_full_pathname + slen + 1, to_print); - extension_char = stat_char (new_full_pathname); +#if defined (VISIBLE_STATS) + if (rl_visible_stats) + extension_char = stat_char (new_full_pathname); + else +#endif + if (path_isdir (new_full_pathname)) + extension_char = '/'; free (new_full_pathname); to_print[-1] = c; @@ -599,7 +731,13 @@ print_filename (to_print, full_pathname) else { s = tilde_expand (full_pathname); - extension_char = stat_char (s); +#if defined (VISIBLE_STATS) + if (rl_visible_stats) + extension_char = stat_char (s); + else +#endif + if (path_isdir (s)) + extension_char = '/'; } free (s); @@ -609,14 +747,14 @@ print_filename (to_print, full_pathname) printed_len++; } } -#endif /* VISIBLE_STATS */ + return printed_len; } static char * rl_quote_filename (s, rtype, qcp) char *s; - int rtype __attribute__((unused)); + int rtype; char *qcp; { char *r; @@ -649,19 +787,32 @@ _rl_find_completion_word (fp, dp) int *fp, *dp; { int scan, end, found_quote, delimiter, pass_next, isbrk; - char quote_char; + char quote_char, *brkchars; end = rl_point; found_quote = delimiter = 0; quote_char = '\0'; + brkchars = 0; + if (rl_completion_word_break_hook) + brkchars = (*rl_completion_word_break_hook) (); + if (brkchars == 0) + brkchars = rl_completer_word_break_characters; + if (rl_completer_quote_characters) { /* We have a list of characters which can be used in pairs to quote substrings for the completer. Try to find the start of an unclosed quoted substring. */ /* FOUND_QUOTE is set so we know what kind of quotes we found. */ +#if defined (HANDLE_MULTIBYTE) + for (scan = pass_next = 0; scan < end; + scan = ((MB_CUR_MAX == 1 || rl_byte_oriented) + ? (scan + 1) + : _rl_find_next_mbchar (rl_line_buffer, scan, 1, MB_FIND_ANY))) +#else for (scan = pass_next = 0; scan < end; scan++) +#endif { if (pass_next) { @@ -719,7 +870,7 @@ _rl_find_completion_word (fp, dp) { scan = rl_line_buffer[rl_point]; - if (strchr (rl_completer_word_break_characters, scan) == 0) + if (strchr (brkchars, scan) == 0) continue; /* Call the application-specific function to tell us whether @@ -747,9 +898,9 @@ _rl_find_completion_word (fp, dp) if (rl_char_is_quoted_p) isbrk = (found_quote == 0 || (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) && - strchr (rl_completer_word_break_characters, scan) != 0; + strchr (brkchars, scan) != 0; else - isbrk = strchr (rl_completer_word_break_characters, scan) != 0; + isbrk = strchr (brkchars, scan) != 0; if (isbrk) { @@ -784,6 +935,9 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char) { char **matches, *temp; + rl_completion_found_quote = found_quote; + rl_completion_quote_character = quote_char; + /* If the user wants to TRY to complete, but then wants to give up and use the default completion function, they set the variable rl_attempted_completion_function. */ @@ -887,6 +1041,7 @@ compute_lcd_of_matches (match_list, matches, text) { register int i, c1, c2, si; int low; /* Count of max-matched characters. */ + char *dtext; /* dequoted TEXT, if needed */ #if defined (HANDLE_MULTIBYTE) int v; mbstate_t ps1, ps2; @@ -978,6 +1133,26 @@ compute_lcd_of_matches (match_list, matches, text) the user typed in the face of multiple matches differing in case. */ if (_rl_completion_case_fold) { + /* We're making an assumption here: + IF we're completing filenames AND + the application has defined a filename dequoting function AND + we found a quote character AND + the application has requested filename quoting + THEN + we assume that TEXT was dequoted before checking against + the file system and needs to be dequoted here before we + check against the list of matches + FI */ + dtext = (char *)NULL; + if (rl_filename_completion_desired && + rl_filename_dequoting_function && + rl_completion_found_quote && + rl_filename_quoting_desired) + { + dtext = (*rl_filename_dequoting_function) (text, rl_completion_quote_character); + text = dtext; + } + /* sort the list to get consistent answers. */ qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare); @@ -997,6 +1172,8 @@ compute_lcd_of_matches (match_list, matches, text) else /* otherwise, just use the text the user typed. */ strncpy (match_list[0], text, low); + + FREE (dtext); } else strncpy (match_list[0], match_list[1], low); @@ -1201,7 +1378,7 @@ display_matches (matches) for (max = 0, i = 1; matches[i]; i++) { temp = printable_part (matches[i]); - len = strlen (temp); + len = fnwidth (temp); if (len > max) max = len; @@ -1336,7 +1513,8 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) struct stat finfo; temp_string_index = 0; - if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char) + if (quote_char && rl_point && rl_completion_suppress_quote == 0 && + rl_line_buffer[rl_point - 1] != quote_char) temp_string[temp_string_index++] = quote_char; if (delimiter) @@ -1447,7 +1625,9 @@ _rl_free_match_list (matches) TAB means do standard completion. `*' means insert all of the possible completions. `!' means to do standard completion, and list all possible completions if - there is more than one. */ + there is more than one. + `@' means to do standard completion, and list all possible completions if + there is more than one and partial completion is not possible. */ int rl_complete_internal (what_to_do) int what_to_do; @@ -1466,7 +1646,6 @@ rl_complete_internal (what_to_do) our_func = rl_completion_entry_function ? rl_completion_entry_function : rl_filename_completion_function; - /* We now look backwards for the start of a filename/variable word. */ end = rl_point; found_quote = delimiter = 0; @@ -1514,6 +1693,7 @@ rl_complete_internal (what_to_do) { case TAB: case '!': + case '@': /* Insert the first match with proper quoting. */ if (*matches[0]) insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); @@ -1533,6 +1713,12 @@ rl_complete_internal (what_to_do) display_matches (matches); break; } + else if (what_to_do == '@') + { + if (nontrivial_lcd == 0) + display_matches (matches); + break; + } else if (rl_editing_mode != vi_mode) rl_ding (); /* There are other matches remaining. */ } @@ -1610,7 +1796,7 @@ rl_completion_matches (text, entry_function) match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list[1] = (char *)NULL; - while ((string = (*entry_function) (text, matches))) + while (string = (*entry_function) (text, matches)) { if (matches + 1 == match_list_size) match_list = (char **)xrealloc @@ -1660,7 +1846,7 @@ rl_username_completion_function (text, state) setpwent (); } - while ((entry = getpwent ())) + while (entry = getpwent ()) { /* Null usernames should result in all users as possible completions. */ if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) @@ -1897,7 +2083,7 @@ rl_filename_completion_function (text, state) ring the bell, and reset the counter to zero. */ int rl_menu_complete (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { rl_compentry_func_t *our_func; int matching_filenames, found_quote; diff --git a/cmd-line-utils/readline/configure.in b/cmd-line-utils/readline/configure.in index bc78f8a0f60..31e17606024 100644 --- a/cmd-line-utils/readline/configure.in +++ b/cmd-line-utils/readline/configure.in @@ -4,9 +4,9 @@ dnl dnl report bugs to chet@po.cwru.edu dnl dnl Process this file with autoconf to produce a configure script. -AC_REVISION([for Readline 4.3, version 2.45, from autoconf version] AC_ACVERSION) +AC_REVISION([for Readline 5.0, version 2.52, from autoconf version] AC_ACVERSION) -AC_INIT(readline, 4.3, bug-readline@gnu.org) +AC_INIT(readline, 5.0-rc1, bug-readline@gnu.org) dnl make sure we are using a recent autoconf version AC_PREREQ(2.50) @@ -16,7 +16,7 @@ AC_CONFIG_AUX_DIR(./support) AC_CONFIG_HEADERS(config.h) dnl update the value of RL_READLINE_VERSION in readline.h when this changes -LIBVERSION=4.3 +LIBVERSION=5.0 AC_CANONICAL_HOST @@ -31,12 +31,18 @@ if test "$opt_curses" = "yes"; then fi dnl option parsing for optional features +opt_multibyte=yes opt_static_libs=yes opt_shared_libs=yes +AC_ARG_ENABLE(multibyte, AC_HELP_STRING([--enable-multibyte], [enable multibyte characters if OS supports them]), opt_multibyte=$enableval) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build shared libraries [[default=YES]]]), opt_shared_libs=$enableval) AC_ARG_ENABLE(static, AC_HELP_STRING([--enable-static], [build static libraries [[default=YES]]]), opt_static_libs=$enableval) +if test $opt_multibyte = no; then +AC_DEFINE(NO_MULTIBYTE_SUPPORT) +fi + echo "" echo "Beginning configuration for readline-$LIBVERSION for ${host_cpu}-${host_vendor}-${host_os}" echo "" @@ -72,6 +78,8 @@ AC_TYPE_SIGNAL AC_TYPE_SIZE_T AC_CHECK_TYPE(ssize_t, int) +AC_HEADER_STDC + AC_HEADER_STAT AC_HEADER_DIRENT @@ -90,6 +98,7 @@ BASH_SYS_REINSTALL_SIGHANDLERS BASH_FUNC_POSIX_SETJMP BASH_FUNC_LSTAT BASH_FUNC_STRCOLL +BASH_FUNC_CTYPE_NONASCII BASH_CHECK_GETPW_FUNCS diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c index 7c393f1c8a5..cab76c0da81 100644 --- a/cmd-line-utils/readline/display.c +++ b/cmd-line-utils/readline/display.c @@ -1,6 +1,6 @@ /* display.c -- readline redisplay facility. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -119,7 +119,7 @@ int _rl_suppress_redisplay = 0; /* The stuff that gets printed out before the actual text of the line. This is usually pointing to rl_prompt. */ -const char *rl_display_prompt = (char *)NULL; +char *rl_display_prompt = (char *)NULL; /* Pseudo-global variables declared here. */ /* The visible cursor position. If you print some text, adjust this. */ @@ -176,12 +176,15 @@ static int prompt_invis_chars_first_line; static int prompt_last_screen_line; +static int prompt_physical_chars; + /* Expand the prompt string S and return the number of visible characters in *LP, if LP is not null. This is currently more-or-less a placeholder for expansion. LIP, if non-null is a place to store the index of the last invisible character in the returned string. NIFLP, if non-zero, is a place to store the number of invisible characters in - the first prompt line. */ + the first prompt line. The previous are used as byte counts -- indexes + into a character buffer. */ /* Current implementation: \001 (^A) start non-visible characters @@ -191,19 +194,25 @@ static int prompt_last_screen_line; \002 are assumed to be `visible'. */ static char * -expand_prompt (pmt, lp, lip, niflp) +expand_prompt (pmt, lp, lip, niflp, vlp) char *pmt; - int *lp, *lip, *niflp; + int *lp, *lip, *niflp, *vlp; { char *r, *ret, *p; - int l, rl, last, ignoring, ninvis, invfl; + int l, rl, last, ignoring, ninvis, invfl, ind, pind, physchars; /* Short-circuit if we can. */ - if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0) + if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0) { r = savestring (pmt); if (lp) *lp = strlen (r); + if (lip) + *lip = 0; + if (niflp) + *niflp = 0; + if (vlp) + *vlp = lp ? *lp : strlen (r); return r; } @@ -212,7 +221,7 @@ expand_prompt (pmt, lp, lip, niflp) invfl = 0; /* invisible chars in first line of prompt */ - for (rl = ignoring = last = ninvis = 0, p = pmt; p && *p; p++) + for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++) { /* This code strips the invisible character string markers RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ @@ -229,13 +238,35 @@ expand_prompt (pmt, lp, lip, niflp) } else { - *r++ = *p; - if (!ignoring) - rl++; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + pind = p - pmt; + ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO); + l = ind - pind; + while (l--) + *r++ = *p++; + if (!ignoring) + rl += ind - pind; + else + ninvis += ind - pind; + p--; /* compensate for later increment */ + } else - ninvis++; - if (rl == _rl_screenwidth) +#endif + { + *r++ = *p; + if (!ignoring) + rl++; /* visible length byte counter */ + else + ninvis++; /* invisible chars byte counter */ + } + + if (rl >= _rl_screenwidth) invfl = ninvis; + + if (ignoring == 0) + physchars++; } } @@ -249,6 +280,8 @@ expand_prompt (pmt, lp, lip, niflp) *lip = last; if (niflp) *niflp = invfl; + if (vlp) + *vlp = physchars; return ret; } @@ -260,7 +293,7 @@ _rl_strip_prompt (pmt) { char *ret; - ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL); + ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL); return ret; } @@ -304,7 +337,8 @@ rl_expand_prompt (prompt) /* The prompt is only one logical line, though it might wrap. */ local_prompt = expand_prompt (prompt, &prompt_visible_length, &prompt_last_invisible, - &prompt_invis_chars_first_line); + &prompt_invis_chars_first_line, + &prompt_physical_chars); local_prompt_prefix = (char *)0; return (prompt_visible_length); } @@ -314,13 +348,15 @@ rl_expand_prompt (prompt) t = ++p; local_prompt = expand_prompt (p, &prompt_visible_length, &prompt_last_invisible, - &prompt_invis_chars_first_line); + (int *)NULL, + (int *)NULL); c = *t; *t = '\0'; /* The portion of the prompt string up to and including the final newline is now null-terminated. */ local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length, (int *)NULL, - &prompt_invis_chars_first_line); + &prompt_invis_chars_first_line, + &prompt_physical_chars); *t = c; return (prompt_prefix_length); } @@ -379,8 +415,8 @@ rl_redisplay () register int in, out, c, linenum, cursor_linenum; register char *line; int c_pos, inv_botlin, lb_botlin, lb_linenum; - int newlines, lpos, temp; - const char *prompt_this_line; + int newlines, lpos, temp, modmark; + char *prompt_this_line; #if defined (HANDLE_MULTIBYTE) wchar_t wc; size_t wc_bytes; @@ -409,10 +445,12 @@ rl_redisplay () /* Mark the line as modified or not. We only do this for history lines. */ + modmark = 0; if (_rl_mark_modified_lines && current_history () && rl_undo_list) { line[out++] = '*'; line[out] = '\0'; + modmark = 1; } /* If someone thought that the redisplay was handled, but the currently @@ -466,7 +504,7 @@ rl_redisplay () } } - pmtlen = strlen (prompt_this_line); + prompt_physical_chars = pmtlen = strlen (prompt_this_line); temp = pmtlen + out + 2; if (temp >= line_size) { @@ -525,7 +563,12 @@ rl_redisplay () /* inv_lbreaks[i] is where line i starts in the buffer. */ inv_lbreaks[newlines = 0] = 0; +#if 0 lpos = out - wrap_offset; +#else + lpos = prompt_physical_chars + modmark; +#endif + #if defined (HANDLE_MULTIBYTE) memset (_rl_wrapped_line, 0, vis_lbsize); #endif @@ -544,15 +587,13 @@ rl_redisplay () prompt_invis_chars_first_line variable could be made into an array saying how many invisible characters there are per line, but that's probably too much work for the benefit gained. How many people have - prompts that exceed two physical lines? */ + prompts that exceed two physical lines? + Additional logic fix from Edward Catmur <ed@catmur.co.uk> */ temp = ((newlines + 1) * _rl_screenwidth) + -#if 0 - ((newlines == 0) ? prompt_invis_chars_first_line : 0) + -#else - ((newlines == 0 && local_prompt_prefix == 0) ? prompt_invis_chars_first_line : 0) + -#endif - ((newlines == 1) ? wrap_offset : 0); - + ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line + : ((newlines == 1) ? wrap_offset : 0)) + : ((newlines == 0) ? wrap_offset :0)); + inv_lbreaks[++newlines] = temp; lpos -= _rl_screenwidth; } @@ -584,7 +625,7 @@ rl_redisplay () #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - if (wc_bytes == (size_t)-1 || wc_bytes == (size_t)-2) + if (MB_INVALIDCH (wc_bytes)) { /* Byte sequence is invalid or shortened. Assume that the first byte represents a character. */ @@ -593,12 +634,12 @@ rl_redisplay () wc_width = 1; memset (&ps, 0, sizeof (mbstate_t)); } - else if (wc_bytes == (size_t)0) + else if (MB_NULLWCH (wc_bytes)) break; /* Found '\0' */ else { temp = wcwidth (wc); - wc_width = (temp < 0) ? 1 : temp; + wc_width = (temp >= 0) ? temp : 1; } } #endif @@ -788,7 +829,7 @@ rl_redisplay () #define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) #define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) #define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) -#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? (char*)"" : VIS_CHARS(line) +#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line) #define INV_LINE(line) (invisible_line + inv_lbreaks[line]) /* For each line in the buffer, do the updating display. */ @@ -829,7 +870,7 @@ rl_redisplay () _rl_move_vert (linenum); _rl_move_cursor_relative (0, tt); _rl_clear_to_eol - ((linenum == _rl_vis_botlin) ? (int)strlen (tt) : _rl_screenwidth); + ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth); } } _rl_vis_botlin = inv_botlin; @@ -865,7 +906,7 @@ rl_redisplay () #endif _rl_output_some_chars (local_prompt, nleft); if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - _rl_last_c_pos = _rl_col_width(local_prompt, 0, nleft); + _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft); else _rl_last_c_pos = nleft; } @@ -1067,12 +1108,12 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) memset (&ps, 0, sizeof (mbstate_t)); ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); - if (ret == (size_t)-1 || ret == (size_t)-2) + if (MB_INVALIDCH (ret)) { tempwidth = 1; ret = 1; } - else if (ret == 0) + else if (MB_NULLWCH (ret)) tempwidth = 0; else tempwidth = wcwidth (wc); @@ -1089,7 +1130,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps); if (ret != 0 && bytes != 0) { - if (ret == (size_t)-1 || ret == (size_t)-2) + if (MB_INVALIDCH (ret)) memmove (old+bytes, old+1, strlen (old+1)); else memmove (old+bytes, old+ret, strlen (old+ret)); @@ -1124,18 +1165,37 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - memset (&ps_new, 0, sizeof(mbstate_t)); - memset (&ps_old, 0, sizeof(mbstate_t)); - - new_offset = old_offset = 0; - for (ofd = old, nfd = new; - (ofd - old < omax) && *ofd && - _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) + /* See if the old line is a subset of the new line, so that the + only change is adding characters. */ + temp = (omax < nmax) ? omax : nmax; + if (memcmp (old, new, temp) == 0) { - old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); - new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); - ofd = old + old_offset; - nfd = new + new_offset; + ofd = old + temp; + nfd = new + temp; + } + else + { + memset (&ps_new, 0, sizeof(mbstate_t)); + memset (&ps_old, 0, sizeof(mbstate_t)); + + if (omax == nmax && STREQN (new, old, omax)) + { + ofd = old + omax; + nfd = new + nmax; + } + else + { + new_offset = old_offset = 0; + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && + _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) + { + old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); + new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); + ofd = old + old_offset; + nfd = new + new_offset; + } + } } } else @@ -1167,8 +1227,11 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) memset (&ps_old, 0, sizeof (mbstate_t)); memset (&ps_new, 0, sizeof (mbstate_t)); +#if 0 + /* On advice from jir@yamato.ibm.com */ _rl_adjust_point (old, ols - old, &ps_old); _rl_adjust_point (new, nls - new, &ps_new); +#endif if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0) break; @@ -1322,7 +1385,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) insert_some_chars (nfd, lendiff, col_lendiff); _rl_last_c_pos += col_lendiff; } - else if (*ols == 0) + else if (*ols == 0 && lendiff > 0) { /* At the end of a line the characters do not have to be "inserted". They can just be placed on the screen. */ @@ -1345,10 +1408,14 @@ update_line (old, new, current_line, omax, nmax, inv_botlin) if ((temp - lendiff) > 0) { _rl_output_some_chars (nfd + lendiff, temp - lendiff); -#if 0 - _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff) - col_lendiff; -#else +#if 1 + /* XXX -- this bears closer inspection. Fixes a redisplay bug + reported against bash-3.0-alpha by Andreas Schwab involving + multibyte characters and prompt strings with invisible + characters, but was previously disabled. */ _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); +#else + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff); #endif } } @@ -1424,12 +1491,13 @@ rl_on_new_line () /* Tell the update routines that we have moved onto a new line with the prompt already displayed. Code originally from the version of readline - distributed with CLISP. */ + distributed with CLISP. rl_expand_prompt must have already been called + (explicitly or implicitly). This still doesn't work exactly right. */ int rl_on_new_line_with_prompt () { int prompt_size, i, l, real_screenwidth, newlines; - char *prompt_last_line; + char *prompt_last_line, *lprompt; /* Initialize visible_line and invisible_line to ensure that they can hold the already-displayed prompt. */ @@ -1438,8 +1506,9 @@ rl_on_new_line_with_prompt () /* Make sure the line structures hold the already-displayed prompt for redisplay. */ - strcpy (visible_line, rl_prompt); - strcpy (invisible_line, rl_prompt); + lprompt = local_prompt ? local_prompt : rl_prompt; + strcpy (visible_line, lprompt); + strcpy (invisible_line, lprompt); /* If the prompt contains newlines, take the last tail. */ prompt_last_line = strrchr (rl_prompt, '\n'); @@ -1474,6 +1543,8 @@ rl_on_new_line_with_prompt () vis_lbreaks[newlines] = l; visible_wrap_offset = 0; + rl_display_prompt = rl_prompt; /* XXX - make sure it's set */ + return 0; } @@ -1508,8 +1579,15 @@ _rl_move_cursor_relative (new, data) #if defined (HANDLE_MULTIBYTE) /* If we have multibyte characters, NEW is indexed by the buffer point in a multibyte string, but _rl_last_c_pos is the display position. In - this case, NEW's display position is not obvious. */ - if ((MB_CUR_MAX == 1 || rl_byte_oriented ) && _rl_last_c_pos == new) return; + this case, NEW's display position is not obvious and must be + calculated. */ + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { + if (_rl_last_c_pos == new) + return; + } + else if (_rl_last_c_pos == _rl_col_width (data, 0, new)) + return; #else if (_rl_last_c_pos == new) return; #endif @@ -1592,11 +1670,7 @@ _rl_move_cursor_relative (new, data) #endif { if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) - { - tputs (_rl_term_cr, 1, _rl_output_character_function); - for (i = 0; i < new; i++) - putc (data[i], rl_outstream); - } + _rl_backspace (_rl_last_c_pos - _rl_col_width (data, 0, new)); else _rl_backspace (_rl_last_c_pos - new); } @@ -1734,7 +1808,6 @@ rl_message (va_alist) int rl_message (format, arg1, arg2) char *format; - int arg1, arg2; { sprintf (msg_buf, format, arg1, arg2); msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ @@ -1763,10 +1836,14 @@ rl_reset_line_state () return 0; } +/* These are getting numerous enough that it's time to create a struct. */ + static char *saved_local_prompt; static char *saved_local_prefix; static int saved_last_invisible; static int saved_visible_length; +static int saved_invis_chars_first_line; +static int saved_physical_chars; void rl_save_prompt () @@ -1775,9 +1852,12 @@ rl_save_prompt () saved_local_prefix = local_prompt_prefix; saved_last_invisible = prompt_last_invisible; saved_visible_length = prompt_visible_length; + saved_invis_chars_first_line = prompt_invis_chars_first_line; + saved_physical_chars = prompt_physical_chars; local_prompt = local_prompt_prefix = (char *)0; prompt_last_invisible = prompt_visible_length = 0; + prompt_invis_chars_first_line = prompt_physical_chars = 0; } void @@ -1790,6 +1870,8 @@ rl_restore_prompt () local_prompt_prefix = saved_local_prefix; prompt_last_invisible = saved_last_invisible; prompt_visible_length = saved_visible_length; + prompt_invis_chars_first_line = saved_invis_chars_first_line; + prompt_physical_chars = saved_physical_chars; } char * @@ -1822,6 +1904,7 @@ _rl_make_prompt_for_search (pchar) prompt_last_invisible = saved_last_invisible; prompt_visible_length = saved_visible_length + 1; } + return pmt; } @@ -1997,9 +2080,8 @@ static void redraw_prompt (t) char *t; { - const char *oldp; - char *oldl, *oldlprefix; - int oldlen, oldlast, oldplen, oldninvis; + char *oldp, *oldl, *oldlprefix; + int oldlen, oldlast, oldplen, oldninvis, oldphyschars; /* Geez, I should make this a struct. */ oldp = rl_display_prompt; @@ -2009,11 +2091,13 @@ redraw_prompt (t) oldplen = prompt_prefix_length; oldlast = prompt_last_invisible; oldninvis = prompt_invis_chars_first_line; + oldphyschars = prompt_physical_chars; rl_display_prompt = t; local_prompt = expand_prompt (t, &prompt_visible_length, &prompt_last_invisible, - &prompt_invis_chars_first_line); + &prompt_invis_chars_first_line, + &prompt_physical_chars); local_prompt_prefix = (char *)NULL; rl_forced_update_display (); @@ -2024,6 +2108,7 @@ redraw_prompt (t) prompt_prefix_length = oldplen; prompt_last_invisible = oldlast; prompt_invis_chars_first_line = oldninvis; + prompt_physical_chars = oldphyschars; } /* Redisplay the current line after a SIGWINCH is received. */ @@ -2133,7 +2218,7 @@ _rl_col_width (str, start, end) while (point < start) { tmp = mbrlen (str + point, max, &ps); - if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + if (MB_INVALIDCH ((size_t)tmp)) { /* In this case, the bytes are invalid or too short to compose a multibyte character, so we assume that the first byte represents @@ -2145,8 +2230,8 @@ _rl_col_width (str, start, end) effect of mbstate is undefined. */ memset (&ps, 0, sizeof (mbstate_t)); } - else if (tmp == 0) - break; /* Found '\0' */ + else if (MB_NULLWCH (tmp)) + break; /* Found '\0' */ else { point += tmp; @@ -2162,7 +2247,7 @@ _rl_col_width (str, start, end) while (point < end) { tmp = mbrtowc (&wc, str + point, max, &ps); - if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + if (MB_INVALIDCH ((size_t)tmp)) { /* In this case, the bytes are invalid or too short to compose a multibyte character, so we assume that the first byte represents @@ -2177,8 +2262,8 @@ _rl_col_width (str, start, end) effect of mbstate is undefined. */ memset (&ps, 0, sizeof (mbstate_t)); } - else if (tmp == 0) - break; /* Found '\0' */ + else if (MB_NULLWCH (tmp)) + break; /* Found '\0' */ else { point += tmp; @@ -2193,4 +2278,3 @@ _rl_col_width (str, start, end) return width; } #endif /* HANDLE_MULTIBYTE */ - diff --git a/cmd-line-utils/readline/funmap.c b/cmd-line-utils/readline/funmap.c index 53fd22754ab..d56ffb9fadc 100644 --- a/cmd-line-utils/readline/funmap.c +++ b/cmd-line-utils/readline/funmap.c @@ -129,6 +129,7 @@ static FUNMAP default_funmap[] = { { "tty-status", rl_tty_status }, { "undo", rl_undo_command }, { "universal-argument", rl_universal_argument }, + { "unix-filename-rubout", rl_unix_filename_rubout }, { "unix-line-discard", rl_unix_line_discard }, { "unix-word-rubout", rl_unix_word_rubout }, { "upcase-word", rl_upcase_word }, diff --git a/cmd-line-utils/readline/histexpand.c b/cmd-line-utils/readline/histexpand.c index eed8d5a365e..47f97e9a6f7 100644 --- a/cmd-line-utils/readline/histexpand.c +++ b/cmd-line-utils/readline/histexpand.c @@ -1,6 +1,6 @@ /* histexpand.c -- history expansion. */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1989-2004 Free Software Foundation, Inc. This file contains the GNU History Library (the Library), a set of routines for managing the text of previously typed lines. @@ -50,6 +50,8 @@ #define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" #define HISTORY_QUOTE_CHARACTERS "\"'`" +#define slashify_in_quotes "\\`\"$" + typedef int _hist_search_func_t PARAMS((const char *, int)); extern int rl_byte_oriented; /* declared in mbutil.c */ @@ -63,6 +65,8 @@ static int subst_rhs_len; static char *get_history_word_specifier PARAMS((char *, char *, int *)); static char *history_find_word PARAMS((char *, int)); +static int history_tokenize_word PARAMS((const char *, int)); +static char *history_substring PARAMS((const char *, int, int)); static char *quote_breaks PARAMS((char *)); @@ -83,14 +87,14 @@ char history_comment_char = '\0'; /* The list of characters which inhibit the expansion of text if found immediately following history_expansion_char. */ -const char *history_no_expand_chars = " \t\n\r="; +char *history_no_expand_chars = " \t\n\r="; /* If set to a non-zero value, single quotes inhibit history expansion. The default is 0. */ int history_quotes_inhibit_expansion = 0; /* Used to split words by history_tokenize_internal. */ -const char *history_word_delimiters = HISTORY_WORD_DELIMITERS; +char *history_word_delimiters = HISTORY_WORD_DELIMITERS; /* If set, this points to a function that is called to verify that a particular history expansion should be performed. */ @@ -199,7 +203,7 @@ get_history_event (string, caller_index, delimiting_quote) } /* Only a closing `?' or a newline delimit a substring search string. */ - for (local_index = i; (c = string[i]); i++) + for (local_index = i; c = string[i]; i++) #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { @@ -209,8 +213,8 @@ get_history_event (string, caller_index, delimiting_quote) memset (&ps, 0, sizeof (mbstate_t)); /* These produce warnings because we're passing a const string to a function that takes a non-const string. */ - _rl_adjust_point (string, i, &ps); - if ((v = _rl_get_char_len (string + i, &ps)) > 1) + _rl_adjust_point ((char *)string, i, &ps); + if ((v = _rl_get_char_len ((char *)string + i, &ps)) > 1) { i += v - 1; continue; @@ -515,7 +519,7 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) char *current_line; /* for !# */ { int i, n, starting_index; - int substitute_globally, want_quotes, print_only; + int substitute_globally, subst_bywords, want_quotes, print_only; char *event, *temp, *result, *tstr, *t, c, *word_spec; int result_len; #if defined (HANDLE_MULTIBYTE) @@ -597,19 +601,25 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) FREE (word_spec); /* Perhaps there are other modifiers involved. Do what they say. */ - want_quotes = substitute_globally = print_only = 0; + want_quotes = substitute_globally = subst_bywords = print_only = 0; starting_index = i; while (string[i] == ':') { c = string[i + 1]; - if (c == 'g') + if (c == 'g' || c == 'a') { substitute_globally = 1; i++; c = string[i + 1]; } + else if (c == 'G') + { + subst_bywords = 1; + i++; + c = string[i + 1]; + } switch (c) { @@ -681,7 +691,7 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) case 's': { char *new_event; - int delimiter, failed, si, l_temp; + int delimiter, failed, si, l_temp, ws, we; if (c == 's') { @@ -758,33 +768,67 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line) } /* Find the first occurrence of THIS in TEMP. */ - si = 0; + /* Substitute SUBST_RHS for SUBST_LHS in TEMP. There are three + cases to consider: + + 1. substitute_globally == subst_bywords == 0 + 2. substitute_globally == 1 && subst_bywords == 0 + 3. substitute_globally == 0 && subst_bywords == 1 + + In the first case, we substitute for the first occurrence only. + In the second case, we substitute for every occurrence. + In the third case, we tokenize into words and substitute the + first occurrence of each word. */ + + si = we = 0; for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) - if (STREQN (temp+si, subst_lhs, subst_lhs_len)) - { - int len = subst_rhs_len - subst_lhs_len + l_temp; - new_event = (char *)xmalloc (1 + len); - strncpy (new_event, temp, si); - strncpy (new_event + si, subst_rhs, subst_rhs_len); - strncpy (new_event + si + subst_rhs_len, - temp + si + subst_lhs_len, - l_temp - (si + subst_lhs_len)); - new_event[len] = '\0'; - free (temp); - temp = new_event; - - failed = 0; - - if (substitute_globally) - { - si += subst_rhs_len; - l_temp = strlen (temp); - substitute_globally++; - continue; - } - else - break; - } + { + /* First skip whitespace and find word boundaries if + we're past the end of the word boundary we found + the last time. */ + if (subst_bywords && si > we) + { + for (; temp[si] && whitespace (temp[si]); si++) + ; + ws = si; + we = history_tokenize_word (temp, si); + } + + if (STREQN (temp+si, subst_lhs, subst_lhs_len)) + { + int len = subst_rhs_len - subst_lhs_len + l_temp; + new_event = (char *)xmalloc (1 + len); + strncpy (new_event, temp, si); + strncpy (new_event + si, subst_rhs, subst_rhs_len); + strncpy (new_event + si + subst_rhs_len, + temp + si + subst_lhs_len, + l_temp - (si + subst_lhs_len)); + new_event[len] = '\0'; + free (temp); + temp = new_event; + + failed = 0; + + if (substitute_globally) + { + /* Reported to fix a bug that causes it to skip every + other match when matching a single character. Was + si += subst_rhs_len previously. */ + si += subst_rhs_len - 1; + l_temp = strlen (temp); + substitute_globally++; + continue; + } + else if (subst_bywords) + { + si = we; + l_temp = strlen (temp); + continue; + } + else + break; + } + } if (substitute_globally > 1) { @@ -877,7 +921,7 @@ history_expand (hstring, output) char **output; { register int j; - int i, r, l, passc, cc, modified, eindex, only_printing; + int i, r, l, passc, cc, modified, eindex, only_printing, dquote; char *string; /* The output string, and its length. */ @@ -940,7 +984,7 @@ history_expand (hstring, output) /* `!' followed by one of the characters in history_no_expand_chars is NOT an expansion. */ - for (i = 0; string[i]; i++) + for (i = dquote = 0; string[i]; i++) { #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) @@ -982,9 +1026,19 @@ history_expand (hstring, output) else break; } - /* XXX - at some point, might want to extend this to handle - double quotes as well. */ - else if (history_quotes_inhibit_expansion && string[i] == '\'') + /* Shell-like quoting: allow backslashes to quote double quotes + inside a double-quoted string. */ + else if (dquote && string[i] == '\\' && cc == '"') + i++; + /* More shell-like quoting: if we're paying attention to single + quotes and letting them quote the history expansion character, + then we need to pay attention to double quotes, because single + quotes are not special inside double-quoted strings. */ + else if (history_quotes_inhibit_expansion && string[i] == '"') + { + dquote = 1 - dquote; + } + else if (dquote == 0 && history_quotes_inhibit_expansion && string[i] == '\'') { /* If this is bash, single quotes inhibit history expansion. */ i++; @@ -997,6 +1051,7 @@ history_expand (hstring, output) if (cc == '\'' || cc == history_expansion_char) i++; } + } if (string[i] != history_expansion_char) @@ -1008,7 +1063,7 @@ history_expand (hstring, output) } /* Extract and perform the substitution. */ - for (passc = i = j = 0; i < l; i++) + for (passc = dquote = i = j = 0; i < l; i++) { int tchar = string[i]; @@ -1059,11 +1114,16 @@ history_expand (hstring, output) ADD_CHAR (tchar); break; + case '"': + dquote = 1 - dquote; + ADD_CHAR (tchar); + break; + case '\'': { /* If history_quotes_inhibit_expansion is set, single quotes inhibit history expansion. */ - if (history_quotes_inhibit_expansion) + if (dquote == 0 && history_quotes_inhibit_expansion) { int quote, slen; @@ -1158,7 +1218,9 @@ history_expand (hstring, output) if (only_printing) { +#if 0 add_history (result); +#endif return (2); } @@ -1221,7 +1283,10 @@ get_history_word_specifier (spec, from, caller_index) if (spec[i] == '-') first = 0; else if (spec[i] == '^') - first = 1; + { + first = 1; + i++; + } else if (_rl_digit_p (spec[i]) && expecting_word_spec) { for (first = 0; _rl_digit_p (spec[i]); i++) @@ -1336,7 +1401,103 @@ history_arg_extract (first, last, string) return (result); } -#define slashify_in_quotes "\\`\"$" +static int +history_tokenize_word (string, ind) + const char *string; + int ind; +{ + register int i; + int delimiter; + + i = ind; + delimiter = 0; + + if (member (string[i], "()\n")) + { + i++; + return i; + } + + if (member (string[i], "<>;&|$")) + { + int peek = string[i + 1]; + + if (peek == string[i] && peek != '$') + { + if (peek == '<' && string[i + 2] == '-') + i++; + i += 2; + return i; + } + else + { + if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || + (peek == '>' && string[i] == '&') || + (peek == '(' && (string[i] == '>' || string[i] == '<')) || /* ) */ + (peek == '(' && string[i] == '$')) /* ) */ + { + i += 2; + return i; + } + } + + if (string[i] != '$') + { + i++; + return i; + } + } + + /* Get word from string + i; */ + + if (member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i++]; + + for (; string[i]; i++) + { + if (string[i] == '\\' && string[i + 1] == '\n') + { + i++; + continue; + } + + if (string[i] == '\\' && delimiter != '\'' && + (delimiter != '"' || member (string[i], slashify_in_quotes))) + { + i++; + continue; + } + + if (delimiter && string[i] == delimiter) + { + delimiter = 0; + continue; + } + + if (!delimiter && (member (string[i], history_word_delimiters))) + break; + + if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i]; + } + + return i; +} + +static char * +history_substring (string, start, end) + const char *string; + int start, end; +{ + register int len; + register char *result; + + len = end - start; + result = (char *)xmalloc (len + 1); + strncpy (result, string + start, len); + result[len] = '\0'; + return result; +} /* Parse STRING into tokens and return an array of strings. If WIND is not -1 and INDP is not null, we also want the word surrounding index @@ -1349,7 +1510,6 @@ history_tokenize_internal (string, wind, indp) { char **result; register int i, start, result_index, size; - int len, delimiter; /* If we're searching for a string that's not part of a word (e.g., " "), make sure we set *INDP to a reasonable value. */ @@ -1360,8 +1520,6 @@ history_tokenize_internal (string, wind, indp) exactly where the shell would split them. */ for (i = result_index = size = 0, result = (char **)NULL; string[i]; ) { - delimiter = 0; - /* Skip leading whitespace. */ for (; string[i] && whitespace (string[i]); i++) ; @@ -1369,88 +1527,30 @@ history_tokenize_internal (string, wind, indp) return (result); start = i; - - if (member (string[i], "()\n")) - { - i++; - goto got_token; - } - if (member (string[i], "<>;&|$")) - { - int peek = string[i + 1]; + i = history_tokenize_word (string, start); - if (peek == string[i] && peek != '$') - { - if (peek == '<' && string[i + 2] == '-') - i++; - i += 2; - goto got_token; - } - else - { - if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || - ((peek == '>') && (string[i] == '&')) || - ((peek == '(') && (string[i] == '$'))) - { - i += 2; - goto got_token; - } - } - if (string[i] != '$') - { - i++; - goto got_token; - } - } - - /* Get word from string + i; */ - - if (member (string[i], HISTORY_QUOTE_CHARACTERS)) - delimiter = string[i++]; - - for (; string[i]; i++) + /* If we have a non-whitespace delimiter character (which would not be + skipped by the loop above), use it and any adjacent delimiters to + make a separate field. Any adjacent white space will be skipped the + next time through the loop. */ + if (i == start && history_word_delimiters) { - if (string[i] == '\\' && string[i + 1] == '\n') - { - i++; - continue; - } - - if (string[i] == '\\' && delimiter != '\'' && - (delimiter != '"' || member (string[i], slashify_in_quotes))) - { - i++; - continue; - } - - if (delimiter && string[i] == delimiter) - { - delimiter = 0; - continue; - } - - if (!delimiter && (member (string[i], history_word_delimiters))) - break; - - if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) - delimiter = string[i]; + i++; + while (string[i] && member (string[i], history_word_delimiters)) + i++; } - got_token: - /* If we are looking for the word in which the character at a particular index falls, remember it. */ if (indp && wind != -1 && wind >= start && wind < i) *indp = result_index; - len = i - start; if (result_index + 2 >= size) result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); - result[result_index] = (char *)xmalloc (1 + len); - strncpy (result[result_index], string + start, len); - result[result_index][len] = '\0'; - result[++result_index] = (char *)NULL; + + result[result_index++] = history_substring (string, start, i); + result[result_index] = (char *)NULL; } return (result); diff --git a/cmd-line-utils/readline/histfile.c b/cmd-line-utils/readline/histfile.c index 77f757eac1d..7d340b346d4 100644 --- a/cmd-line-utils/readline/histfile.c +++ b/cmd-line-utils/readline/histfile.c @@ -1,6 +1,6 @@ /* histfile.c - functions to manipulate the history file. */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1989-2003 Free Software Foundation, Inc. This file contains the GNU History Library (the Library), a set of routines for managing the text of previously typed lines. @@ -23,14 +23,19 @@ /* The goal is to make the implementation transparent, so that you don't have to know what data types are used, just what functions you can call. I think I have done that. */ + #define READLINE_LIBRARY +#if defined (__TANDEM) +# include <floss.h> +#endif + #include "config_readline.h" #include <stdio.h> #include <sys/types.h> -#ifndef _MINIX +#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H) # include <sys/file.h> #endif #include "posixstat.h" @@ -50,7 +55,7 @@ # undef HAVE_MMAP #endif -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP # include <sys/mman.h> # ifdef MAP_FILE @@ -65,7 +70,7 @@ # define MAP_FAILED ((void *)-1) # endif -#endif /* HAVE_MMAP */ +#endif /* HISTORY_USE_MMAP */ /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment on win 95/98/nt), we want to open files with O_BINARY mode so that there @@ -91,6 +96,13 @@ extern int errno; #include "rlshell.h" #include "xmalloc.h" +/* If non-zero, we write timestamps to the history file in history_do_write() */ +int history_write_timestamps = 0; + +/* Does S look like the beginning of a history timestamp entry? Placeholder + for more extensive tests. */ +#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char) + /* Return the string that should be used in the place of this filename. This only matters when you don't specify the filename to read_history (), or write_history (). */ @@ -149,13 +161,20 @@ read_history_range (filename, from, to) const char *filename; int from, to; { - register char *line_start, *line_end; - char *input, *buffer, *bufend; + register char *line_start, *line_end, *p; + char *input, *buffer, *bufend, *last_ts; int file, current_line, chars_read; struct stat finfo; size_t file_size; +#if defined (EFBIG) + int overflow_errno = EFBIG; +#elif defined (EOVERFLOW) + int overflow_errno = EOVERFLOW; +#else + int overflow_errno = EIO; +#endif - buffer = (char *)NULL; + buffer = last_ts = (char *)NULL; input = history_filename (filename); file = open (input, O_RDONLY|O_BINARY, 0666); @@ -167,37 +186,42 @@ read_history_range (filename, from, to) /* check for overflow on very large files */ if (file_size != finfo.st_size || file_size + 1 < file_size) { -#if defined (EFBIG) - errno = EFBIG; -#elif defined (EOVERFLOW) - errno = EOVERFLOW; -#endif + errno = overflow_errno; goto error_and_exit; } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP /* We map read/write and private so we can change newlines to NULs without affecting the underlying object. */ buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); if ((void *)buffer == MAP_FAILED) - goto error_and_exit; + { + errno = overflow_errno; + goto error_and_exit; + } chars_read = file_size; #else buffer = (char *)malloc (file_size + 1); if (buffer == 0) - goto error_and_exit; + { + errno = overflow_errno; + goto error_and_exit; + } chars_read = read (file, buffer, file_size); #endif if (chars_read < 0) { error_and_exit: - chars_read = errno; + if (errno != 0) + chars_read = errno; + else + chars_read = EIO; if (file >= 0) close (file); FREE (input); -#ifndef HAVE_MMAP +#ifndef HISTORY_USE_MMAP FREE (buffer); #endif @@ -218,8 +242,12 @@ read_history_range (filename, from, to) for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) if (*line_end == '\n') { - current_line++; - line_start = line_end + 1; + p = line_end + 1; + /* If we see something we think is a timestamp, continue with this + line. We should check more extensively here... */ + if (HIST_TIMESTAMP_START(p) == 0) + current_line++; + line_start = p; } /* If there are lines left to gobble, then gobble them now. */ @@ -229,7 +257,22 @@ read_history_range (filename, from, to) *line_end = '\0'; if (*line_start) - add_history (line_start); + { + if (HIST_TIMESTAMP_START(line_start) == 0) + { + add_history (line_start); + if (last_ts) + { + add_history_time (last_ts); + last_ts = NULL; + } + } + else + { + last_ts = line_start; + current_line--; + } + } current_line++; @@ -240,7 +283,7 @@ read_history_range (filename, from, to) } FREE (input); -#ifndef HAVE_MMAP +#ifndef HISTORY_USE_MMAP FREE (buffer); #else munmap (buffer, file_size); @@ -257,7 +300,7 @@ history_truncate_file (fname, lines) const char *fname; int lines; { - char *buffer, *filename, *bp; + char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */ int file, chars_read, rv; struct stat finfo; size_t file_size; @@ -320,11 +363,14 @@ history_truncate_file (fname, lines) } /* Count backwards from the end of buffer until we have passed - LINES lines. */ - for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) + LINES lines. bp1 is set funny initially. But since bp[1] can't + be a comment character (since it's off the end) and *bp can't be + both a newline and the history comment character, it should be OK. */ + for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) { - if (*bp == '\n') + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) lines--; + bp1 = bp; } /* If this is the first line, then the file contains exactly the @@ -333,11 +379,14 @@ history_truncate_file (fname, lines) the current value of i and 0. Otherwise, write from the start of this line until the end of the buffer. */ for ( ; bp > buffer; bp--) - if (*bp == '\n') - { - bp++; - break; - } + { + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) + { + bp++; + break; + } + bp1 = bp; + } /* Write only if there are more lines in the file than we want to truncate to. */ @@ -372,9 +421,9 @@ history_do_write (filename, nelements, overwrite) register int i; char *output; int file, mode, rv; +#ifdef HISTORY_USE_MMAP size_t cursize; -#ifdef HAVE_MMAP mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; #else mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; @@ -388,7 +437,7 @@ history_do_write (filename, nelements, overwrite) return (errno); } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); #endif @@ -406,10 +455,18 @@ history_do_write (filename, nelements, overwrite) the_history = history_list (); /* Calculate the total number of bytes to write. */ for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) - buffer_size += 1 + strlen (the_history[i]->line); +#if 0 + buffer_size += 2 + HISTENT_BYTES (the_history[i]); +#else + { + if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) + buffer_size += strlen (the_history[i]->timestamp) + 1; + buffer_size += strlen (the_history[i]->line) + 1; + } +#endif /* Allocate the buffer, and fill it. */ -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP if (ftruncate (file, buffer_size+cursize) == -1) goto mmap_error; buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); @@ -434,12 +491,18 @@ mmap_error: for (j = 0, i = history_length - nelements; i < history_length; i++) { + if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) + { + strcpy (buffer + j, the_history[i]->timestamp); + j += strlen (the_history[i]->timestamp); + buffer[j++] = '\n'; + } strcpy (buffer + j, the_history[i]->line); j += strlen (the_history[i]->line); buffer[j++] = '\n'; } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) rv = errno; #else diff --git a/cmd-line-utils/readline/history.c b/cmd-line-utils/readline/history.c index 759ff9e0de9..bb1960d8d99 100644 --- a/cmd-line-utils/readline/history.c +++ b/cmd-line-utils/readline/history.c @@ -1,6 +1,6 @@ -/* History.c -- standalone history library */ +/* history.c -- standalone history library */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1989-2003 Free Software Foundation, Inc. This file contains the GNU History Library (the Library), a set of routines for managing the text of previously typed lines. @@ -50,6 +50,8 @@ /* The number of slots to increase the_history by. */ #define DEFAULT_HISTORY_GROW_SIZE 50 +static char *hist_inittime PARAMS((void)); + /* **************************************************************** */ /* */ /* History Functions */ @@ -121,14 +123,15 @@ using_history () } /* Return the number of bytes that the primary history entries are using. - This just adds up the lengths of the_history->lines. */ + This just adds up the lengths of the_history->lines and the associated + timestamps. */ int history_total_bytes () { register int i, result; for (i = result = 0; the_history && the_history[i]; i++) - result += strlen (the_history[i]->line); + result += HISTENT_BYTES (the_history[i]); return (result); } @@ -204,6 +207,40 @@ history_get (offset) : the_history[local_index]; } +time_t +history_get_time (hist) + HIST_ENTRY *hist; +{ + char *ts; + time_t t; + + if (hist == 0 || hist->timestamp == 0) + return 0; + ts = hist->timestamp; + if (ts[0] != history_comment_char) + return 0; + t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */ + return t; +} + +static char * +hist_inittime () +{ + time_t t; + char ts[64], *ret; + + t = (time_t) time ((time_t *)0); +#if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */ + snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t); +#else + sprintf (ts, "X%lu", (unsigned long) t); +#endif + ret = savestring (ts); + ret[0] = history_comment_char; + + return ret; +} + /* Place STRING at the end of the history list. The data field is set to NULL. */ void @@ -223,10 +260,7 @@ add_history (string) /* If there is something in the slot, then remove it. */ if (the_history[0]) - { - free (the_history[0]->line); - free (the_history[0]); - } + (void) free_history_entry (the_history[0]); /* Copy the rest of the entries, moving down one slot. */ for (i = 0; i < history_length; i++) @@ -258,10 +292,41 @@ add_history (string) temp->line = savestring (string); temp->data = (char *)NULL; + temp->timestamp = hist_inittime (); + the_history[history_length] = (HIST_ENTRY *)NULL; the_history[history_length - 1] = temp; } +/* Change the time stamp of the most recent history entry to STRING. */ +void +add_history_time (string) + const char *string; +{ + HIST_ENTRY *hs; + + hs = the_history[history_length - 1]; + FREE (hs->timestamp); + hs->timestamp = savestring (string); +} + +/* Free HIST and return the data so the calling application can free it + if necessary and desired. */ +histdata_t +free_history_entry (hist) + HIST_ENTRY *hist; +{ + histdata_t x; + + if (hist == 0) + return ((histdata_t) 0); + FREE (hist->line); + FREE (hist->timestamp); + x = hist->data; + free (hist); + return (x); +} + /* Make the history entry at WHICH have LINE and DATA. This returns the old entry so you can dispose of the data. In the case of an invalid WHICH, a NULL pointer is returned. */ @@ -281,6 +346,7 @@ replace_history_entry (which, line, data) temp->line = savestring (line); temp->data = data; + temp->timestamp = savestring (old_value->timestamp); the_history[which] = temp; return (old_value); @@ -325,10 +391,7 @@ stifle_history (max) { /* This loses because we cannot free the data. */ for (i = 0, j = history_length - max; i < j; i++) - { - free (the_history[i]->line); - free (the_history[i]); - } + free_history_entry (the_history[i]); history_base = i; for (j = 0, i = history_length - max; j < max; i++, j++) @@ -370,8 +433,7 @@ clear_history () /* This loses because we cannot free the data. */ for (i = 0; i < history_length; i++) { - free (the_history[i]->line); - free (the_history[i]); + free_history_entry (the_history[i]); the_history[i] = (HIST_ENTRY *)NULL; } diff --git a/cmd-line-utils/readline/history.h b/cmd-line-utils/readline/history.h index afd85104554..14ca2a996c7 100644 --- a/cmd-line-utils/readline/history.h +++ b/cmd-line-utils/readline/history.h @@ -1,5 +1,5 @@ -/* History.h -- the names of functions that you can call in history. */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* history.h -- the names of functions that you can call in history. */ +/* Copyright (C) 1989-2003 Free Software Foundation, Inc. This file contains the GNU History Library (the Library), a set of routines for managing the text of previously typed lines. @@ -26,6 +26,8 @@ extern "C" { #endif +#include <time.h> /* XXX - for history timestamp code */ + #if defined READLINE_LIBRARY # include "rlstdc.h" # include "rltypedefs.h" @@ -43,9 +45,13 @@ typedef char *histdata_t; /* The structure used to store a history entry. */ typedef struct _hist_entry { char *line; + char *timestamp; /* char * rather than time_t for read/write */ histdata_t data; } HIST_ENTRY; +/* Size of the history-library-managed space in history entry HS. */ +#define HISTENT_BYTES(hs) (strlen ((hs)->line) + strlen ((hs)->timestamp)) + /* A structure used to pass the current state of the history stuff around. */ typedef struct _hist_state { HIST_ENTRY **entries; /* Pointer to the entries themselves. */ @@ -76,11 +82,19 @@ extern void history_set_history_state PARAMS((HISTORY_STATE *)); The associated data field (if any) is set to NULL. */ extern void add_history PARAMS((const char *)); +/* Change the timestamp associated with the most recent history entry to + STRING. */ +extern void add_history_time PARAMS((const char *)); + /* A reasonably useless function, only here for completeness. WHICH is the magic number that tells us which element to delete. The elements are numbered from 0. */ extern HIST_ENTRY *remove_history PARAMS((int)); +/* Free the history entry H and return any application-specific data + associated with it. */ +extern histdata_t free_history_entry PARAMS((HIST_ENTRY *)); + /* Make the history entry at WHICH have LINE and DATA. This returns the old entry so you can dispose of the data. In the case of an invalid WHICH, a NULL pointer is returned. */ @@ -119,6 +133,10 @@ extern HIST_ENTRY *current_history PARAMS((void)); array. OFFSET is relative to history_base. */ extern HIST_ENTRY *history_get PARAMS((int)); +/* Return the timestamp associated with the HIST_ENTRY * passed as an + argument */ +extern time_t history_get_time PARAMS((HIST_ENTRY *)); + /* Return the number of bytes that the primary history entries are using. This just adds up the lengths of the_history->lines. */ extern int history_total_bytes PARAMS((void)); @@ -225,12 +243,14 @@ extern int history_length; extern int history_max_entries; extern char history_expansion_char; extern char history_subst_char; -extern const char *history_word_delimiters; +extern char *history_word_delimiters; extern char history_comment_char; -extern const char *history_no_expand_chars; +extern char *history_no_expand_chars; extern char *history_search_delimiter_chars; extern int history_quotes_inhibit_expansion; +extern int history_write_timestamps; + /* Backwards compatibility */ extern int max_input_history; diff --git a/cmd-line-utils/readline/histsearch.c b/cmd-line-utils/readline/histsearch.c index ffc97d720db..778b323afdc 100644 --- a/cmd-line-utils/readline/histsearch.c +++ b/cmd-line-utils/readline/histsearch.c @@ -75,11 +75,11 @@ history_search_internal (string, direction, anchored) if (string == 0 || *string == '\0') return (-1); - if (!history_length || ((i == history_length) && !reverse)) + if (!history_length || ((i >= history_length) && !reverse)) return (-1); - if (reverse && (i == history_length)) - i--; + if (reverse && (i >= history_length)) + i = history_length - 1; #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0) diff --git a/cmd-line-utils/readline/input.c b/cmd-line-utils/readline/input.c index d9c52dfcec8..1981061eac6 100644 --- a/cmd-line-utils/readline/input.c +++ b/cmd-line-utils/readline/input.c @@ -21,6 +21,10 @@ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #define READLINE_LIBRARY +#if defined (__TANDEM) +# include <floss.h> +#endif + #include "config_readline.h" #include <sys/types.h> @@ -152,6 +156,12 @@ _rl_unget_char (key) return (0); } +int +_rl_pushed_input_available () +{ + return (push_index != pop_index); +} + /* If a character is available to be read, then read it and stuff it into IBUFFER. Otherwise, just return. Returns number of characters read (0 if none available) and -1 on error (EIO). */ @@ -160,7 +170,7 @@ rl_gather_tyi () { int tty; register int tem, result; - int chars_avail; + int chars_avail, k; char input; #if defined(HAVE_SELECT) fd_set readfds, exceptfds; @@ -200,6 +210,11 @@ rl_gather_tyi () fcntl (tty, F_SETFL, tem); if (chars_avail == -1 && errno == EAGAIN) return 0; + if (chars_avail == 0) /* EOF */ + { + rl_stuff_char (EOF); + return (0); + } } #endif /* O_NDELAY */ @@ -223,7 +238,12 @@ rl_gather_tyi () if (result != -1) { while (chars_avail--) - rl_stuff_char ((*rl_getc_function) (rl_instream)); + { + k = (*rl_getc_function) (rl_instream); + rl_stuff_char (k); + if (k == NEWLINE || k == RETURN) + break; + } } else { @@ -385,7 +405,7 @@ rl_read_key () else { /* If input is coming from a macro, then use that. */ - if ((c = _rl_next_macro_key ())) + if (c = _rl_next_macro_key ()) return (c); /* If the user has an event function, then call it periodically. */ diff --git a/cmd-line-utils/readline/isearch.c b/cmd-line-utils/readline/isearch.c index 1de16c6a56c..f7b0f1404e9 100644 --- a/cmd-line-utils/readline/isearch.c +++ b/cmd-line-utils/readline/isearch.c @@ -68,7 +68,7 @@ static char *prev_line_found; static char *last_isearch_string; static int last_isearch_string_len; -static const char *default_isearch_terminators = "\033\012"; +static char *default_isearch_terminators = "\033\012"; /* Search backwards through the history looking for a string which is typed interactively. Start with the current line. */ @@ -96,7 +96,7 @@ rl_forward_search_history (sign, key) static void rl_display_search (search_string, reverse_p, where) char *search_string; - int reverse_p, where __attribute__((unused)); + int reverse_p, where; { char *message; int msglen, searchlen; @@ -144,7 +144,7 @@ rl_display_search (search_string, reverse_p, where) backwards. */ static int rl_search_history (direction, invoking_key) - int direction, invoking_key __attribute__((unused)); + int direction, invoking_key; { /* The string that the user types in to search for. */ char *search_string; @@ -184,7 +184,7 @@ rl_search_history (direction, invoking_key) /* The list of characters which terminate the search, but are not subsequently executed. If the variable isearch-terminators has been set, we use that value, otherwise we use ESC and C-J. */ - const char *isearch_terminators; + char *isearch_terminators; RL_SETSTATE(RL_STATE_ISEARCH); orig_point = rl_point; diff --git a/cmd-line-utils/readline/keymaps.c b/cmd-line-utils/readline/keymaps.c index 9972d83e4f1..2be03f7086f 100644 --- a/cmd-line-utils/readline/keymaps.c +++ b/cmd-line-utils/readline/keymaps.c @@ -62,11 +62,13 @@ rl_make_bare_keymap () keymap[i].function = (rl_command_func_t *)NULL; } +#if 0 for (i = 'A'; i < ('Z' + 1); i++) { keymap[i].type = ISFUNC; keymap[i].function = rl_do_lowercase_version; } +#endif return (keymap); } @@ -77,8 +79,9 @@ rl_copy_keymap (map) Keymap map; { register int i; - Keymap temp = rl_make_bare_keymap (); + Keymap temp; + temp = rl_make_bare_keymap (); for (i = 0; i < KEYMAP_SIZE; i++) { temp[i].type = map[i].type; @@ -107,12 +110,8 @@ rl_make_keymap () newmap[CTRL('H')].function = rl_rubout; #if KEYMAP_SIZE > 128 - /* Printing characters in some 8-bit character sets. */ - for (i = 128; i < 160; i++) - newmap[i].function = rl_insert; - - /* ISO Latin-1 printing characters should self-insert. */ - for (i = 160; i < 256; i++) + /* Printing characters in ISO Latin-1 and some 8-bit character sets. */ + for (i = 128; i < 256; i++) newmap[i].function = rl_insert; #endif /* KEYMAP_SIZE > 128 */ diff --git a/cmd-line-utils/readline/kill.c b/cmd-line-utils/readline/kill.c index 32a661f076f..061bdafcf9a 100644 --- a/cmd-line-utils/readline/kill.c +++ b/cmd-line-utils/readline/kill.c @@ -77,7 +77,7 @@ static int rl_yank_nth_arg_internal PARAMS((int, int, int)); of kill material. */ int rl_set_retained_kills (num) - int num __attribute__((unused)); + int num; { return 0; } @@ -294,7 +294,7 @@ rl_backward_kill_line (direction, ignore) /* Kill the whole line, no matter where point is. */ int rl_kill_full_line (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { rl_begin_undo_group (); rl_point = 0; @@ -312,7 +312,7 @@ rl_kill_full_line (count, ignore) using behaviour that they expect. */ int rl_unix_word_rubout (count, key) - int count, key __attribute__((unused)); + int count, key; { int orig_point; @@ -337,6 +337,47 @@ rl_unix_word_rubout (count, key) if (rl_editing_mode == emacs_mode) rl_mark = rl_point; } + + return 0; +} + +/* This deletes one filename component in a Unix pathname. That is, it + deletes backward to directory separator (`/') or whitespace. */ +int +rl_unix_filename_rubout (count, key) + int count, key; +{ + int orig_point, c; + + if (rl_point == 0) + rl_ding (); + else + { + orig_point = rl_point; + if (count <= 0) + count = 1; + + while (count--) + { + c = rl_line_buffer[rl_point - 1]; + while (rl_point && (whitespace (c) || c == '/')) + { + rl_point--; + c = rl_line_buffer[rl_point - 1]; + } + + while (rl_point && (whitespace (c) == 0) && c != '/') + { + rl_point--; + c = rl_line_buffer[rl_point - 1]; + } + } + + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; } @@ -348,7 +389,7 @@ rl_unix_word_rubout (count, key) doing. */ int rl_unix_line_discard (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (rl_point == 0) rl_ding (); @@ -385,7 +426,7 @@ region_kill_internal (delete) /* Copy the text in the region to the kill ring. */ int rl_copy_region_to_kill (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { return (region_kill_internal (0)); } @@ -393,7 +434,7 @@ rl_copy_region_to_kill (count, ignore) /* Kill the text between the point and mark. */ int rl_kill_region (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { int r, npoint; @@ -458,7 +499,7 @@ rl_copy_backward_word (count, key) /* Yank back the last killed text. This ignores arguments. */ int rl_yank (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { if (rl_kill_ring == 0) { @@ -477,7 +518,7 @@ rl_yank (count, ignore) yank back some other text. */ int rl_yank_pop (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int l, n; diff --git a/cmd-line-utils/readline/macro.c b/cmd-line-utils/readline/macro.c index 7f5c39f7d86..f7b77a831b8 100644 --- a/cmd-line-utils/readline/macro.c +++ b/cmd-line-utils/readline/macro.c @@ -190,7 +190,7 @@ _rl_kill_kbd_macro () re-executing the existing macro. */ int rl_start_kbd_macro (ignore1, ignore2) - int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); + int ignore1, ignore2; { if (RL_ISSTATE (RL_STATE_MACRODEF)) { @@ -215,7 +215,7 @@ rl_start_kbd_macro (ignore1, ignore2) that many times, counting the definition as the first time. */ int rl_end_kbd_macro (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { if (RL_ISSTATE (RL_STATE_MACRODEF) == 0) { @@ -235,7 +235,7 @@ rl_end_kbd_macro (count, ignore) COUNT says how many times to execute it. */ int rl_call_last_kbd_macro (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { if (current_macro == 0) _rl_abort_internal (); diff --git a/cmd-line-utils/readline/mbutil.c b/cmd-line-utils/readline/mbutil.c index 3113b7b0538..c88e9485f39 100644 --- a/cmd-line-utils/readline/mbutil.c +++ b/cmd-line-utils/readline/mbutil.c @@ -1,6 +1,6 @@ /* mbutil.c -- readline multibyte character utility functions */ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -90,12 +90,12 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero) /* if this is true, means that seed was not pointed character started byte. So correct the point and consume count */ if (seed < point) - count --; + count--; while (count > 0) { tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps); - if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + if (MB_INVALIDCH ((size_t)tmp)) { /* invalid bytes. asume a byte represents a character */ point++; @@ -103,9 +103,8 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero) /* reset states. */ memset(&ps, 0, sizeof(mbstate_t)); } - else if (tmp == (size_t)0) - /* found '\0' char */ - break; + else if (MB_NULLWCH (tmp)) + break; /* found wide '\0' */ else { /* valid bytes */ @@ -158,7 +157,7 @@ _rl_find_prev_mbchar_internal (string, seed, find_non_zero) while (point < seed) { tmp = mbrtowc (&wc, string + point, length - point, &ps); - if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + if (MB_INVALIDCH ((size_t)tmp)) { /* in this case, bytes are invalid or shorted to compose multibyte char, so assume that the first byte represents @@ -167,8 +166,12 @@ _rl_find_prev_mbchar_internal (string, seed, find_non_zero) /* clear the state of the byte sequence, because in this case effect of mbstate is undefined */ memset(&ps, 0, sizeof (mbstate_t)); + + /* Since we're assuming that this byte represents a single + non-zero-width character, don't forget about it. */ + prev = point; } - else if (tmp == 0) + else if (MB_NULLWCH (tmp)) break; /* Found '\0' char. Can this happen? */ else { @@ -194,7 +197,7 @@ _rl_find_prev_mbchar_internal (string, seed, find_non_zero) if it couldn't parse a complete multibyte character. */ int _rl_get_char_len (src, ps) - const char *src; + char *src; mbstate_t *ps; { size_t tmp; @@ -203,14 +206,16 @@ _rl_get_char_len (src, ps) if (tmp == (size_t)(-2)) { /* shorted to compose multibyte char */ - memset (ps, 0, sizeof(mbstate_t)); + if (ps) + memset (ps, 0, sizeof(mbstate_t)); return -2; } else if (tmp == (size_t)(-1)) { /* invalid to compose multibyte char */ /* initialize the conversion state */ - memset (ps, 0, sizeof(mbstate_t)); + if (ps) + memset (ps, 0, sizeof(mbstate_t)); return -1; } else if (tmp == (size_t)0) @@ -223,9 +228,12 @@ _rl_get_char_len (src, ps) return 1. Otherwise return 0. */ int _rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) - char *buf1, *buf2; - mbstate_t *ps1, *ps2; - int pos1, pos2; + char *buf1; + int pos1; + mbstate_t *ps1; + char *buf2; + int pos2; + mbstate_t *ps2; { int i, w1, w2; @@ -249,7 +257,7 @@ _rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) it returns -1 */ int _rl_adjust_point(string, point, ps) - const char *string; + char *string; int point; mbstate_t *ps; { @@ -266,7 +274,7 @@ _rl_adjust_point(string, point, ps) while (pos < point) { tmp = mbrlen (string + pos, length - pos, ps); - if((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + if (MB_INVALIDCH ((size_t)tmp)) { /* in this case, bytes are invalid or shorted to compose multibyte char, so assume that the first byte represents @@ -274,8 +282,11 @@ _rl_adjust_point(string, point, ps) pos++; /* clear the state of the byte sequence, because in this case effect of mbstate is undefined */ - memset (ps, 0, sizeof (mbstate_t)); + if (ps) + memset (ps, 0, sizeof (mbstate_t)); } + else if (MB_NULLWCH (tmp)) + pos++; else pos += tmp; } @@ -308,8 +319,8 @@ _rl_is_mbchar_matched (string, seed, end, mbchar, length) #undef _rl_find_next_mbchar int _rl_find_next_mbchar (string, seed, count, flags) - char *string __attribute__((unused)); - int seed, count, flags __attribute__((unused)); + char *string; + int seed, count, flags; { #if defined (HANDLE_MULTIBYTE) return _rl_find_next_mbchar_internal (string, seed, count, flags); @@ -324,8 +335,8 @@ _rl_find_next_mbchar (string, seed, count, flags) #undef _rl_find_prev_mbchar int _rl_find_prev_mbchar (string, seed, flags) - char *string __attribute__((unused)); - int seed, flags __attribute__((unused)); + char *string; + int seed, flags; { #if defined (HANDLE_MULTIBYTE) return _rl_find_prev_mbchar_internal (string, seed, flags); diff --git a/cmd-line-utils/readline/misc.c b/cmd-line-utils/readline/misc.c index 858d09dbe90..810b940edab 100644 --- a/cmd-line-utils/readline/misc.c +++ b/cmd-line-utils/readline/misc.c @@ -1,6 +1,6 @@ /* misc.c -- miscellaneous bindable readline functions. */ -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -155,7 +155,7 @@ rl_digit_loop () /* Add the current digit to the argument in progress. */ int rl_digit_argument (ignore, key) - int ignore __attribute__((unused)), key; + int ignore, key; { rl_execute_next (key); return (rl_digit_loop ()); @@ -185,7 +185,7 @@ _rl_init_argument () dispatch on it. If the key is the abort character then abort. */ int rl_universal_argument (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_numeric_arg *= 4; return (rl_digit_loop ()); @@ -251,6 +251,8 @@ rl_maybe_unsave_line () { if (_rl_saved_line_for_history) { + /* Can't call with `1' because rl_undo_list might point to an undo + list from a history entry, as in rl_replace_from_history() below. */ rl_replace_line (_rl_saved_line_for_history->line, 0); rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; _rl_free_history_entry (_rl_saved_line_for_history); @@ -272,6 +274,13 @@ rl_maybe_save_line () _rl_saved_line_for_history->line = savestring (rl_line_buffer); _rl_saved_line_for_history->data = (char *)rl_undo_list; } + else if (STREQ (rl_line_buffer, _rl_saved_line_for_history->line) == 0) + { + free (_rl_saved_line_for_history->line); + _rl_saved_line_for_history->line = savestring (rl_line_buffer); + _rl_saved_line_for_history->data = (char *)rl_undo_list; /* XXX possible memleak */ + } + return 0; } @@ -296,7 +305,7 @@ _rl_history_set_point () rl_point = rl_end; #if defined (VI_MODE) - if (rl_editing_mode == vi_mode) + if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) rl_point = 0; #endif /* VI_MODE */ @@ -307,8 +316,10 @@ _rl_history_set_point () void rl_replace_from_history (entry, flags) HIST_ENTRY *entry; - int flags __attribute__((unused)); /* currently unused */ + int flags; /* currently unused */ { + /* Can't call with `1' because rl_undo_list might point to an undo list + from a history entry, just like we're setting up here. */ rl_replace_line (entry->line, 0); rl_undo_list = (UNDO_LIST *)entry->data; rl_point = rl_end; @@ -332,7 +343,7 @@ rl_replace_from_history (entry, flags) /* Meta-< goes to the start of the history. */ int rl_beginning_of_history (count, key) - int count __attribute__((unused)), key; + int count, key; { return (rl_get_previous_history (1 + where_history (), key)); } @@ -340,7 +351,7 @@ rl_beginning_of_history (count, key) /* Meta-> goes to the end of the history. (The current line). */ int rl_end_of_history (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_maybe_replace_line (); using_history (); @@ -433,6 +444,7 @@ rl_get_previous_history (count, key) rl_replace_from_history (temp, 0); _rl_history_set_point (); } + return 0; } @@ -444,7 +456,7 @@ rl_get_previous_history (count, key) /* How to toggle back and forth between editing modes. */ int rl_vi_editing_mode (count, key) - int count __attribute__((unused)), key; + int count, key; { #if defined (VI_MODE) _rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */ @@ -457,7 +469,7 @@ rl_vi_editing_mode (count, key) int rl_emacs_editing_mode (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_editing_mode = emacs_mode; _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */ @@ -468,7 +480,7 @@ rl_emacs_editing_mode (count, key) /* Function for the rest of the library to use to set insert/overwrite mode. */ void _rl_set_insert_mode (im, force) - int im, force __attribute__((unused)); + int im, force; { #ifdef CURSOR_MODE _rl_set_cursor (im, force); @@ -481,7 +493,7 @@ _rl_set_insert_mode (im, force) mode. A negative or zero explicit argument selects insert mode. */ int rl_overwrite_mode (count, key) - int count, key __attribute__((unused)); + int count, key; { if (rl_explicit_arg == 0) _rl_set_insert_mode (rl_insert_mode ^ 1, 0); diff --git a/cmd-line-utils/readline/nls.c b/cmd-line-utils/readline/nls.c index 6555c50c22b..4f28152f316 100644 --- a/cmd-line-utils/readline/nls.c +++ b/cmd-line-utils/readline/nls.c @@ -73,6 +73,23 @@ static char *normalize_codeset PARAMS((char *)); static char *find_codeset PARAMS((char *, size_t *)); #endif /* !HAVE_SETLOCALE */ +static char *_rl_get_locale_var PARAMS((const char *)); + +static char * +_rl_get_locale_var (v) + const char *v; +{ + char *lspec; + + lspec = sh_get_env_value ("LC_ALL"); + if (lspec == 0 || *lspec == 0) + lspec = sh_get_env_value (v); + if (lspec == 0 || *lspec == 0) + lspec = sh_get_env_value ("LANG"); + + return lspec; +} + /* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value to decide the defaults for 8-bit character input and output. Returns 1 if we set eight-bit mode. */ @@ -82,10 +99,21 @@ _rl_init_eightbit () /* If we have setlocale(3), just check the current LC_CTYPE category value, and go into eight-bit mode if it's not C or POSIX. */ #if defined (HAVE_SETLOCALE) - char *t; + char *lspec, *t; /* Set the LC_CTYPE locale category from environment variables. */ - t = setlocale (LC_CTYPE, ""); + lspec = _rl_get_locale_var ("LC_CTYPE"); + /* Since _rl_get_locale_var queries the right environment variables, + we query the current locale settings with setlocale(), and, if + that doesn't return anything, we set lspec to the empty string to + force the subsequent call to setlocale() to define the `native' + environment. */ + if (lspec == 0 || *lspec == 0) + lspec = setlocale (LC_CTYPE, (char *)NULL); + if (lspec == 0) + lspec = ""; + t = setlocale (LC_CTYPE, lspec); + if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0)) { _rl_meta_flag = 1; @@ -103,9 +131,8 @@ _rl_init_eightbit () /* We don't have setlocale. Finesse it. Check the environment for the appropriate variables and set eight-bit mode if they have the right values. */ - lspec = sh_get_env_value ("LC_ALL"); - if (lspec == 0) lspec = sh_get_env_value ("LC_CTYPE"); - if (lspec == 0) lspec = sh_get_env_value ("LANG"); + lspec = _rl_get_locale_var ("LC_CTYPE"); + if (lspec == 0 || (t = normalize_codeset (lspec)) == 0) return (0); for (i = 0; t && legal_lang_values[i]; i++) diff --git a/cmd-line-utils/readline/parens.c b/cmd-line-utils/readline/parens.c index 5d4a08a0ce8..bb893ac1bfb 100644 --- a/cmd-line-utils/readline/parens.c +++ b/cmd-line-utils/readline/parens.c @@ -21,6 +21,10 @@ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #define READLINE_LIBRARY +#if defined (__TANDEM) +# include <floss.h> +#endif + #include "rlconf.h" #include "config_readline.h" diff --git a/cmd-line-utils/readline/posixdir.h b/cmd-line-utils/readline/posixdir.h index 505e27954f1..91f6d96111d 100644 --- a/cmd-line-utils/readline/posixdir.h +++ b/cmd-line-utils/readline/posixdir.h @@ -25,7 +25,11 @@ #if defined (HAVE_DIRENT_H) # include <dirent.h> -# define D_NAMLEN(d) (strlen ((d)->d_name)) +# if defined (HAVE_STRUCT_DIRENT_D_NAMLEN) +# define D_NAMLEN(d) ((d)->d_namlen) +# else +# define D_NAMLEN(d) (strlen ((d)->d_name)) +# endif /* !HAVE_STRUCT_DIRENT_D_NAMLEN */ #else # if defined (HAVE_SYS_NDIR_H) # include <sys/ndir.h> @@ -42,11 +46,11 @@ # define D_NAMLEN(d) ((d)->d_namlen) #endif /* !HAVE_DIRENT_H */ -#if defined (STRUCT_DIRENT_HAS_D_INO) && !defined (STRUCT_DIRENT_HAS_D_FILENO) +#if defined (HAVE_STRUCT_DIRENT_D_INO) && !defined (HAVE_STRUCT_DIRENT_D_FILENO) # define d_fileno d_ino #endif -#if defined (_POSIX_SOURCE) && (!defined (STRUCT_DIRENT_HAS_D_INO) || defined (BROKEN_DIRENT_D_INO)) +#if defined (_POSIX_SOURCE) && (!defined (HAVE_STRUCT_DIRENT_D_INO) || defined (BROKEN_DIRENT_D_INO)) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ # define REAL_DIR_ENTRY(dp) 1 diff --git a/cmd-line-utils/readline/readline.c b/cmd-line-utils/readline/readline.c index 2c0bb499b7b..e82db84c9dc 100644 --- a/cmd-line-utils/readline/readline.c +++ b/cmd-line-utils/readline/readline.c @@ -66,11 +66,11 @@ #include "xmalloc.h" #ifndef RL_LIBRARY_VERSION -# define RL_LIBRARY_VERSION "4.3" +# define RL_LIBRARY_VERSION "5.0" #endif #ifndef RL_READLINE_VERSION -# define RL_READLINE_VERSION 0x0403 +# define RL_READLINE_VERSION 0x0500 #endif extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); @@ -83,6 +83,7 @@ static void bind_arrow_keys_internal PARAMS((Keymap)); static void bind_arrow_keys PARAMS((void)); static void readline_default_bindings PARAMS((void)); +static void reset_default_bindings PARAMS((void)); /* **************************************************************** */ /* */ @@ -345,7 +346,7 @@ readline_internal_setup () #if defined (VI_MODE) if (rl_editing_mode == vi_mode) - rl_vi_insertion_mode (1, 0); + rl_vi_insertion_mode (1, 'i'); #endif /* VI_MODE */ if (rl_pre_input_hook) @@ -648,7 +649,21 @@ _rl_dispatch_subseq (key, map, got_subseq) the function. The recursive call to _rl_dispatch_subseq has already taken care of pushing any necessary input back onto the input queue with _rl_unget_char. */ - r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); + { +#if 0 + r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); +#else + /* XXX - experimental code -- might never be executed. Save + for later. */ + Keymap m = FUNCTION_TO_KEYMAP (map, key); + int type = m[ANYOTHERKEY].type; + func = m[ANYOTHERKEY].function; + if (type == ISFUNC && func == rl_do_lowercase_version) + r = _rl_dispatch (_rl_to_lower (key), map); + else + r = _rl_dispatch (ANYOTHERKEY, m); +#endif + } else if (r && map[ANYOTHERKEY].function) { /* We didn't match (r is probably -1), so return something to @@ -682,6 +697,7 @@ _rl_dispatch_subseq (key, map, got_subseq) } #if defined (VI_MODE) if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && + key != ANYOTHERKEY && _rl_vi_textmod_command (key)) _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); #endif @@ -836,7 +852,7 @@ readline_initialize_everything () /* If the completion parser's default word break characters haven't been set yet, then do so now. */ if (rl_completer_word_break_characters == (char *)NULL) - rl_completer_word_break_characters = rl_basic_word_break_characters; + rl_completer_word_break_characters = (char *)rl_basic_word_break_characters; } /* If this system allows us to look at the values of the regular @@ -848,6 +864,15 @@ readline_default_bindings () rl_tty_set_default_bindings (_rl_keymap); } +/* Reset the default bindings for the terminal special characters we're + interested in back to rl_insert and read the new ones. */ +static void +reset_default_bindings () +{ + rl_tty_unset_default_bindings (_rl_keymap); + rl_tty_set_default_bindings (_rl_keymap); +} + /* Bind some common arrow key sequences in MAP. */ static void bind_arrow_keys_internal (map) @@ -859,25 +884,25 @@ bind_arrow_keys_internal (map) _rl_keymap = map; #if defined (__MSDOS__) - _rl_bind_if_unbound ("\033[0A", rl_get_previous_history); - _rl_bind_if_unbound ("\033[0B", rl_backward_char); - _rl_bind_if_unbound ("\033[0C", rl_forward_char); - _rl_bind_if_unbound ("\033[0D", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033[0A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[0B", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[0C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[0D", rl_get_next_history); #endif - _rl_bind_if_unbound ("\033[A", rl_get_previous_history); - _rl_bind_if_unbound ("\033[B", rl_get_next_history); - _rl_bind_if_unbound ("\033[C", rl_forward_char); - _rl_bind_if_unbound ("\033[D", rl_backward_char); - _rl_bind_if_unbound ("\033[H", rl_beg_of_line); - _rl_bind_if_unbound ("\033[F", rl_end_of_line); - - _rl_bind_if_unbound ("\033OA", rl_get_previous_history); - _rl_bind_if_unbound ("\033OB", rl_get_next_history); - _rl_bind_if_unbound ("\033OC", rl_forward_char); - _rl_bind_if_unbound ("\033OD", rl_backward_char); - _rl_bind_if_unbound ("\033OH", rl_beg_of_line); - _rl_bind_if_unbound ("\033OF", rl_end_of_line); + rl_bind_keyseq_if_unbound ("\033[A", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033[B", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033[C", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033[D", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033[H", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033[F", rl_end_of_line); + + rl_bind_keyseq_if_unbound ("\033OA", rl_get_previous_history); + rl_bind_keyseq_if_unbound ("\033OB", rl_get_next_history); + rl_bind_keyseq_if_unbound ("\033OC", rl_forward_char); + rl_bind_keyseq_if_unbound ("\033OD", rl_backward_char); + rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line); + rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line); _rl_keymap = xkeymap; } diff --git a/cmd-line-utils/readline/readline.h b/cmd-line-utils/readline/readline.h index 9425de50aef..222b317c4a8 100644 --- a/cmd-line-utils/readline/readline.h +++ b/cmd-line-utils/readline/readline.h @@ -1,6 +1,6 @@ /* Readline.h -- the names of functions callable from within readline. */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -40,9 +40,9 @@ extern "C" { #endif /* Hex-encoded Readline version number. */ -#define RL_READLINE_VERSION 0x0403 /* Readline 4.3 */ -#define RL_VERSION_MAJOR 4 -#define RL_VERSION_MINOR 3 +#define RL_READLINE_VERSION 0x0500 /* Readline 5.0 */ +#define RL_VERSION_MAJOR 5 +#define RL_VERSION_MINOR 0 /* Readline data structures. */ @@ -160,6 +160,7 @@ extern int rl_kill_line PARAMS((int, int)); extern int rl_backward_kill_line PARAMS((int, int)); extern int rl_kill_full_line PARAMS((int, int)); extern int rl_unix_word_rubout PARAMS((int, int)); +extern int rl_unix_filename_rubout PARAMS((int, int)); extern int rl_unix_line_discard PARAMS((int, int)); extern int rl_copy_region_to_kill PARAMS((int, int)); extern int rl_kill_region PARAMS((int, int)); @@ -258,6 +259,8 @@ extern int rl_vi_check PARAMS((void)); extern int rl_vi_domove PARAMS((int, int *)); extern int rl_vi_bracktype PARAMS((int)); +extern void rl_vi_start_inserting PARAMS((int, int, int)); + /* VI-mode pseudo-bindable commands, used as utility functions. */ extern int rl_vi_fWord PARAMS((int, int)); extern int rl_vi_bWord PARAMS((int, int)); @@ -290,12 +293,20 @@ extern int rl_bind_key PARAMS((int, rl_command_func_t *)); extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap)); extern int rl_unbind_key PARAMS((int)); extern int rl_unbind_key_in_map PARAMS((int, Keymap)); +extern int rl_bind_key_if_unbound PARAMS((int, rl_command_func_t *)); +extern int rl_bind_key_if_unbound_in_map PARAMS((int, rl_command_func_t *, Keymap)); extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap)); extern int rl_unbind_command_in_map PARAMS((const char *, Keymap)); -extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap)); +extern int rl_bind_keyseq PARAMS((const char *, rl_command_func_t *)); +extern int rl_bind_keyseq_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); +extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *)); +extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap)); extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap)); extern int rl_variable_bind PARAMS((const char *, const char *)); +/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */ +extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap)); + /* Backwards compatibility, use rl_generic_bind instead. */ extern int rl_macro_bind PARAMS((const char *, const char *, Keymap)); @@ -329,7 +340,7 @@ extern void rl_set_keymap PARAMS((Keymap)); extern Keymap rl_get_keymap PARAMS((void)); /* Undocumented; used internally only. */ extern void rl_set_keymap_from_edit_mode PARAMS((void)); -extern const char *rl_get_keymap_name_from_edit_mode PARAMS((void)); +extern char *rl_get_keymap_name_from_edit_mode PARAMS((void)); /* Functions for manipulating the funmap, which maps command names to functions. */ extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *)); @@ -358,7 +369,7 @@ extern int rl_clear_message PARAMS((void)); extern int rl_reset_line_state PARAMS((void)); extern int rl_crlf PARAMS((void)); -#if (defined (__STDC__) || defined (__cplusplus)) && defined (USE_VARARGS) && defined (PREFER_STDARG) +#if defined (USE_VARARGS) && defined (PREFER_STDARG) extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); #else extern int rl_message (); @@ -384,13 +395,14 @@ extern char *rl_copy_text PARAMS((int, int)); extern void rl_prep_terminal PARAMS((int)); extern void rl_deprep_terminal PARAMS((void)); extern void rl_tty_set_default_bindings PARAMS((Keymap)); +extern void rl_tty_unset_default_bindings PARAMS((Keymap)); extern int rl_reset_terminal PARAMS((const char *)); extern void rl_resize_terminal PARAMS((void)); extern void rl_set_screen_size PARAMS((int, int)); extern void rl_get_screen_size PARAMS((int *, int *)); -extern const char *rl_get_termcap PARAMS((const char *)); +extern char *rl_get_termcap PARAMS((const char *)); /* Functions for character input. */ extern int rl_stuff_char PARAMS((int)); @@ -603,7 +615,12 @@ extern const char *rl_basic_word_break_characters; /* The list of characters that signal a break between words for rl_complete_internal. The default list is the contents of rl_basic_word_break_characters. */ -extern const char *rl_completer_word_break_characters; +extern /*const*/ char *rl_completer_word_break_characters; + +/* Hook function to allow an application to set the completion word + break characters before readline breaks up the line. Allows + position-dependent word break characters. */ +extern rl_cpvfunc_t *rl_completion_word_break_hook; /* List of characters which can be used to quote a substring of the line. Completion occurs on the entire substring, and within the substring @@ -687,6 +704,11 @@ extern int rl_attempted_completion_over; functions. */ extern int rl_completion_type; +/* Up to this many items will be displayed in response to a + possible-completions call. After that, we ask the user if she + is sure she wants to see them all. The default value is 100. */ +extern int rl_completion_query_items; + /* Character appended to completed words when at the end of the line. The default is a space. Nothing is added if this is '\0'. */ extern int rl_completion_append_character; @@ -695,10 +717,18 @@ extern int rl_completion_append_character; rl_completion_append_character will not be appended. */ extern int rl_completion_suppress_append; -/* Up to this many items will be displayed in response to a - possible-completions call. After that, we ask the user if she - is sure she wants to see them all. The default value is 100. */ -extern int rl_completion_query_items; +/* Set to any quote character readline thinks it finds before any application + completion function is called. */ +extern int rl_completion_quote_character; + +/* Set to a non-zero value if readline found quoting anywhere in the word to + be completed; set before any application completion function is called. */ +extern int rl_completion_found_quote; + +/* If non-zero, the completion functions don't append any closing quote. + This is set to 0 by rl_complete_internal and may be changed by an + application-specific completion function. */ +extern int rl_completion_suppress_quote; /* If non-zero, a slash will be appended to completed filenames that are symbolic links to directory names, subject to the value of the @@ -749,6 +779,7 @@ extern int rl_inhibit_completion; #define RL_STATE_SIGHANDLER 0x08000 /* in readline sighandler */ #define RL_STATE_UNDOING 0x10000 /* doing an undo */ #define RL_STATE_INPUTPENDING 0x20000 /* rl_execute_next called */ +#define RL_STATE_TTYCSAVED 0x40000 /* tty special chars saved */ #define RL_STATE_DONE 0x80000 /* done; accepted line */ @@ -785,6 +816,12 @@ struct readline_state { int catchsigs; int catchsigwinch; + /* search state */ + + /* completion state */ + + /* options state */ + /* reserved for future expansion, so the struct size doesn't change */ char reserved[64]; }; diff --git a/cmd-line-utils/readline/rldefs.h b/cmd-line-utils/readline/rldefs.h index 5cba9a5ac32..0d600407b5f 100644 --- a/cmd-line-utils/readline/rldefs.h +++ b/cmd-line-utils/readline/rldefs.h @@ -32,10 +32,6 @@ #include "rlstdc.h" -#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ <8) -#define __attribute__(A) -#endif - #if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING) # define TERMIOS_TTY_DRIVER #else @@ -81,7 +77,7 @@ extern int _rl_stricmp PARAMS((char *, char *)); extern int _rl_strnicmp PARAMS((char *, char *, int)); #endif -#if defined (HAVE_STRPBRK) +#if defined (HAVE_STRPBRK) && !defined (HAVE_MULTIBYTE) # define _rl_strpbrk(a,b) strpbrk((a),(b)) #else extern char *_rl_strpbrk PARAMS((const char *, const char *)); diff --git a/cmd-line-utils/readline/rlmbutil.h b/cmd-line-utils/readline/rlmbutil.h index 4660a72fce5..77cc026e3e8 100644 --- a/cmd-line-utils/readline/rlmbutil.h +++ b/cmd-line-utils/readline/rlmbutil.h @@ -35,11 +35,18 @@ #if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) # include <wchar.h> # include <wctype.h> -# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */ +# if defined (HAVE_MBSRTOWCS) && defined (HAVE_MBRTOWC) && defined (HAVE_MBRLEN) && defined (HAVE_WCWIDTH) + /* system is supposed to support XPG5 */ # define HANDLE_MULTIBYTE 1 # endif #endif +/* If we don't want multibyte chars even on a system that supports them, let + the configuring user turn multibyte support off. */ +#if defined (NO_MULTIBYTE_SUPPORT) +# undef HANDLE_MULTIBYTE +#endif + /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ #if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) # define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) @@ -82,14 +89,17 @@ extern int _rl_find_next_mbchar PARAMS((char *, int, int, int)); #ifdef HANDLE_MULTIBYTE extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *)); -extern int _rl_get_char_len PARAMS((const char *, mbstate_t *)); -extern int _rl_adjust_point PARAMS((const char *, int, mbstate_t *)); +extern int _rl_get_char_len PARAMS((char *, mbstate_t *)); +extern int _rl_adjust_point PARAMS((char *, int, mbstate_t *)); extern int _rl_read_mbchar PARAMS((char *, int)); extern int _rl_read_mbstring PARAMS((int, char *, int)); extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int)); +#define MB_INVALIDCH(x) ((x) == (size_t)-1 || (x) == (size_t)-2) +#define MB_NULLWCH(x) ((x) == 0) + #else /* !HANDLE_MULTIBYTE */ #undef MB_LEN_MAX @@ -101,6 +111,9 @@ extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int)); #define _rl_find_prev_mbchar(b, i, f) (((i) == 0) ? (i) : ((i) - 1)) #define _rl_find_next_mbchar(b, i1, i2, f) ((i1) + (i2)) +#define MB_INVALIDCH(x) (0) +#define MB_NULLWCH(x) (0) + #endif /* !HANDLE_MULTIBYTE */ extern int rl_byte_oriented; diff --git a/cmd-line-utils/readline/rlprivate.h b/cmd-line-utils/readline/rlprivate.h index 36645fb4a65..c3cee917b76 100644 --- a/cmd-line-utils/readline/rlprivate.h +++ b/cmd-line-utils/readline/rlprivate.h @@ -1,7 +1,7 @@ /* rlprivate.h -- functions and variables global to the readline library, but not intended for use by applications. */ -/* Copyright (C) 1999 Free Software Foundation, Inc. +/* Copyright (C) 1999-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -73,7 +73,7 @@ extern int rl_set_retained_kills PARAMS((int)); extern void _rl_set_screen_size PARAMS((int, int)); /* undo.c */ -extern int _rl_fix_last_undo_of_type PARAMS((unsigned int, int, int)); +extern int _rl_fix_last_undo_of_type PARAMS((int, int, int)); /* util.c */ extern char *_rl_savestring PARAMS((const char *)); @@ -103,7 +103,6 @@ extern int readline_internal_char PARAMS((void)); #endif /* READLINE_CALLBACKS */ /* bind.c */ -extern void _rl_bind_if_unbound PARAMS((const char *, rl_command_func_t *)); /* complete.c */ extern char _rl_find_completion_word PARAMS((int *, int *)); @@ -131,6 +130,7 @@ extern int _rl_input_available PARAMS((void)); extern int _rl_input_queued PARAMS((int)); extern void _rl_insert_typein PARAMS((int)); extern int _rl_unget_char PARAMS((int)); +extern int _rl_pushed_input_available PARAMS((void)); /* macro.c */ extern void _rl_with_macro_input PARAMS((char *)); @@ -219,6 +219,7 @@ extern const char *_rl_possible_meta_prefixes[]; /* complete.c */ extern int _rl_complete_show_all; +extern int _rl_complete_show_unmodified; extern int _rl_complete_mark_directories; extern int _rl_complete_mark_symlink_dirs; extern int _rl_print_completions_horizontally; @@ -230,7 +231,7 @@ extern int _rl_page_completions; extern int _rl_vis_botlin; extern int _rl_last_c_pos; extern int _rl_suppress_redisplay; -extern const char *rl_display_prompt; +extern char *rl_display_prompt; /* isearch.c */ extern char *_rl_isearch_terminators; @@ -261,16 +262,16 @@ extern procenv_t readline_top_level; /* terminal.c */ extern int _rl_enable_keypad; extern int _rl_enable_meta; -extern const char *_rl_term_clreol; -extern const char *_rl_term_clrpag; -extern const char *_rl_term_im; -extern const char *_rl_term_ic; -extern const char *_rl_term_ei; -extern const char *_rl_term_DC; -extern const char *_rl_term_up; -extern const char *_rl_term_dc; -extern const char *_rl_term_cr; -extern const char *_rl_term_IC; +extern char *_rl_term_clreol; +extern char *_rl_term_clrpag; +extern char *_rl_term_im; +extern char *_rl_term_ic; +extern char *_rl_term_ei; +extern char *_rl_term_DC; +extern char *_rl_term_up; +extern char *_rl_term_dc; +extern char *_rl_term_cr; +extern char *_rl_term_IC; extern int _rl_screenheight; extern int _rl_screenwidth; extern int _rl_screenchars; @@ -281,4 +282,7 @@ extern int _rl_term_autowrap; extern int _rl_doing_an_undo; extern int _rl_undo_group_level; +/* vi_mode.c */ +extern int _rl_vi_last_command; + #endif /* _RL_PRIVATE_H_ */ diff --git a/cmd-line-utils/readline/rlstdc.h b/cmd-line-utils/readline/rlstdc.h index d6a22b3742c..847fa9c26f4 100644 --- a/cmd-line-utils/readline/rlstdc.h +++ b/cmd-line-utils/readline/rlstdc.h @@ -37,7 +37,7 @@ #endif #ifndef __attribute__ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) # define __attribute__(x) # endif #endif diff --git a/cmd-line-utils/readline/rltty.c b/cmd-line-utils/readline/rltty.c index 9a2cef4b279..3e9c71c8df1 100644 --- a/cmd-line-utils/readline/rltty.c +++ b/cmd-line-utils/readline/rltty.c @@ -184,6 +184,8 @@ static int set_tty_settings PARAMS((int, TIOTYPE *)); static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); + static void save_tty_chars (tiop) TIOTYPE *tiop; @@ -398,6 +400,9 @@ static int set_tty_settings PARAMS((int, TIOTYPE *)); static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); +static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); + #if defined (FLUSHO) # define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) #else @@ -650,7 +655,10 @@ rl_prep_terminal (meta_flag) otio = tio; + rl_tty_unset_default_bindings (_rl_keymap); save_tty_chars (&otio); + RL_SETSTATE(RL_STATE_TTYCSAVED); + _rl_bind_tty_special_chars (_rl_keymap, tio); prepare_terminal_settings (meta_flag, otio, &tio); @@ -709,7 +717,7 @@ rl_deprep_terminal () int rl_restart_output (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int fildes = fileno (rl_outstream); #if defined (TIOCSTART) @@ -742,7 +750,7 @@ rl_restart_output (count, key) int rl_stop_output (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int fildes = fileno (rl_instream); @@ -774,70 +782,97 @@ rl_stop_output (count, key) /* */ /* **************************************************************** */ -/* Set the system's default editing characters to their readline equivalents - in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ -void -rltty_set_default_bindings (kmap) - Keymap kmap; -{ - TIOTYPE ttybuff; - int tty = fileno (rl_instream); +#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func) #if defined (NEW_TTY_DRIVER) +static void +set_special_char (kmap, tiop, sc, func) + Keymap kmap; + TIOTYPE *tiop; + int sc; + rl_command_func_t *func; +{ + if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC) + kmap[(unsigned char)sc].function = func; +} -#define SET_SPECIAL(sc, func) \ - do \ - { \ - int ic; \ - ic = sc; \ - if (ic != -1 && kmap[(unsigned char)ic].type == ISFUNC) \ - kmap[(unsigned char)ic].function = func; \ - } \ - while (0) +#define RESET_SPECIAL(c) \ + if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) + kmap[(unsigned char)c].function = rl_insert; - if (get_tty_settings (tty, &ttybuff) == 0) +static void +_rl_bind_tty_special_chars (kmap, ttybuff) + Keymap kmap; + TIOTYPE ttybuff; +{ + if (ttybuff.flags & SGTTY_SET) { - if (ttybuff.flags & SGTTY_SET) - { - SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); - SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); - } + SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); + SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); + } # if defined (TIOCGLTC) - if (ttybuff.flags & LTCHARS_SET) - { - SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); - SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); - } -# endif /* TIOCGLTC */ + if (ttybuff.flags & LTCHARS_SET) + { + SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); + SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); } +# endif /* TIOCGLTC */ +} #else /* !NEW_TTY_DRIVER */ +static void +set_special_char (kmap, tiop, sc, func) + Keymap kmap; + TIOTYPE *tiop; + int sc; + rl_command_func_t *func; +{ + unsigned char uc; -#define SET_SPECIAL(sc, func) \ - do \ - { \ - unsigned char uc; \ - uc = ttybuff.c_cc[sc]; \ - if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ - kmap[uc].function = func; \ - } \ - while (0) + uc = tiop->c_cc[sc]; + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) + kmap[uc].function = func; +} - if (get_tty_settings (tty, &ttybuff) == 0) - { - SET_SPECIAL (VERASE, rl_rubout); - SET_SPECIAL (VKILL, rl_unix_line_discard); +/* used later */ +#define RESET_SPECIAL(uc) \ + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ + kmap[uc].function = rl_insert; + +static void +_rl_bind_tty_special_chars (kmap, ttybuff) + Keymap kmap; + TIOTYPE ttybuff; +{ + SET_SPECIAL (VERASE, rl_rubout); + SET_SPECIAL (VKILL, rl_unix_line_discard); # if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VLNEXT, rl_quoted_insert); + SET_SPECIAL (VLNEXT, rl_quoted_insert); # endif /* VLNEXT && TERMIOS_TTY_DRIVER */ # if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) - SET_SPECIAL (VWERASE, rl_unix_word_rubout); + SET_SPECIAL (VWERASE, rl_unix_word_rubout); # endif /* VWERASE && TERMIOS_TTY_DRIVER */ - } +} + #endif /* !NEW_TTY_DRIVER */ + +/* Set the system's default editing characters to their readline equivalents + in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ +void +rltty_set_default_bindings (kmap) + Keymap kmap; +{ + TIOTYPE ttybuff; + int tty; + static int called = 0; + + tty = fileno (rl_instream); + + if (get_tty_settings (tty, &ttybuff) == 0) + _rl_bind_tty_special_chars (kmap, ttybuff); } /* New public way to set the system default editing chars to their readline @@ -849,6 +884,30 @@ rl_tty_set_default_bindings (kmap) rltty_set_default_bindings (kmap); } +/* Rebind all of the tty special chars that readline worries about back + to self-insert. Call this before saving the current terminal special + chars with save_tty_chars(). This only works on POSIX termios or termio + systems. */ +void +rl_tty_unset_default_bindings (kmap) + Keymap kmap; +{ + /* Don't bother before we've saved the tty special chars at least once. */ + if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0) + return; + + RESET_SPECIAL (_rl_tty_chars.t_erase); + RESET_SPECIAL (_rl_tty_chars.t_kill); + +# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) + RESET_SPECIAL (_rl_tty_chars.t_lnext); +# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ + +# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) + RESET_SPECIAL (_rl_tty_chars.t_werase); +# endif /* VWERASE && TERMIOS_TTY_DRIVER */ +} + #if defined (HANDLE_SIGNALS) #if defined (NEW_TTY_DRIVER) diff --git a/cmd-line-utils/readline/rltty.h b/cmd-line-utils/readline/rltty.h index 029a3fbc0e1..142e96b6a64 100644 --- a/cmd-line-utils/readline/rltty.h +++ b/cmd-line-utils/readline/rltty.h @@ -61,22 +61,22 @@ #endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ typedef struct _rl_tty_chars { - char t_eof; - char t_eol; - char t_eol2; - char t_erase; - char t_werase; - char t_kill; - char t_reprint; - char t_intr; - char t_quit; - char t_susp; - char t_dsusp; - char t_start; - char t_stop; - char t_lnext; - char t_flush; - char t_status; + unsigned char t_eof; + unsigned char t_eol; + unsigned char t_eol2; + unsigned char t_erase; + unsigned char t_werase; + unsigned char t_kill; + unsigned char t_reprint; + unsigned char t_intr; + unsigned char t_quit; + unsigned char t_susp; + unsigned char t_dsusp; + unsigned char t_start; + unsigned char t_stop; + unsigned char t_lnext; + unsigned char t_flush; + unsigned char t_status; } _RL_TTY_CHARS; #endif /* _RLTTY_H_ */ diff --git a/cmd-line-utils/readline/rltypedefs.h b/cmd-line-utils/readline/rltypedefs.h index f3280e9fce0..862bdb8e4d9 100644 --- a/cmd-line-utils/readline/rltypedefs.h +++ b/cmd-line-utils/readline/rltypedefs.h @@ -1,6 +1,6 @@ /* rltypedefs.h -- Type declarations for readline functions. */ -/* Copyright (C) 2000 Free Software Foundation, Inc. +/* Copyright (C) 2000-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -79,6 +79,12 @@ typedef void rl_voidfunc_t PARAMS((void)); typedef void rl_vintfunc_t PARAMS((int)); typedef void rl_vcpfunc_t PARAMS((char *)); typedef void rl_vcppfunc_t PARAMS((char **)); + +typedef char *rl_cpvfunc_t PARAMS((void)); +typedef char *rl_cpifunc_t PARAMS((int)); +typedef char *rl_cpcpfunc_t PARAMS((char *)); +typedef char *rl_cpcppfunc_t PARAMS((char **)); + #endif /* _RL_FUNCTION_TYPEDEF */ #ifdef __cplusplus diff --git a/cmd-line-utils/readline/savestring.c b/cmd-line-utils/readline/savestring.c new file mode 100644 index 00000000000..ae605374d13 --- /dev/null +++ b/cmd-line-utils/readline/savestring.c @@ -0,0 +1,38 @@ +/* savestring.c */ + +/* Copyright (C) 1998,2003 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library 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, or + (at your option) any later version. + + The GNU Readline Library 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. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#include "config_readline.h" + +#ifdef HAVE_STRING_H +# include <string.h> +#endif +#include "xmalloc.h" + +/* Backwards compatibility, now that savestring has been removed from + all `public' readline header files. */ +char * +savestring (s) + const char *s; +{ + return ((char *)strcpy ((char *)xmalloc (1 + strlen (s)), (s))); +} diff --git a/cmd-line-utils/readline/search.c b/cmd-line-utils/readline/search.c index 637534924f1..1878d2bf031 100644 --- a/cmd-line-utils/readline/search.c +++ b/cmd-line-utils/readline/search.c @@ -80,8 +80,13 @@ static void make_history_line_current (entry) HIST_ENTRY *entry; { - rl_replace_line (entry->line, 0); +#if 0 + rl_replace_line (entry->line, 1); rl_undo_list = (UNDO_LIST *)entry->data; +#else + _rl_replace_text (entry->line, 0, rl_end); + _rl_fix_point (1); +#endif if (_rl_saved_line_for_history) _rl_free_history_entry (_rl_saved_line_for_history); @@ -187,6 +192,11 @@ noninc_search (dir, pchar) saved_point = rl_point; saved_mark = rl_mark; + /* Clear the undo list, since reading the search string should create its + own undo list, and the whole list will end up being freed when we + finish reading the search string. */ + rl_undo_list = 0; + /* Use the line buffer to read the search string. */ rl_line_buffer[0] = 0; rl_end = rl_point = 0; @@ -294,7 +304,7 @@ noninc_search (dir, pchar) code calls this, KEY will be `?'. */ int rl_noninc_forward_search (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { noninc_search (1, (key == '?') ? '?' : 0); return 0; @@ -304,7 +314,7 @@ rl_noninc_forward_search (count, key) calls this, KEY will be `/'. */ int rl_noninc_reverse_search (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { noninc_search (-1, (key == '/') ? '/' : 0); return 0; @@ -314,7 +324,7 @@ rl_noninc_reverse_search (count, key) for. If there is no saved search string, abort. */ int rl_noninc_forward_search_again (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (!noninc_search_string) { @@ -329,7 +339,7 @@ rl_noninc_forward_search_again (count, key) for. If there is no saved search string, abort. */ int rl_noninc_reverse_search_again (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (!noninc_search_string) { diff --git a/cmd-line-utils/readline/shell.c b/cmd-line-utils/readline/shell.c index fd6a2816309..41668d70ab5 100644 --- a/cmd-line-utils/readline/shell.c +++ b/cmd-line-utils/readline/shell.c @@ -124,6 +124,7 @@ sh_set_lines_and_columns (lines, cols) b = (char *)xmalloc (INT_STRLEN_BOUND (int) + sizeof ("LINES=") + 1); sprintf (b, "LINES=%d", lines); putenv (b); + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + sizeof ("COLUMNS=") + 1); sprintf (b, "COLUMNS=%d", cols); putenv (b); @@ -132,9 +133,12 @@ sh_set_lines_and_columns (lines, cols) b = (char *)xmalloc (INT_STRLEN_BOUND (int) + 1); sprintf (b, "%d", lines); setenv ("LINES", b, 1); + free (b); + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + 1); sprintf (b, "%d", cols); setenv ("COLUMNS", b, 1); + free (b); # endif /* HAVE_SETENV */ #endif /* !HAVE_PUTENV */ } diff --git a/cmd-line-utils/readline/signals.c b/cmd-line-utils/readline/signals.c index 4609598ff98..be1150f6c54 100644 --- a/cmd-line-utils/readline/signals.c +++ b/cmd-line-utils/readline/signals.c @@ -71,6 +71,10 @@ typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt # define sigemptyset(m) #endif /* !HAVE_POSIX_SIGNALS */ +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); @@ -83,6 +87,8 @@ int rl_catch_signals = 1; /* If non-zero, readline will install a signal handler for SIGWINCH. */ #ifdef SIGWINCH int rl_catch_sigwinch = 1; +#else +int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */ #endif static int signals_set_flag; @@ -231,7 +237,7 @@ rl_set_sighandler (sig, handler, ohandler) struct sigaction act; act.sa_handler = handler; - act.sa_flags = 0; /* XXX - should we set SA_RESTART for SIGWINCH? */ + act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0; sigemptyset (&act.sa_mask); sigemptyset (&ohandler->sa_mask); sigaction (sig, &act, &old_handler); diff --git a/cmd-line-utils/readline/terminal.c b/cmd-line-utils/readline/terminal.c index b2bcf5f146c..3545fce5b85 100644 --- a/cmd-line-utils/readline/terminal.c +++ b/cmd-line-utils/readline/terminal.c @@ -82,41 +82,40 @@ static int tcap_initialized; # if defined (__EMX__) || defined (NEED_EXTERN_PC) extern # endif /* __EMX__ || NEED_EXTERN_PC */ -char PC; -char *BC, *UP; +char PC, *BC, *UP; #endif /* __linux__ */ /* Some strings to control terminal actions. These are output by tputs (). */ -const char *_rl_term_clreol; -const char *_rl_term_clrpag; -const char *_rl_term_cr; -const char *_rl_term_backspace; -const char *_rl_term_goto; -const char *_rl_term_pc; +char *_rl_term_clreol; +char *_rl_term_clrpag; +char *_rl_term_cr; +char *_rl_term_backspace; +char *_rl_term_goto; +char *_rl_term_pc; /* Non-zero if we determine that the terminal can do character insertion. */ int _rl_terminal_can_insert = 0; /* How to insert characters. */ -const char *_rl_term_im; -const char *_rl_term_ei; -const char *_rl_term_ic; -const char *_rl_term_ip; -const char *_rl_term_IC; +char *_rl_term_im; +char *_rl_term_ei; +char *_rl_term_ic; +char *_rl_term_ip; +char *_rl_term_IC; /* How to delete characters. */ -const char *_rl_term_dc; -const char *_rl_term_DC; +char *_rl_term_dc; +char *_rl_term_DC; #if defined (HACK_TERMCAP_MOTION) char *_rl_term_forward_char; #endif /* HACK_TERMCAP_MOTION */ /* How to go up a line. */ -const char *_rl_term_up; +char *_rl_term_up; /* A visible bell; char if the terminal can be made to flash the screen. */ -static const char *_rl_visible_bell; +static char *_rl_visible_bell; /* Non-zero means the terminal can auto-wrap lines. */ int _rl_term_autowrap; @@ -126,30 +125,30 @@ static int term_has_meta; /* The sequences to write to turn on and off the meta key, if this terminal has one. */ -static const char *_rl_term_mm; -static const char *_rl_term_mo; +static char *_rl_term_mm; +static char *_rl_term_mo; /* The key sequences output by the arrow keys, if this terminal has any. */ -static const char *_rl_term_ku; -static const char *_rl_term_kd; -static const char *_rl_term_kr; -static const char *_rl_term_kl; +static char *_rl_term_ku; +static char *_rl_term_kd; +static char *_rl_term_kr; +static char *_rl_term_kl; /* How to initialize and reset the arrow keys, if this terminal has any. */ -static const char *_rl_term_ks; -static const char *_rl_term_ke; +static char *_rl_term_ks; +static char *_rl_term_ke; /* The key sequences sent by the Home and End keys, if any. */ -static const char *_rl_term_kh; -static const char *_rl_term_kH; -static const char *_rl_term_at7; /* @7 */ +static char *_rl_term_kh; +static char *_rl_term_kH; +static char *_rl_term_at7; /* @7 */ /* Insert key */ -static const char *_rl_term_kI; +static char *_rl_term_kI; /* Cursor control */ -static const char *_rl_term_vs; /* very visible */ -static const char *_rl_term_ve; /* normal */ +static char *_rl_term_vs; /* very visible */ +static char *_rl_term_ve; /* normal */ static void bind_termcap_arrow_keys PARAMS((Keymap)); @@ -295,7 +294,7 @@ rl_resize_terminal () struct _tc_string { const char *tc_var; - const char **tc_value; + char **tc_value; }; /* This should be kept sorted, just in case we decide to change the @@ -343,14 +342,10 @@ get_term_capabilities (bp) char **bp; { #if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ - register unsigned int i; + register int i; for (i = 0; i < NUM_TC_STRINGS; i++) -# if defined(__LCC__) || defined(__MWERKS__) *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp); -# else - *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); -# endif #endif tcap_initialized = 1; } @@ -432,8 +427,8 @@ _rl_init_terminal_io (terminal_name) tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we change that later... */ PC = '\0'; - BC = (char*)(_rl_term_backspace = "\b"); - UP = (char*)_rl_term_up; + BC = _rl_term_backspace = "\b"; + UP = _rl_term_up; return 0; } @@ -443,8 +438,8 @@ _rl_init_terminal_io (terminal_name) /* Set up the variables that the termcap library expects the application to provide. */ PC = _rl_term_pc ? *_rl_term_pc : 0; - BC = (char*)_rl_term_backspace; - UP = (char*)_rl_term_up; + BC = _rl_term_backspace; + UP = _rl_term_up; if (!_rl_term_cr) _rl_term_cr = "\r"; @@ -488,22 +483,22 @@ bind_termcap_arrow_keys (map) xkeymap = _rl_keymap; _rl_keymap = map; - _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history); - _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history); - _rl_bind_if_unbound (_rl_term_kr, rl_forward); - _rl_bind_if_unbound (_rl_term_kl, rl_backward); + rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history); + rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history); + rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char); + rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char); - _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ - _rl_bind_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ + rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ + rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ _rl_keymap = xkeymap; } -const char * +char * rl_get_termcap (cap) const char *cap; { - register unsigned int i; + register int i; if (tcap_initialized == 0) return ((char *)NULL); diff --git a/cmd-line-utils/readline/text.c b/cmd-line-utils/readline/text.c index d98b266edfe..ad7b53ec422 100644 --- a/cmd-line-utils/readline/text.c +++ b/cmd-line-utils/readline/text.c @@ -1,6 +1,6 @@ /* text.c -- text handling commands for readline. */ -/* Copyright (C) 1987-2002 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -168,6 +168,9 @@ _rl_fix_point (fix_mark_too) } #undef _RL_FIX_POINT +/* Replace the contents of the line buffer between START and END with + TEXT. The operation is undoable. To replace the entire line in an + undoable mode, use _rl_replace_text(text, 0, rl_end); */ int _rl_replace_text (text, start, end) const char *text; @@ -400,7 +403,7 @@ rl_backward (count, key) /* Move to the beginning of the line. */ int rl_beg_of_line (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_point = 0; return 0; @@ -409,7 +412,7 @@ rl_beg_of_line (count, key) /* Move to the end of the line. */ int rl_end_of_line (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_point = rl_end; return 0; @@ -506,7 +509,7 @@ rl_backward_word (count, key) /* Clear the current line. Numeric argument to C-l does this. */ int rl_refresh_line (ignore1, ignore2) - int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); + int ignore1, ignore2; { int curr_line; @@ -545,7 +548,7 @@ rl_clear_screen (count, key) int rl_arrow_keys (count, c) - int count, c __attribute__((unused)); + int count, c; { int ch; @@ -799,13 +802,10 @@ _rl_overwrite_char (count, c) k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX); #endif + rl_begin_undo_group (); + for (i = 0; i < count; i++) { - rl_begin_undo_group (); - - if (rl_point < rl_end) - rl_delete (1, c); - #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) rl_insert_text (mbkey); @@ -813,9 +813,12 @@ _rl_overwrite_char (count, c) #endif _rl_insert_char (1, c); - rl_end_undo_group (); + if (rl_point < rl_end) + rl_delete (1, c); } + rl_end_undo_group (); + return 0; } @@ -830,7 +833,7 @@ rl_insert (count, c) /* Insert the next typed character verbatim. */ int rl_quoted_insert (count, key) - int count, key __attribute__((unused)); + int count, key; { int c; @@ -852,7 +855,7 @@ rl_quoted_insert (count, key) /* Insert a tab character. */ int rl_tab_insert (count, key) - int count, key __attribute__((unused)); + int count, key; { return (_rl_insert_char (count, '\t')); } @@ -862,7 +865,7 @@ rl_tab_insert (count, key) meaning in the future. */ int rl_newline (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { rl_done = 1; @@ -875,7 +878,8 @@ rl_newline (count, key) if (rl_editing_mode == vi_mode) { _rl_vi_done_inserting (); - _rl_vi_reset_last (); + if (_rl_vi_textmod_command (_rl_vi_last_command) == 0) /* XXX */ + _rl_vi_reset_last (); } #endif /* VI_MODE */ @@ -895,7 +899,7 @@ rl_newline (count, key) is special cased. */ int rl_do_lowercase_version (ignore1, ignore2) - int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); + int ignore1, ignore2; { return 0; } @@ -933,9 +937,12 @@ _rl_overwrite_rubout (count, key) rl_delete_text (opoint, rl_point); /* Emacs puts point at the beginning of the sequence of spaces. */ - opoint = rl_point; - _rl_insert_char (l, ' '); - rl_point = opoint; + if (rl_point < rl_end) + { + opoint = rl_point; + _rl_insert_char (l, ' '); + rl_point = opoint; + } rl_end_undo_group (); @@ -1087,7 +1094,7 @@ rl_rubout_or_delete (count, key) /* Delete all spaces and tabs around point. */ int rl_delete_horizontal_space (count, ignore) - int count __attribute__((unused)), ignore __attribute__((unused)); + int count, ignore; { int start = rl_point; @@ -1128,9 +1135,9 @@ rl_delete_or_show_completions (count, key) A K*rn shell style function. */ int rl_insert_comment (count, key) - int count __attribute__((unused)), key; + int count, key; { - const char *rl_comment_text; + char *rl_comment_text; int rl_comment_len; rl_beg_of_line (1, key); @@ -1167,7 +1174,7 @@ rl_insert_comment (count, key) /* Uppercase the word at point. */ int rl_upcase_word (count, key) - int count, key __attribute__((unused)); + int count, key; { return (rl_change_case (count, UpCase)); } @@ -1175,7 +1182,7 @@ rl_upcase_word (count, key) /* Lowercase the word at point. */ int rl_downcase_word (count, key) - int count, key __attribute__((unused)); + int count, key; { return (rl_change_case (count, DownCase)); } @@ -1183,7 +1190,7 @@ rl_downcase_word (count, key) /* Upcase the first letter, downcase the rest. */ int rl_capitalize_word (count, key) - int count, key __attribute__((unused)); + int count, key; { return (rl_change_case (count, CapCase)); } @@ -1308,7 +1315,7 @@ rl_transpose_words (count, key) then transpose the characters before point. */ int rl_transpose_chars (count, key) - int count, key __attribute__((unused)); + int count, key; { #if defined (HANDLE_MULTIBYTE) char *dummy; @@ -1480,14 +1487,14 @@ _rl_char_search (count, fdir, bdir) int rl_char_search (count, key) - int count, key __attribute__((unused)); + int count, key; { return (_rl_char_search (count, FFIND, BFIND)); } int rl_backward_char_search (count, key) - int count, key __attribute__((unused)); + int count, key; { return (_rl_char_search (count, BFIND, FFIND)); } @@ -1513,7 +1520,7 @@ _rl_set_mark_at_pos (position) /* A bindable command to set the mark. */ int rl_set_mark (count, key) - int count, key __attribute__((unused)); + int count, key; { return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); } @@ -1521,7 +1528,7 @@ rl_set_mark (count, key) /* Exchange the position of mark and point. */ int rl_exchange_point_and_mark (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (rl_mark > rl_end) rl_mark = -1; diff --git a/cmd-line-utils/readline/tilde.c b/cmd-line-utils/readline/tilde.c index 456a6bcb357..c44357ffbea 100644 --- a/cmd-line-utils/readline/tilde.c +++ b/cmd-line-utils/readline/tilde.c @@ -19,6 +19,8 @@ along with Readline; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + #include "config_readline.h" #if defined (HAVE_UNISTD_H) @@ -188,7 +190,7 @@ tilde_expand (string) int result_size, result_index; result_index = result_size = 0; - if ((result = strchr(string, '~'))) + if (result = strchr (string, '~')) result = (char *)xmalloc (result_size = (strlen (string) + 16)); else result = (char *)xmalloc (result_size = (strlen (string) + 1)); diff --git a/cmd-line-utils/readline/undo.c b/cmd-line-utils/readline/undo.c index 947da3d00d0..48baded332a 100644 --- a/cmd-line-utils/readline/undo.c +++ b/cmd-line-utils/readline/undo.c @@ -169,8 +169,7 @@ rl_do_undo () int _rl_fix_last_undo_of_type (type, start, end) - unsigned int type; - int start, end; + int type, start, end; { UNDO_LIST *rl; @@ -228,7 +227,7 @@ rl_modifying (start, end) /* Revert the current line to its previous state. */ int rl_revert_line (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { if (!rl_undo_list) rl_ding (); @@ -243,7 +242,7 @@ rl_revert_line (count, key) /* Do some undoing of things that were done. */ int rl_undo_command (count, key) - int count, key __attribute__((unused)); + int count, key; { if (count < 0) return 0; /* Nothing to do. */ diff --git a/cmd-line-utils/readline/util.c b/cmd-line-utils/readline/util.c index 403b3d544d9..43478aaf1ac 100644 --- a/cmd-line-utils/readline/util.c +++ b/cmd-line-utils/readline/util.c @@ -96,14 +96,14 @@ _rl_abort_internal () int rl_abort (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { return (_rl_abort_internal ()); } int rl_tty_status (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { #if defined (TIOCSTAT) ioctl (1, TIOCSTAT, (char *)0); @@ -153,7 +153,7 @@ rl_extend_line_buffer (len) /* A function for simple tilde expansion. */ int rl_tilde_expand (ignore, key) - int ignore __attribute__((unused)), key __attribute__((unused)); + int ignore, key; { register int start, end; char *homedir, *temp; @@ -248,7 +248,7 @@ _rl_strpbrk (string1, string2) { v = _rl_get_char_len (string1, &ps); if (v > 1) - string += v - 1; /* -1 to account for auto-increment in loop */ + string1 += v - 1; /* -1 to account for auto-increment in loop */ } #endif } diff --git a/cmd-line-utils/readline/vi_mode.c b/cmd-line-utils/readline/vi_mode.c index e8ad05d866f..9a8cfdd7200 100644 --- a/cmd-line-utils/readline/vi_mode.c +++ b/cmd-line-utils/readline/vi_mode.c @@ -1,7 +1,7 @@ /* vi_mode.c -- A vi emulation mode for Bash. Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ -/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1987-2004 Free Software Foundation, Inc. This file is part of the GNU Readline Library, a library for reading lines of text with interactive input and history editing. @@ -61,6 +61,8 @@ #define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) #endif +int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ + /* Non-zero means enter insertion mode. */ static int _rl_vi_doing_insert; @@ -81,7 +83,6 @@ static int vi_continued_command; static char *vi_insert_buffer; static int vi_insert_buffer_size; -static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ static int _rl_vi_last_repeat = 1; static int _rl_vi_last_arg_sign = 1; static int _rl_vi_last_motion; @@ -109,7 +110,7 @@ static int rl_digit_loop1 PARAMS((void)); void _rl_vi_initialize_line () { - register unsigned int i; + register int i; for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) vi_mark_chars[i] = -1; @@ -133,6 +134,16 @@ _rl_vi_set_last (key, repeat, sign) _rl_vi_last_arg_sign = sign; } +/* A convenience function that calls _rl_vi_set_last to save the last command + information and enters insertion mode. */ +void +rl_vi_start_inserting (key, repeat, sign) + int key, repeat, sign; +{ + _rl_vi_set_last (key, repeat, sign); + rl_vi_insertion_mode (1, key); +} + /* Is the command C a VI mode text modification command? */ int _rl_vi_textmod_command (c) @@ -156,7 +167,7 @@ _rl_vi_stuff_insert (count) puts you back into insert mode. */ int rl_vi_redo (count, c) - int count, c __attribute__((unused)); + int count, c; { int r; @@ -195,7 +206,7 @@ rl_vi_undo (count, key) /* Yank the nth arg from the previous line into this line at point. */ int rl_vi_yank_arg (count, key) - int count, key __attribute__((unused)); + int count, key; { /* Readline thinks that the first word on a line is the 0th, while vi thinks the first word on a line is the 1st. Compensate. */ @@ -276,7 +287,7 @@ rl_vi_search (count, key) /* Completion, from vi's point of view. */ int rl_vi_complete (ignore, key) - int ignore __attribute__((unused)), key; + int ignore, key; { if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) { @@ -295,21 +306,18 @@ rl_vi_complete (ignore, key) rl_complete (0, key); if (key == '*' || key == '\\') - { - _rl_vi_set_last (key, 1, rl_arg_sign); - rl_vi_insertion_mode (1, key); - } + rl_vi_start_inserting (key, 1, rl_arg_sign); + return (0); } /* Tilde expansion for vi mode. */ int rl_vi_tilde_expand (ignore, key) - int ignore __attribute__((unused)), key; + int ignore, key; { rl_tilde_expand (0, key); - _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ - rl_vi_insertion_mode (1, key); + rl_vi_start_inserting (key, 1, rl_arg_sign); return (0); } @@ -377,7 +385,7 @@ rl_vi_end_word (count, key) /* Move forward a word the way that 'W' does. */ int rl_vi_fWord (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { @@ -394,7 +402,7 @@ rl_vi_fWord (count, ignore) int rl_vi_bWord (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point > 0) { @@ -418,7 +426,7 @@ rl_vi_bWord (count, ignore) int rl_vi_eWord (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { @@ -427,7 +435,8 @@ rl_vi_eWord (count, ignore) /* Move to the next non-whitespace character (to the start of the next word). */ - while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; if (rl_point && rl_point < rl_end) { @@ -448,7 +457,7 @@ rl_vi_eWord (count, ignore) int rl_vi_fword (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point < (rl_end - 1)) { @@ -474,7 +483,7 @@ rl_vi_fword (count, ignore) int rl_vi_bword (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point > 0) { @@ -513,7 +522,7 @@ rl_vi_bword (count, ignore) int rl_vi_eword (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { while (count-- && rl_point < rl_end - 1) { @@ -538,7 +547,7 @@ rl_vi_eword (count, ignore) int rl_vi_insert_beg (count, key) - int count __attribute__((unused)), key; + int count, key; { rl_beg_of_line (1, key); rl_vi_insertion_mode (1, key); @@ -547,7 +556,7 @@ rl_vi_insert_beg (count, key) int rl_vi_append_mode (count, key) - int count __attribute__((unused)), key; + int count, key; { if (rl_point < rl_end) { @@ -567,7 +576,7 @@ rl_vi_append_mode (count, key) int rl_vi_append_eol (count, key) - int count __attribute__((unused)), key; + int count, key; { rl_end_of_line (1, key); rl_vi_append_mode (1, key); @@ -577,7 +586,7 @@ rl_vi_append_eol (count, key) /* What to do in the case of C-d. */ int rl_vi_eof_maybe (count, c) - int count __attribute__((unused)), c __attribute__((unused)); + int count, c; { return (rl_newline (1, '\n')); } @@ -588,7 +597,7 @@ rl_vi_eof_maybe (count, c) switching keymaps. */ int rl_vi_insertion_mode (count, key) - int count __attribute__((unused)), key; + int count, key; { _rl_keymap = vi_insertion_keymap; _rl_vi_last_key_before_insert = key; @@ -638,7 +647,7 @@ _rl_vi_done_inserting () } else { - if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) + if ((_rl_vi_last_key_before_insert == 'i' || _rl_vi_last_key_before_insert == 'a') && rl_undo_list) _rl_vi_save_insert (rl_undo_list); /* XXX - Other keys probably need to be checked. */ else if (_rl_vi_last_key_before_insert == 'C') @@ -651,7 +660,7 @@ _rl_vi_done_inserting () int rl_vi_movement_mode (count, key) - int count __attribute__((unused)), key; + int count, key; { if (rl_point > 0) rl_backward_char (1, key); @@ -678,7 +687,8 @@ _rl_vi_change_mbchar_case (count) int count; { wchar_t wc; - char mb[MB_LEN_MAX]; + char mb[MB_LEN_MAX+1]; + int mblen; mbstate_t ps; memset (&ps, 0, sizeof (mbstate_t)); @@ -701,7 +711,9 @@ _rl_vi_change_mbchar_case (count) /* Vi is kind of strange here. */ if (wc) { - wctomb (mb, wc); + mblen = wcrtomb (mb, wc, &ps); + if (mblen >= 0) + mb[mblen] = '\0'; rl_begin_undo_group (); rl_delete (1, 0); rl_insert_text (mb); @@ -718,14 +730,15 @@ _rl_vi_change_mbchar_case (count) int rl_vi_change_case (count, ignore) - int count, ignore __attribute__((unused)); + int count, ignore; { - char c = 0; + int c, p; /* Don't try this on an empty line. */ if (rl_point >= rl_end) return (0); + c = 0; #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) return (_rl_vi_change_mbchar_case (count)); @@ -747,8 +760,11 @@ rl_vi_change_case (count, ignore) /* Vi is kind of strange here. */ if (c) { + p = rl_point; rl_begin_undo_group (); - rl_delete (1, c); + rl_vi_delete (1, c); + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; _rl_insert_char (1, c); rl_end_undo_group (); rl_vi_check (); @@ -761,12 +777,14 @@ rl_vi_change_case (count, ignore) int rl_vi_put (count, key) - int count __attribute__((unused)), key; + int count, key; { if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); - rl_yank (1, key); + while (count--) + rl_yank (1, key); + rl_backward_char (1, key); return (0); } @@ -814,6 +832,7 @@ rl_vi_domove (key, nextkey) { save = rl_numeric_arg; rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; rl_digit_loop1 (); rl_numeric_arg *= save; RL_SETSTATE(RL_STATE_MOREINPUT); @@ -941,7 +960,7 @@ rl_digit_loop1 () int rl_vi_delete_to (count, key) - int count __attribute__((unused)), key; + int count, key; { int c; @@ -1012,8 +1031,7 @@ rl_vi_change_to (count, key) /* `C' does not save the text inserted for undoing or redoing. */ if (_rl_uppercase_p (key) == 0) _rl_vi_doing_insert = 1; - _rl_vi_set_last (key, count, rl_arg_sign); - rl_vi_insertion_mode (1, key); + rl_vi_start_inserting (key, rl_numeric_arg, rl_arg_sign); } return (0); @@ -1021,7 +1039,7 @@ rl_vi_change_to (count, key) int rl_vi_yank_to (count, key) - int count __attribute__((unused)), key; + int count, key; { int c, save = rl_point; @@ -1077,7 +1095,7 @@ rl_vi_delete (count, key) int rl_vi_back_to_indent (count, key) - int count __attribute__((unused)), key; + int count, key; { rl_beg_of_line (1, key); while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) @@ -1087,7 +1105,7 @@ rl_vi_back_to_indent (count, key) int rl_vi_first_print (count, key) - int count __attribute__((unused)), key; + int count, key; { return (rl_vi_back_to_indent (1, key)); } @@ -1156,7 +1174,7 @@ rl_vi_char_search (count, key) /* Match brackets */ int rl_vi_match (ignore, key) - int ignore __attribute__((unused)), key; + int ignore, key; { int count = 1, brack, pos, tmp, pre; @@ -1262,14 +1280,14 @@ rl_vi_bracktype (c) /* XXX - think about reading an entire mbchar with _rl_read_mbchar and inserting it in one bunch instead of the loop below (like in - rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] + rl_vi_char_search or _rl_vi_change_mbchar_case). Set c to mbchar[0] for test against 033 or ^C. Make sure that _rl_read_mbchar does this right. */ int rl_vi_change_char (count, key) - int count, key __attribute__((unused)); + int count, key; { - int c; + int c, p; if (vi_redoing) c = _rl_vi_last_replacement; @@ -1283,11 +1301,11 @@ rl_vi_change_char (count, key) if (c == '\033' || c == CTRL ('C')) return -1; + rl_begin_undo_group (); while (count-- && rl_point < rl_end) { - rl_begin_undo_group (); - - rl_delete (1, c); + p = rl_point; + rl_vi_delete (1, c); #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) while (_rl_insert_char (1, c)) @@ -1298,12 +1316,14 @@ rl_vi_change_char (count, key) } else #endif - _rl_insert_char (1, c); - if (count == 0) - rl_backward_char (1, c); - - rl_end_undo_group (); + { + if (rl_point < p) /* Did we retreat at EOL? */ + rl_point++; + _rl_insert_char (1, c); + } } + rl_end_undo_group (); + return (0); } @@ -1313,7 +1333,7 @@ rl_vi_subst (count, key) { /* If we are redoing, rl_vi_change_to will stuff the last motion char */ if (vi_redoing == 0) - rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ + rl_stuff_char ((key == 'S') ? 'c' : 'l'); /* `S' == `cc', `s' == `cl' */ return (rl_vi_change_to (count, 'c')); } @@ -1370,7 +1390,7 @@ rl_vi_overstrike_delete (count, key) int rl_vi_replace (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int i; @@ -1431,7 +1451,7 @@ rl_vi_possible_completions() /* Functions to save and restore marks. */ int rl_vi_set_mark (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int ch; @@ -1451,7 +1471,7 @@ rl_vi_set_mark (count, key) int rl_vi_goto_mark (count, key) - int count __attribute__((unused)), key __attribute__((unused)); + int count, key; { int ch; diff --git a/configure.in b/configure.in index 8ea135c3613..fda98749c53 100644 --- a/configure.in +++ b/configure.in @@ -1,23 +1,23 @@ dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.58)dnl Minimum Autoconf version required. +AC_PREREQ(2.57)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # Don't forget to also update the NDB lines below. -AM_INIT_AUTOMAKE(mysql, 5.0.10-beta) +AM_INIT_AUTOMAKE(mysql, 5.0.11-beta) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 DOT_FRM_VERSION=6 # See the libtool docs for information on how to do shared lib versions. -SHARED_LIB_VERSION=14:0:0 +SHARED_LIB_VERSION=15:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=10 +NDB_VERSION_BUILD=11 NDB_VERSION_STATUS="beta" # Set all version vars based on $VERSION. How do we do this more elegant ? @@ -1966,7 +1966,7 @@ AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" then - CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-Wcheck//'` + CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-ansi//; s/-pedantic//; s/-Wcheck//'` fi AC_TRY_COMPILE( @@ -2001,7 +2001,7 @@ AC_LANG_SAVE AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" then - CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-Wcheck//'` + CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-ansi//; s/-pedantic//; s/-Wcheck//'` fi AC_TRY_COMPILE( [#undef inline @@ -2034,7 +2034,7 @@ AC_LANG_SAVE AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" then - CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-Wcheck//'` + CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed -e 's/-fbranch-probabilities//; s/-Wall//; s/-ansi//; s/-pedantic//; s/-Wcheck//'` fi AC_TRY_COMPILE( [#undef inline diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index 946ac219e1a..916203bc7d7 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -1,3 +1,4 @@ + /* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify @@ -23,8 +24,10 @@ #include <my_global.h> #include <my_sys.h> +#include <m_string.h> #include <my_getopt.h> + const char *config_file="my"; /* Default config file */ uint verbose= 0, opt_defaults_file_used= 0; const char *default_dbug_option="d:t:o,/tmp/my_print_defaults.trace"; @@ -48,6 +51,10 @@ static struct my_option my_long_options[] = "Read this file after the global /etc config file and before the config file in the users home directory.", (gptr*) &defaults_extra_file, (gptr*) &defaults_extra_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"defaults-group-suffix", 'g', + "In addition to the given groups, read also groups with this suffix", + (gptr*) &defaults_group_suffix, (gptr*) &defaults_group_suffix, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"extra-file", 'e', "Synonym for --defaults-extra-file.", (gptr*) &defaults_extra_file, (gptr*) &defaults_extra_file, 0, GET_STR, @@ -127,37 +134,32 @@ static int get_options(int *argc,char ***argv) return 0; } + int main(int argc, char **argv) { - int count, error; - char **load_default_groups, *tmp_arguments[3], - **argument, **arguments; - char *defaults, *extra_defaults; + int count, error, args_used; + char **load_default_groups, *tmp_arguments[6]; + char **argument, **arguments, **org_argv; + char *defaults, *extra_defaults, *group_suffix; MY_INIT(argv[0]); - get_defaults_files(argc, argv, &defaults, &extra_defaults); + org_argv= argv; + args_used= get_defaults_options(argc, argv, &defaults, &extra_defaults, + &group_suffix); - /* - ** Check out the args - */ - if (!(load_default_groups=(char**) my_malloc((argc+2)*sizeof(char*), + /* Copy defaults-xxx arguments & program name */ + count=args_used+1; + arguments= tmp_arguments; + memcpy((char*) arguments, (char*) org_argv, count * sizeof(*org_argv)); + arguments[count]= 0; + + /* Check out the args */ + if (!(load_default_groups=(char**) my_malloc((argc+1)*sizeof(char*), MYF(MY_WME)))) exit(1); if (get_options(&argc,&argv)) exit(1); - - for (count=0; *argv ; argv++,count++) - load_default_groups[count]= *argv; - load_default_groups[count]=0; - - count=0; - arguments=tmp_arguments; - arguments[count++]=my_progname; - if (extra_defaults) - arguments[count++]= extra_defaults; - if (defaults) - arguments[count++]= defaults; - arguments[count]= 0; + memcpy((char*) load_default_groups, (char*) argv, (argc + 1) * sizeof(*argv)); if ((error= load_defaults(config_file, (const char **) load_default_groups, &count, &arguments))) diff --git a/extra/perror.c b/extra/perror.c index d68f5230e4a..dedd558e4cf 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -41,7 +41,7 @@ static struct my_option my_long_options[] = {"info", 'I', "Synonym for --help.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_NDBCLUSTER_DB - {"ndb", 0, "Ndbcluster storage engine specific error codes.", (gptr*) &ndb_code, + {"ndb", 257, "Ndbcluster storage engine specific error codes.", (gptr*) &ndb_code, (gptr*) &ndb_code, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif #ifdef HAVE_SYS_ERRLIST diff --git a/extra/replace.c b/extra/replace.c index d92355359d3..9acf1620d49 100644 --- a/extra/replace.c +++ b/extra/replace.c @@ -175,7 +175,7 @@ register char **argv[]; case 'I': case '?': help=1; /* Help text written */ - printf("%s Ver 1.3 for %s at %s\n",my_progname,SYSTEM_TYPE, + printf("%s Ver 1.4 for %s at %s\n",my_progname,SYSTEM_TYPE, MACHINE_TYPE); if (version) break; @@ -1048,23 +1048,31 @@ FILE *in,*out; } -static int convert_file(rep,name) -REPLACE *rep; -my_string name; +static int convert_file(REPLACE *rep, my_string name) { int error; FILE *in,*out; - char dir_buff[FN_REFLEN],*tempname; + char dir_buff[FN_REFLEN], tempname[FN_REFLEN]; + char link_name[FN_REFLEN], *org_name = name; + File temp_file; DBUG_ENTER("convert_file"); - if (!(in=my_fopen(name,O_RDONLY,MYF(MY_WME)))) + /* check if name is a symlink */ +#ifdef HAVE_READLINK + org_name= (!my_disable_symlinks && + !my_readlink(link_name, name, MYF(0))) ? link_name : name; +#endif + if (!(in= my_fopen(org_name,O_RDONLY,MYF(MY_WME)))) + DBUG_RETURN(1); + dirname_part(dir_buff,org_name); + if ((temp_file= create_temp_file(tempname, dir_buff, "PR", O_WRONLY, + MYF(MY_WME))) < 0) + { + my_fclose(in,MYF(0)); DBUG_RETURN(1); - dirname_part(dir_buff,name); - tempname=my_tempnam(dir_buff,"PR",MYF(MY_WME)); - if (!(out=my_fopen(tempname,(int) (O_WRONLY | O_CREAT), - MYF(MY_WME)))) + } + if (!(out= my_fdopen(temp_file, tempname, O_WRONLY, MYF(MY_WME)))) { - (*free)(tempname); my_fclose(in,MYF(0)); DBUG_RETURN(1); } @@ -1073,10 +1081,9 @@ my_string name; my_fclose(in,MYF(0)); my_fclose(out,MYF(0)); if (updated && ! error) - my_redel(name,tempname,MYF(MY_WME | MY_LINK_WARNING)); + my_redel(org_name,tempname,MYF(MY_WME | MY_LINK_WARNING)); else my_delete(tempname,MYF(MY_WME)); - (*free)(tempname); if (!silent && ! error) { if (updated) diff --git a/include/config-netware.h b/include/config-netware.h index 906f557f608..16fa451a770 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -46,6 +46,7 @@ extern "C" { #undef HAVE_SYS_MMAN_H #undef HAVE_SYNCH_H #undef HAVE_MMAP +#undef HAVE_RINT #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_SIGMASK 1 diff --git a/include/config-win.h b/include/config-win.h index 2559b3b74fd..04f79e95c80 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -284,7 +284,9 @@ inline double ulonglong2double(ulonglong value) #define doublestore(T,V) { *((long *) T) = *((long*) &V); \ *(((long *) T)+1) = *(((long*) &V)+1); } #define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); } +#define floatget(V,M) memcpy((byte*) &V,(byte*) (M),sizeof(float)) #define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V), sizeof(float)) +#define floatget(V,M) memcpy((byte*)(&V), (byte*)(M), sizeof(float)) #define float8get(V,M) doubleget((V),(M)) #define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) #define float8store(V,M) doublestore((V),(M)) @@ -353,6 +355,9 @@ inline double ulonglong2double(ulonglong value) #ifndef DEFAULT_HOME_ENV #define DEFAULT_HOME_ENV MYSQL_HOME #endif +#ifndef DEFAULT_GROUP_SUFFIX_ENV +#define DEFAULT_GROUP_SUFFIX_ENV MYSQL_GROUP_SUFFIX +#endif /* File name handling */ diff --git a/include/my_bitmap.h b/include/my_bitmap.h index 84a5d8bd18a..f4fe28266e4 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -54,6 +54,7 @@ extern void bitmap_clear_all(MY_BITMAP *map); extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit); extern void bitmap_free(MY_BITMAP *map); extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit); extern void bitmap_set_all(MY_BITMAP *map); extern void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit); extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size); diff --git a/include/my_global.h b/include/my_global.h index 61850931a8e..95763f64e55 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -1005,7 +1005,8 @@ do { doubleget_union _tmp; \ #define float4get(V,M) do { *((long *) &(V)) = *((long*) (M)); } while(0) #define float8get(V,M) doubleget((V),(M)) #define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) -#define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V), sizeof(float)) +#define floatstore(T,V) memcpy((byte*)(T), (byte*)(&V),sizeof(float)) +#define floatget(V,M) memcpy((byte*) &V,(byte*) (M),sizeof(float)) #define float8store(V,M) doublestore((V),(M)) #endif /* __i386__ */ @@ -1176,7 +1177,8 @@ do { doubleget_union _tmp; \ *(((char*)T)+1)=(((A) >> 16));\ *(((char*)T)+0)=(((A) >> 24)); } while(0) -#define floatstore(T,V) memcpy_fixed((byte*)(T), (byte*)(&V), sizeof(float)) +#define floatget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(float)) +#define floatstore(T,V) memcpy_fixed((byte*) (T),(byte*)(&V),sizeof(float)) #define doubleget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(double)) #define doublestore(T,V) memcpy_fixed((byte*) (T),(byte*) &V,sizeof(double)) #define longlongget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(ulonglong)) @@ -1191,7 +1193,8 @@ do { doubleget_union _tmp; \ #define shortstore(T,V) int2store(T,V) #define longstore(T,V) int4store(T,V) #ifndef floatstore -#define floatstore(T,V) memcpy_fixed((byte*)(T), (byte*)(&V), sizeof(float)) +#define floatstore(T,V) memcpy_fixed((byte*) (T),(byte*) (&V),sizeof(float)) +#define floatget(V,M) memcpy_fixed((byte*) &V, (byte*) (M), sizeof(float)) #endif #ifndef doubleget #define doubleget(V,M) memcpy_fixed((byte*) &V,(byte*) (M),sizeof(double)) diff --git a/include/my_sys.h b/include/my_sys.h index e31659c0652..6747733da9c 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -263,7 +263,7 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io, extern char wild_many,wild_one,wild_prefix; extern const char *charsets_dir; extern char *defaults_extra_file; -extern const char *defaults_instance; +extern const char *defaults_group_suffix; extern my_bool timed_mutexes; @@ -553,7 +553,6 @@ extern gptr my_once_alloc(uint Size,myf MyFlags); extern void my_once_free(void); extern char *my_once_strdup(const char *src,myf myflags); extern char *my_once_memdup(const char *src, uint len, myf myflags); -extern my_string my_tempnam(const char *dir,const char *pfx,myf MyFlags); extern File my_open(const char *FileName,int Flags,myf MyFlags); extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, @@ -785,8 +784,9 @@ extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, extern char *strdup_root(MEM_ROOT *root,const char *str); extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); -extern void get_defaults_files(int argc, char **argv, - char **defaults, char **extra_defaults); +extern int get_defaults_options(int argc, char **argv, + char **defaults, char **extra_defaults, + char **group_suffix); extern int load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv); extern int modify_defaults_file(const char *file_location, const char *option, diff --git a/include/my_time.h b/include/my_time.h index 8058df8fe4e..aa68a6f0bbd 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -53,7 +53,7 @@ enum enum_mysql_timestamp_type str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint flags, int *was_cut); longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res, - my_bool fuzzy_date, int *was_cut); + uint flags, int *was_cut); ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *time); ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *time); ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *time); diff --git a/include/myisam.h b/include/myisam.h index 7d3f0e0c801..03194fe42ae 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -35,14 +35,26 @@ extern "C" { /* defines used by myisam-funktions */ -/* The following defines can be increased if necessary */ -#define MI_MAX_KEY 64 /* Max allowed keys */ -#define MI_MAX_KEY_SEG 16 /* Max segments for key */ -#define MI_MAX_KEY_LENGTH 1000 +/* + There is a hard limit for the maximum number of keys as there are only + 8 bits in the index file header for the number of keys in a table. + This means that 0..255 keys can exist for a table. The idea of + MI_MAX_POSSIBLE_KEY is to ensure that one can use myisamchk & tools on + a MyISAM table for which one has more keys than MyISAM is normally + compiled for. If you don't have this, you will get a core dump when + running myisamchk compiled for 128 keys on a table with 255 keys. +*/ +#define MI_MAX_POSSIBLE_KEY 255 /* For myisam_chk */ +#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */ +/* + The following defines can be increased if necessary. + BUT: MI_MAX_KEY must be <= MI_MAX_POSSIBLE_KEY. +*/ +#define MI_MAX_KEY 64 /* Max allowed keys */ +#define MI_MAX_KEY_SEG 16 /* Max segments for key */ +#define MI_MAX_KEY_LENGTH 1000 #define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8) -#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */ -#define MI_MAX_POSSIBLE_KEY 64 /* For myisam_chk */ #define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */ #define MI_NAME_IEXT ".MYI" #define MI_NAME_DEXT ".MYD" @@ -56,6 +68,63 @@ extern "C" { #define mi_portable_sizeof_char_ptr 8 +/* + In the following macros '_keyno_' is 0 .. keys-1. + If there can be more keys than bits in the key_map, the highest bit + is for all upper keys. They cannot be switched individually. + This means that clearing of high keys is ignored, setting one high key + sets all high keys. +*/ +#define MI_KEYMAP_BITS (8 * SIZEOF_LONG_LONG) +#define MI_KEYMAP_HIGH_MASK (ULL(1) << (MI_KEYMAP_BITS - 1)) +#define mi_get_mask_all_keys_active(_keys_) \ + (((_keys_) < MI_KEYMAP_BITS) ? \ + ((ULL(1) << (_keys_)) - ULL(1)) : \ + (~ ULL(0))) + +#if MI_MAX_KEY > MI_KEYMAP_BITS + +#define mi_is_key_active(_keymap_,_keyno_) \ + (((_keyno_) < MI_KEYMAP_BITS) ? \ + test((_keymap_) & (ULL(1) << (_keyno_))) : \ + test((_keymap_) & MI_KEYMAP_HIGH_MASK)) +#define mi_set_key_active(_keymap_,_keyno_) \ + (_keymap_)|= (((_keyno_) < MI_KEYMAP_BITS) ? \ + (ULL(1) << (_keyno_)) : \ + MI_KEYMAP_HIGH_MASK) +#define mi_clear_key_active(_keymap_,_keyno_) \ + (_keymap_)&= (((_keyno_) < MI_KEYMAP_BITS) ? \ + (~ (ULL(1) << (_keyno_))) : \ + (~ (ULL(0))) /*ignore*/ ) + +#else + +#define mi_is_key_active(_keymap_,_keyno_) \ + test((_keymap_) & (ULL(1) << (_keyno_))) +#define mi_set_key_active(_keymap_,_keyno_) \ + (_keymap_)|= (ULL(1) << (_keyno_)) +#define mi_clear_key_active(_keymap_,_keyno_) \ + (_keymap_)&= (~ (ULL(1) << (_keyno_))) + +#endif + +#define mi_is_any_key_active(_keymap_) \ + test((_keymap_)) +#define mi_is_all_keys_active(_keymap_,_keys_) \ + ((_keymap_) == mi_get_mask_all_keys_active(_keys_)) +#define mi_set_all_keys_active(_keymap_,_keys_) \ + (_keymap_)= mi_get_mask_all_keys_active(_keys_) +#define mi_clear_all_keys_active(_keymap_) \ + (_keymap_)= 0 +#define mi_intersect_keys_active(_to_,_from_) \ + (_to_)&= (_from_) +#define mi_is_any_intersect_keys_active(_keymap1_,_keys_,_keymap2_) \ + ((_keymap1_) & (_keymap2_) & \ + mi_get_mask_all_keys_active(_keys_)) +#define mi_copy_keys_active(_to_,_maxkeys_,_from_) \ + (_to_)= (mi_get_mask_all_keys_active(_maxkeys_) & \ + (_from_)) + /* Param to/from mi_info */ typedef struct st_mi_isaminfo /* Struct from h_info */ diff --git a/include/thr_lock.h b/include/thr_lock.h index dc4f9968cb7..251d8e7c9cf 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -62,17 +62,45 @@ enum thr_lock_type { TL_IGNORE=-1, /* Abort new lock request with an error */ TL_WRITE_ONLY}; +enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1, + THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 }; + + extern ulong max_write_lock_count; +extern ulong table_lock_wait_timeout; extern my_bool thr_lock_inited; extern enum thr_lock_type thr_upgraded_concurrent_insert_lock; -typedef struct st_thr_lock_data { +/* + A description of the thread which owns the lock. The address + of an instance of this structure is used to uniquely identify the thread. +*/ + +typedef struct st_thr_lock_info +{ pthread_t thread; + ulong thread_id; + ulong n_cursors; +} THR_LOCK_INFO; + +/* + Lock owner identifier. Globally identifies the lock owner within the + thread and among all the threads. The address of an instance of this + structure is used as id. +*/ + +typedef struct st_thr_lock_owner +{ + THR_LOCK_INFO *info; +} THR_LOCK_OWNER; + + +typedef struct st_thr_lock_data { + THR_LOCK_OWNER *owner; struct st_thr_lock_data *next,**prev; struct st_thr_lock *lock; pthread_cond_t *cond; enum thr_lock_type type; - ulong thread_id; void *status_param; /* Param to status functions */ void *debug_print_param; } THR_LOCK_DATA; @@ -102,16 +130,21 @@ extern LIST *thr_lock_thread_list; extern pthread_mutex_t THR_LOCK_lock; my_bool init_thr_lock(void); /* Must be called once/thread */ +#define thr_lock_owner_init(owner, info_arg) (owner)->info= (info_arg) +void thr_lock_info_init(THR_LOCK_INFO *info); void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *status_param); -int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type); +enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, + THR_LOCK_OWNER *owner, + enum thr_lock_type lock_type); void thr_unlock(THR_LOCK_DATA *data); -int thr_multi_lock(THR_LOCK_DATA **data,uint count); +enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, + uint count, THR_LOCK_OWNER *owner); void thr_multi_unlock(THR_LOCK_DATA **data,uint count); void thr_abort_locks(THR_LOCK *lock); -void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread); +my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread); void thr_print_locks(void); /* For debugging */ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data); my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data); diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 362e3552411..adbc4afafd2 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -19,7 +19,9 @@ Created 10/21/1995 Heikki Tuuri typedef struct fil_node_struct fil_node_t; +#ifdef UNIV_DO_FLUSH extern ibool os_do_not_call_flush_at_each_write; +#endif /* UNIV_DO_FLUSH */ extern ibool os_has_said_disk_full; extern ibool os_aio_print_debug; diff --git a/innobase/include/read0read.h b/innobase/include/read0read.h index db6bf888095..1a7a86470a8 100644 --- a/innobase/include/read0read.h +++ b/innobase/include/read0read.h @@ -69,6 +69,35 @@ read_view_print( /*============*/ read_view_t* view); /* in: read view */ +/************************************************************************* +Create a consistent cursor view for mysql to be used in cursors. In this +consistent read view modifications done by the creating transaction or future +transactions are not visible. */ + +cursor_view_t* +read_cursor_view_create_for_mysql( +/*==============================*/ + trx_t* cr_trx);/* in: trx where cursor view is created */ + +/************************************************************************* +Close a given consistent cursor view for and restore global read view +back to a transaction. */ + +void +read_cursor_view_close_for_mysql( +/*=============================*/ + trx_t* trx, /* in: trx */ + cursor_view_t* curview); /* in: cursor view to be closed */ +/************************************************************************* +This function sets a given consistent cursor view to a transaction +read view if given consistent cursor view is not null. Otherwice, function +restores a global read view to a transaction read view. */ + +void +read_cursor_set_for_mysql( +/*======================*/ + trx_t* trx, /* in: transaction where cursor is set */ + cursor_view_t* curview);/* in: consistent cursor view to be set */ /* Read view lists the trx ids of those transactions for which a consistent read should not see the modifications to the database. */ @@ -100,6 +129,17 @@ struct read_view_struct{ /* List of read views in trx_sys */ }; +/* Implement InnoDB framework to support consistent read views in +cursors. This struct holds both heap where consistent read view +is allocated and pointer to a read view. */ + +struct cursor_view_struct{ + mem_heap_t* heap; + /* Memory heap for the cursor view */ + read_view_t* read_view; + /* Consistent read view of the cursor*/ +}; + #ifndef UNIV_NONINL #include "read0read.ic" #endif diff --git a/innobase/include/read0types.h b/innobase/include/read0types.h index 5eb3e533f89..7d42728523e 100644 --- a/innobase/include/read0types.h +++ b/innobase/include/read0types.h @@ -10,5 +10,6 @@ Created 2/16/1997 Heikki Tuuri #define read0types_h typedef struct read_view_struct read_view_t; +typedef struct cursor_view_struct cursor_view_t; #endif diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h index c798c047fa3..5955ab9a06a 100644 --- a/innobase/include/sync0sync.h +++ b/innobase/include/sync0sync.h @@ -522,10 +522,11 @@ extern ibool sync_order_checks_on; extern ibool sync_initialized; /* Global list of database mutexes (not OS mutexes) created. */ -UT_LIST_BASE_NODE_T(mutex_t) mutex_list; +typedef UT_LIST_BASE_NODE_T(mutex_t) ut_list_base_node_t; +extern ut_list_base_node_t mutex_list; /* Mutex protecting the mutex_list variable */ -mutex_t mutex_list_mutex; +extern mutex_t mutex_list_mutex; #ifndef UNIV_NONINL diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 146730d46f8..2fc4d5a289f 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -602,8 +602,19 @@ struct trx_struct{ UT_LIST_BASE_NODE_T(lock_t) trx_locks; /* locks reserved by the transaction */ /*------------------------------*/ - mem_heap_t* read_view_heap; /* memory heap for the read view */ - read_view_t* read_view; /* consistent read view or NULL */ + mem_heap_t* global_read_view_heap; + /* memory heap for the global read + view */ + read_view_t* global_read_view; + /* consistent read view used in the + transaction is stored here if + transaction is using a consistent + read view associated to a cursor */ + read_view_t* read_view; /* consistent read view used in the + transaction or NULL, this read view + can be normal read view associated + to a transaction or read view + associated to a cursor */ /*------------------------------*/ UT_LIST_BASE_NODE_T(trx_named_savept_t) trx_savepoints; /* savepoints set with SAVEPOINT ..., diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 48dc808e36c..9c87b59f018 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -40,9 +40,13 @@ ulint os_innodb_umask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; ulint os_innodb_umask = 0; #endif +#ifdef UNIV_DO_FLUSH /* If the following is set to TRUE, we do not call os_file_flush in every os_file_write. We can set this TRUE when the doublewrite buffer is used. */ ibool os_do_not_call_flush_at_each_write = FALSE; +#else +/* We do not call os_file_flush in every os_file_write. */ +#endif /* UNIV_DO_FLUSH */ /* We use these mutexes to protect lseek + file i/o operation, if the OS does not provide an atomic pread or pwrite, or similar */ @@ -1985,6 +1989,7 @@ os_file_pwrite( os_file_n_pending_pwrites--; os_mutex_exit(os_file_count_mutex); +# ifdef UNIV_DO_FLUSH if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && !os_do_not_call_flush_at_each_write) { @@ -1995,6 +2000,7 @@ os_file_pwrite( ut_a(TRUE == os_file_flush(file)); } +# endif /* UNIV_DO_FLUSH */ return(ret); #else @@ -2017,6 +2023,7 @@ os_file_pwrite( ret = write(file, buf, (ssize_t)n); +# ifdef UNIV_DO_FLUSH if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && !os_do_not_call_flush_at_each_write) { @@ -2027,6 +2034,7 @@ os_file_pwrite( ut_a(TRUE == os_file_flush(file)); } +# endif /* UNIV_DO_FLUSH */ os_mutex_exit(os_file_seek_mutexes[i]); @@ -2313,9 +2321,11 @@ retry: /* Always do fsync to reduce the probability that when the OS crashes, a database page is only partially physically written to disk. */ +# ifdef UNIV_DO_FLUSH if (!os_do_not_call_flush_at_each_write) { ut_a(TRUE == os_file_flush(file)); } +# endif /* UNIV_DO_FLUSH */ os_mutex_exit(os_file_seek_mutexes[i]); @@ -3533,10 +3543,12 @@ os_aio_windows_handle( if (ret && len == slot->len) { ret_val = TRUE; +# ifdef UNIV_DO_FLUSH if (slot->type == OS_FILE_WRITE && !os_do_not_call_flush_at_each_write) { ut_a(TRUE == os_file_flush(slot->file)); } +# endif /* UNIV_DO_FLUSH */ } else { os_file_handle_error(slot->name, "Windows aio"); @@ -3617,10 +3629,12 @@ os_aio_posix_handle( *message1 = slot->message1; *message2 = slot->message2; +# ifdef UNIV_DO_FLUSH if (slot->type == OS_FILE_WRITE && !os_do_not_call_flush_at_each_write) { ut_a(TRUE == os_file_flush(slot->file)); } +# endif /* UNIV_DO_FLUSH */ os_mutex_exit(array->mutex); diff --git a/innobase/read/read0read.c b/innobase/read/read0read.c index 0c4a037508e..76df7cdbee0 100644 --- a/innobase/read/read0read.c +++ b/innobase/read/read0read.c @@ -212,15 +212,16 @@ read_view_close_for_mysql( /*======================*/ trx_t* trx) /* in: trx which has a read view */ { - ut_a(trx->read_view); + ut_a(trx->global_read_view); mutex_enter(&kernel_mutex); - read_view_close(trx->read_view); + read_view_close(trx->global_read_view); - mem_heap_empty(trx->read_view_heap); + mem_heap_empty(trx->global_read_view_heap); trx->read_view = NULL; + trx->global_read_view = NULL; mutex_exit(&kernel_mutex); } @@ -258,3 +259,137 @@ read_view_print( (ulong) ut_dulint_get_low(read_view_get_nth_trx_id(view, i))); } } + +/************************************************************************* +Create a consistent cursor view for mysql to be used in cursors. In this +consistent read view modifications done by the creating transaction or future +transactions are not visible. */ + +cursor_view_t* +read_cursor_view_create_for_mysql( +/*==============================*/ + trx_t* cr_trx) /* in: trx where cursor view is created */ +{ + cursor_view_t* curview; + read_view_t* view; + mem_heap_t* heap; + trx_t* trx; + ulint n; + + ut_a(cr_trx); + + /* Use larger heap than in trx_create when creating a read_view + because cursors are quite long. */ + + heap = mem_heap_create(512); + + curview = (cursor_view_t*) mem_heap_alloc(heap, sizeof(cursor_view_t)); + curview->heap = heap; + + mutex_enter(&kernel_mutex); + + curview->read_view = read_view_create_low( + UT_LIST_GET_LEN(trx_sys->trx_list), + curview->heap); + + view = curview->read_view; + view->creator = cr_trx; + + /* No future transactions should be visible in the view */ + + view->low_limit_no = trx_sys->max_trx_id; + view->low_limit_id = view->low_limit_no; + + view->can_be_too_old = FALSE; + + n = 0; + trx = UT_LIST_GET_FIRST(trx_sys->trx_list); + + /* No active transaction should be visible, not even cr_trx !*/ + + while (trx) { + if (trx->conc_state == TRX_ACTIVE || + trx->conc_state == TRX_PREPARED) { + + read_view_set_nth_trx_id(view, n, trx->id); + + n++; + + /* NOTE that a transaction whose trx number is < + trx_sys->max_trx_id can still be active, if it is + in the middle of its commit! Note that when a + transaction starts, we initialize trx->no to + ut_dulint_max. */ + + if (ut_dulint_cmp(view->low_limit_no, trx->no) > 0) { + + view->low_limit_no = trx->no; + } + } + + trx = UT_LIST_GET_NEXT(trx_list, trx); + } + + view->n_trx_ids = n; + + if (n > 0) { + /* The last active transaction has the smallest id: */ + view->up_limit_id = read_view_get_nth_trx_id(view, n - 1); + } else { + view->up_limit_id = view->low_limit_id; + } + + UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view); + + mutex_exit(&kernel_mutex); + + return(curview); +} + +/************************************************************************* +Close a given consistent cursor view for and restore global read view +back to a transaction. */ + +void +read_cursor_view_close_for_mysql( +/*=============================*/ + trx_t* trx, /* in: trx */ + cursor_view_t* curview)/* in: cursor view to be closed */ +{ + ut_a(curview); + ut_a(curview->read_view); + ut_a(curview->heap); + + mutex_enter(&kernel_mutex); + + read_view_close(curview->read_view); + trx->read_view = trx->global_read_view; + + mutex_exit(&kernel_mutex); + + mem_heap_free(curview->heap); +} + +/************************************************************************* +This function sets a given consistent cursor view to a transaction +read view if given consistent cursor view is not null. Otherwice, function +restores a global read view to a transaction read view. */ + +void +read_cursor_set_for_mysql( +/*======================*/ + trx_t* trx, /* in: transaction where cursor is set */ + cursor_view_t* curview)/* in: consistent cursor view to be set */ +{ + ut_a(trx); + + mutex_enter(&kernel_mutex); + + if (UNIV_LIKELY(curview != NULL)) { + trx->read_view = curview->read_view; + } else { + trx->read_view = trx->global_read_view; + } + + mutex_exit(&kernel_mutex); +} diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 15439bed7e7..0b563eb147e 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2524,13 +2524,21 @@ row_sel_store_mysql_rec( (byte) (templ->mysql_null_bit_mask); switch (templ->type) { case DATA_VARCHAR: - case DATA_CHAR: case DATA_BINARY: + case DATA_VARMYSQL: + if (templ->mysql_type + == DATA_MYSQL_TRUE_VARCHAR) { + /* This is a >= 5.0.3 type + true VARCHAR. Zero the field. */ + pad_char = 0x00; + break; + } + /* Fall through */ + case DATA_CHAR: case DATA_FIXBINARY: case DATA_MYSQL: - case DATA_VARMYSQL: - /* MySQL pads all non-BLOB and non-TEXT - string types with space ' ' */ + /* MySQL pads all string types (except + BLOB, TEXT and true VARCHAR) with space. */ if (UNIV_UNLIKELY(templ->mbminlen == 2)) { /* Treat UCS2 as a special case. */ data = mysql_rec @@ -4083,6 +4091,11 @@ normal_return: } func_exit: + /* Restore a global read view back to transaction. This forces + MySQL always to set cursor view before fetch if it is used. */ + + trx->read_view = trx->global_read_view; + trx->op_info = ""; if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); @@ -4136,7 +4149,8 @@ row_search_check_if_query_cache_permitted( && !trx->read_view) { trx->read_view = read_view_open_now(trx, - trx->read_view_heap); + trx->global_read_view_heap); + trx->global_read_view = trx->read_view; } } diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index f0f0e9a3a2e..43249f4b96f 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -141,6 +141,12 @@ sync_thread_t* sync_thread_level_arrays; /* Mutex protecting sync_thread_level_arrays */ mutex_t sync_thread_mutex; +/* Global list of database mutexes (not OS mutexes) created. */ +ut_list_base_node_t mutex_list; + +/* Mutex protecting the mutex_list variable */ +mutex_t mutex_list_mutex; + /* Latching order checks start when this is set TRUE */ ibool sync_order_checks_on = FALSE; diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 68fe6d5079a..bf48c30e942 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -97,8 +97,9 @@ trx_doublewrite_init( /* Since we now start to use the doublewrite buffer, no need to call fsync() after every write to a data file */ - +#ifdef UNIV_DO_FLUSH os_do_not_call_flush_at_each_write = TRUE; +#endif /* UNIV_DO_FLUSH */ mutex_create(&(trx_doublewrite->mutex)); mutex_set_level(&(trx_doublewrite->mutex), SYNC_DOUBLEWRITE); diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 10fbf3468c0..f95491443ee 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -159,7 +159,8 @@ trx_create( trx->auto_inc_lock = NULL; - trx->read_view_heap = mem_heap_create(256); + trx->global_read_view_heap = mem_heap_create(256); + trx->global_read_view = NULL; trx->read_view = NULL; /* Set X/Open XA transaction identification to NULL */ @@ -318,10 +319,12 @@ trx_free( ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); - if (trx->read_view_heap) { - mem_heap_free(trx->read_view_heap); + if (trx->global_read_view_heap) { + mem_heap_free(trx->global_read_view_heap); } + trx->global_read_view = NULL; + ut_a(trx->read_view == NULL); mem_free(trx); @@ -831,10 +834,23 @@ trx_commit_off_kernel( lock_release_off_kernel(trx); if (trx->read_view) { + /* If transaction has a global read view this case + means that transaction has been using a consistent + read view associated to a cursor. Only the global + read view associated to a transaction is closed + and read view is then removed from the transaction. + If read view associated to a cursor is still used + it must be re-registered to another transaction. */ + + if (UNIV_LIKELY_NULL(trx->global_read_view)) { + trx->read_view = trx->global_read_view; + } + read_view_close(trx->read_view); - mem_heap_empty(trx->read_view_heap); + mem_heap_empty(trx->global_read_view_heap); trx->read_view = NULL; + trx->global_read_view = NULL; } if (must_flush_log) { @@ -964,7 +980,9 @@ trx_assign_read_view( mutex_enter(&kernel_mutex); if (!trx->read_view) { - trx->read_view = read_view_open_now(trx, trx->read_view_heap); + trx->read_view = read_view_open_now(trx, + trx->global_read_view_heap); + trx->global_read_view = trx->read_view; } mutex_exit(&kernel_mutex); diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index a2bfa616f6b..fab1a402c1e 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -84,6 +84,7 @@ CLEANFILES = $(target_libadd) $(SHLIBOBJS) \ DEFS = -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \ -DDATADIR="\"$(MYSQLDATAdir)\"" \ -DDEFAULT_HOME_ENV=MYSQL_HOME \ + -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" $(target_defs) # The automatic dependencies miss this diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index f9ddf7fa665..3931d7947aa 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1599,13 +1599,8 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, ulong length) { if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) - { return escape_quotes_for_mysql(mysql->charset, to, 0, from, length); - } - else - { - return escape_string_for_mysql(mysql->charset, to, 0, from, length); - } + return escape_string_for_mysql(mysql->charset, to, 0, from, length); } @@ -3585,7 +3580,7 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value, case MYSQL_TYPE_TIMESTAMP: { MYSQL_TIME *tm= (MYSQL_TIME *)buffer; - (void) str_to_datetime(value, length, tm, 0, &err); + (void) str_to_datetime(value, length, tm, TIME_FUZZY_DATE, &err); *param->error= test(err) && (param->buffer_type == MYSQL_TYPE_DATE && tm->time_type != MYSQL_TIMESTAMP_DATE); break; @@ -3703,7 +3698,8 @@ static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field, case MYSQL_TYPE_DATETIME: { int error; - value= number_to_datetime(value, (MYSQL_TIME *) buffer, 1, &error); + value= number_to_datetime(value, (MYSQL_TIME *) buffer, TIME_FUZZY_DATE, + &error); *param->error= test(error); break; } diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 0688ea5732b..5d8c2309063 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -148,7 +148,8 @@ EXPORTS mysql_embedded mysql_server_init mysql_server_end + get_defaults_files mysql_set_character_set mysql_get_character_set_info - get_defaults_files + get_defaults_options modify_defaults_file diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index c3b239ac7b9..a86d467299c 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -502,6 +502,8 @@ void *create_embedded_thd(int client_flag, char *db) /* TODO - add init_connect command execution */ + if (thd->variables.max_join_size == HA_POS_ERROR) + thd->options |= OPTION_BIG_SELECTS; thd->proc_info=0; // Remove 'login' thd->command=COM_SLEEP; thd->version=refresh_version; diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index dcb14e95d36..93456901a7d 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -158,7 +158,7 @@ EXPORTS mysql_stmt_attr_get mysql_stmt_attr_set mysql_stmt_field_count - get_defaults_files + get_defaults_options my_charset_bin my_charset_same modify_defaults_file diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 9e003a18dac..1db829808a9 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -282,7 +282,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info) if ((skr=(my_off_t) info->state->key_file_length) != size) { /* Don't give error if file generated by myisampack */ - if (skr > size && info->s->state.key_map) + if (skr > size && mi_is_any_key_active(info->s->state.key_map)) { error=1; mi_check_print_error(param, @@ -379,7 +379,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++) { param->key_crc[key]=0; - if (!(((ulonglong) 1 << key) & share->state.key_map)) + if (! mi_is_key_active(share->state.key_map, key)) { /* Remember old statistics for key */ memcpy((char*) rec_per_key_part, @@ -507,7 +507,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) (int) ((my_off_t2double(key_totlength) - my_off_t2double(all_keydata))*100.0/ my_off_t2double(key_totlength))); - else if (all_totaldata != 0L && share->state.key_map) + else if (all_totaldata != 0L && mi_is_any_key_active(share->state.key_map)) puts(""); } if (param->key_file_blocks != info->state->key_file_length && @@ -1034,7 +1034,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) for (key=0,keyinfo= info->s->keyinfo; key < info->s->base.keys; key++,keyinfo++) { - if ((((ulonglong) 1 << key) & info->s->state.key_map)) + if (mi_is_key_active(info->s->state.key_map, key)) { if(!(keyinfo->flag & HA_FULLTEXT)) { @@ -1298,8 +1298,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, */ if (param->testflag & T_CREATE_MISSING_KEYS) - share->state.key_map= ((((ulonglong) 1L << share->base.keys)-1) & - param->keys_in_use); + mi_copy_keys_active(share->state.key_map, share->base.keys, + param->keys_in_use); info->state->key_file_length=share->base.keystart; @@ -1461,7 +1461,7 @@ static int writekeys(MI_CHECK *param, register MI_INFO *info, byte *buff, key=info->lastkey+info->s->base.max_key_length; for (i=0 ; i < info->s->base.keys ; i++) { - if (((ulonglong) 1 << i) & info->s->state.key_map) + if (mi_is_key_active(info->s->state.key_map, i)) { if (info->s->keyinfo[i].flag & HA_FULLTEXT ) { @@ -1492,7 +1492,7 @@ static int writekeys(MI_CHECK *param, register MI_INFO *info, byte *buff, info->errkey=(int) i; /* This key was found */ while ( i-- > 0 ) { - if (((ulonglong) 1 << i) & info->s->state.key_map) + if (mi_is_key_active(info->s->state.key_map, i)) { if (info->s->keyinfo[i].flag & HA_FULLTEXT) { @@ -1529,7 +1529,7 @@ int movepoint(register MI_INFO *info, byte *record, my_off_t oldpos, key=info->lastkey+info->s->base.max_key_length; for (i=0 ; i < info->s->base.keys; i++) { - if (i != prot_key && (((ulonglong) 1 << i) & info->s->state.key_map)) + if (i != prot_key && mi_is_key_active(info->s->state.key_map, i)) { key_length=_mi_make_key(info,i,key,record,oldpos); if (info->s->keyinfo[i].flag & HA_NOSAME) @@ -1628,7 +1628,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ; key++,keyinfo++) { - if (!(((ulonglong) 1 << key) & share->state.key_map)) + if (! mi_is_key_active(info->s->state.key_map, key)) continue; if (share->state.key_root[key] != HA_OFFSET_ERROR) @@ -2023,7 +2023,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.read_cache=param->read_cache; sort_param.keyinfo=share->keyinfo+sort_param.key; sort_param.seg=sort_param.keyinfo->seg; - if (!(((ulonglong) 1 << sort_param.key) & key_map)) + if (! mi_is_key_active(key_map, sort_param.key)) { /* Remember old statistics for key */ memcpy((char*) rec_per_key_part, @@ -2084,7 +2084,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, if (param->testflag & T_STATISTICS) update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique, (ulonglong) info->state->records); - share->state.key_map|=(ulonglong) 1 << sort_param.key; + mi_set_key_active(share->state.key_map, sort_param.key); if (sort_param.fix_datafile) { @@ -2405,7 +2405,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].key=key; sort_param[i].keyinfo=share->keyinfo+key; sort_param[i].seg=sort_param[i].keyinfo->seg; - if (!(((ulonglong) 1 << key) & key_map)) + if (! mi_is_key_active(key_map, key)) { /* Remember old statistics for key */ memcpy((char*) rec_per_key_part, @@ -3917,8 +3917,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, { byte *record; if (!info->s->base.auto_key || - !(((ulonglong) 1 << (info->s->base.auto_key-1) - & info->s->state.key_map))) + ! mi_is_key_active(info->s->state.key_map, info->s->base.auto_key - 1)) { if (!(param->testflag & T_VERY_SILENT)) mi_check_print_info(param, @@ -4070,7 +4069,7 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows) if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) && ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1) { - share->state.key_map&= ~ ((ulonglong) 1 << i); + mi_clear_key_active(share->state.key_map, i); info->update|= HA_STATE_CHANGED; } } @@ -4094,7 +4093,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, mi_repair_by_sort only works if we have at least one key. If we don't have any keys, we should use the normal repair. */ - if (!key_map) + if (! mi_is_any_key_active(key_map)) return FALSE; /* Can't use sort */ for (i=0 ; i < share->base.keys ; i++,key++) { diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 33b344405ec..6d4106afda5 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -251,9 +251,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* called by myisamchk - i.e. table structure was taken from MYI file and SPATIAL key *does have* additional sp_segs keysegs. - We'd better delete them now + keydef->seg here points right at the GEOMETRY segment, + so we only need to decrease keydef->keysegs. + (see recreate_table() in mi_check.c) */ - keydef->keysegs-=sp_segs; + keydef->keysegs-=sp_segs-1; } for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ; @@ -508,7 +510,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, mi_int2store(share.state.header.key_parts,key_segs); mi_int2store(share.state.header.unique_key_parts,unique_key_parts); - share.state.key_map = ((ulonglong) 1 << keys)-1; + mi_set_all_keys_active(share.state.key_map, keys); share.base.keystart = share.state.state.key_file_length= MY_ALIGN(info_length, myisam_block_size); share.base.max_key_block_length=max_key_block_length; diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index cc4a17182f7..60a07254e82 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -74,7 +74,7 @@ int mi_delete(MI_INFO *info,const byte *record) old_key=info->lastkey2; for (i=0 ; i < share->base.keys ; i++ ) { - if (((ulonglong) 1 << i) & info->s->state.key_map) + if (mi_is_key_active(info->s->state.key_map, i)) { info->s->keyinfo[i].version++; if (info->s->keyinfo[i].flag & HA_FULLTEXT ) diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index ba32bb9115a..bfe1748af01 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -244,7 +244,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) error=1; /* Not possibly if not lock */ break; } - if (share->state.key_map) + if (mi_is_any_key_active(share->state.key_map)) { MI_KEYDEF *key=share->keyinfo; uint i; @@ -252,7 +252,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) { if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) { - share->state.key_map&= ~ ((ulonglong) 1 << i); + mi_clear_key_active(share->state.key_map, i); info->update|= HA_STATE_CHANGED; } } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 74b97a65609..82663e0c318 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -192,14 +192,14 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) } share->state_diff_length=len-MI_STATE_INFO_SIZE; - mi_state_info_read(disk_cache, &share->state); + mi_state_info_read((uchar*) disk_cache, &share->state); len= mi_uint2korr(share->state.header.base_info_length); if (len != MI_BASE_INFO_SIZE) { DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d", len,MI_BASE_INFO_SIZE)) } - disk_pos=my_n_base_info_read(disk_cache+base_pos, &share->base); + disk_pos=my_n_base_info_read((uchar*) disk_cache + base_pos, &share->base); share->state.state_length=base_pos; if (!(open_flags & HA_OPEN_FOR_REPAIR) && @@ -863,7 +863,7 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite) } -char *mi_state_info_read(char *ptr, MI_STATE_INFO *state) +char *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state) { uint i,keys,key_parts,key_blocks; memcpy_fixed(&state->header,ptr, sizeof(state->header)); @@ -929,7 +929,7 @@ uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead) } else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) return (MY_FILE_ERROR); - mi_state_info_read(buff, state); + mi_state_info_read((uchar*) buff, state); } return 0; } @@ -974,7 +974,7 @@ uint mi_base_info_write(File file, MI_BASE_INFO *base) } -char *my_n_base_info_read(char *ptr, MI_BASE_INFO *base) +char *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base) { base->keystart = mi_sizekorr(ptr); ptr +=8; base->max_data_file_length = mi_sizekorr(ptr); ptr +=8; @@ -1204,7 +1204,7 @@ int mi_disable_indexes(MI_INFO *info) { MYISAM_SHARE *share= info->s; - share->state.key_map= 0; + mi_clear_all_keys_active(share->state.key_map); return 0; } @@ -1240,7 +1240,7 @@ int mi_enable_indexes(MI_INFO *info) error= HA_ERR_CRASHED; } else - share->state.key_map= ((ulonglong) 1L << share->base.keys) - 1; + mi_set_all_keys_active(share->state.key_map, share->base.keys); return error; } @@ -1265,6 +1265,6 @@ int mi_indexes_are_disabled(MI_INFO *info) { MYISAM_SHARE *share= info->s; - return (! share->state.key_map && share->base.keys); + return (! mi_is_any_key_active(share->state.key_map) && share->base.keys); } diff --git a/myisam/mi_preload.c b/myisam/mi_preload.c index 317ab4ad7fe..d63399b519d 100644 --- a/myisam/mi_preload.c +++ b/myisam/mi_preload.c @@ -51,7 +51,7 @@ int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves) my_off_t pos= share->base.keystart; DBUG_ENTER("mi_preload"); - if (!keys || !key_map || key_file_length == pos) + if (!keys || !mi_is_any_key_active(key_map) || key_file_length == pos) DBUG_RETURN(0); block_length= keyinfo[0].block_length; diff --git a/myisam/mi_rsame.c b/myisam/mi_rsame.c index 56c8d1226ca..321097744b9 100644 --- a/myisam/mi_rsame.c +++ b/myisam/mi_rsame.c @@ -30,7 +30,7 @@ int mi_rsame(MI_INFO *info, byte *record, int inx) { DBUG_ENTER("mi_rsame"); - if (inx != -1 && ! (((ulonglong) 1 << inx) & info->s->state.key_map)) + if (inx != -1 && ! mi_is_key_active(info->s->state.key_map, inx)) { DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX); } diff --git a/myisam/mi_rsamepos.c b/myisam/mi_rsamepos.c index a1d96fb7104..35cdd41e297 100644 --- a/myisam/mi_rsamepos.c +++ b/myisam/mi_rsamepos.c @@ -32,7 +32,7 @@ int mi_rsame_with_pos(MI_INFO *info, byte *record, int inx, my_off_t filepos) { DBUG_ENTER("mi_rsame_with_pos"); - if (inx < -1 || ! (((ulonglong) 1 << inx) & info->s->state.key_map)) + if (inx < -1 || ! mi_is_key_active(info->s->state.key_map, inx)) { DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX); } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index c669a8be8f8..ed61bbfe41a 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -29,7 +29,7 @@ int _mi_check_index(MI_INFO *info, int inx) { if (inx == -1) /* Use last index */ inx=info->lastinx; - if (inx < 0 || ! (((ulonglong) 1 << inx) & info->s->state.key_map)) + if (inx < 0 || ! mi_is_key_active(info->s->state.key_map, inx)) { my_errno=HA_ERR_WRONG_INDEX; return -1; diff --git a/myisam/mi_update.c b/myisam/mi_update.c index cda60694008..ab23f2e6da9 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -87,7 +87,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) changed=0; for (i=0 ; i < share->base.keys ; i++) { - if (((ulonglong) 1 << i) & share->state.key_map) + if (mi_is_key_active(share->state.key_map, i)) { if (share->keyinfo[i].flag & HA_FULLTEXT ) { diff --git a/myisam/mi_write.c b/myisam/mi_write.c index dd062b79769..c8f9aa84a41 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -101,7 +101,7 @@ int mi_write(MI_INFO *info, byte *record) buff=info->lastkey2; for (i=0 ; i < share->base.keys ; i++) { - if (((ulonglong) 1 << i) & share->state.key_map) + if (mi_is_key_active(share->state.key_map, i)) { bool local_lock_tree= (lock_tree && !(info->bulk_insert && @@ -175,7 +175,7 @@ err: info->errkey= (int) i; while ( i-- > 0) { - if (((ulonglong) 1 << i) & share->state.key_map) + if (mi_is_key_active(share->state.key_map, i)) { bool local_lock_tree= (lock_tree && !(info->bulk_insert && @@ -944,20 +944,21 @@ int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows) MI_KEYDEF *key=share->keyinfo; bulk_insert_param *params; uint i, num_keys, total_keylength; - ulonglong key_map=0; + ulonglong key_map; DBUG_ENTER("_mi_init_bulk_insert"); DBUG_PRINT("enter",("cache_size: %lu", cache_size)); DBUG_ASSERT(!info->bulk_insert && (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)); + mi_clear_all_keys_active(key_map); for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++) { - if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1 - && test(share->state.key_map & ((ulonglong) 1 << i))) + if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) && + mi_is_key_active(share->state.key_map, i)) { num_keys++; - key_map |=((ulonglong) 1 << i); + mi_set_key_active(key_map, i); total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE; } } @@ -981,7 +982,7 @@ int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows) params=(bulk_insert_param *)(info->bulk_insert+share->base.keys); for (i=0 ; i < share->base.keys ; i++) { - if (test(key_map & ((ulonglong) 1 << i))) + if (mi_is_key_active(key_map, i)) { params->info=info; params->keynr=i; diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 519e123e9da..4856d93b320 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -871,8 +871,8 @@ static int myisamchk(MI_CHECK *param, my_string filename) MI_STATE_INFO_SIZE || mi_uint2korr(share->state.header.base_info_length) != MI_BASE_INFO_SIZE || - ((param->keys_in_use & ~share->state.key_map) & - (((ulonglong) 1L << share->base.keys)-1)) || + mi_is_any_intersect_keys_active(param->keys_in_use, share->base.keys, + ~share->state.key_map) || test_if_almost_full(info) || info->s->state.header.file_version[3] != myisam_file_magic[3] || (set_collation && @@ -939,8 +939,8 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (param->testflag & T_REP_ANY) { ulonglong tmp=share->state.key_map; - share->state.key_map= (((ulonglong) 1 << share->base.keys)-1) - & param->keys_in_use; + mi_copy_keys_active(share->state.key_map, share->base.keys, + param->keys_in_use); if (tmp != share->state.key_map) info->update|=HA_STATE_CHANGED; } @@ -961,7 +961,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (!error) { if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) && - (share->state.key_map || + (mi_is_any_key_active(share->state.key_map) || (rep_quick && !param->keys_in_use && !recreate)) && mi_test_if_sort_rep(info, info->state->records, info->s->state.key_map, @@ -1037,7 +1037,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) llstr(info->state->records,llbuff), llstr(info->state->del,llbuff2)); error =chk_status(param,info); - share->state.key_map &=param->keys_in_use; + mi_intersect_keys_active(share->state.key_map, param->keys_in_use); error =chk_size(param,info); if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE))) error|=chk_del(param, info,param->testflag); @@ -1266,7 +1266,7 @@ static void descript(MI_CHECK *param, register MI_INFO *info, my_string name) } printf("Recordlength: %13d\n",(int) share->base.pack_reclength); - if (share->state.key_map != (((ulonglong) 1 << share->base.keys) -1)) + if (! mi_is_all_keys_active(share->state.key_map, share->base.keys)) { longlong2str(share->state.key_map,buff,2); printf("Using only keys '%s' of %d possibly keys\n", @@ -1448,7 +1448,7 @@ static int mi_sort_records(MI_CHECK *param, temp_buff=0; new_file= -1; - if (!(((ulonglong) 1 << sort_key) & share->state.key_map)) + if (! mi_is_key_active(share->state.key_map, sort_key)) { mi_check_print_warning(param, "Can't sort table '%s' on key %d; No such key", diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 5688b377d3d..74463ec065a 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -676,10 +676,10 @@ extern void _mi_unmap_file(MI_INFO *info); extern uint save_pack_length(byte *block_buff,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); +char *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state); uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead); uint mi_base_info_write(File file, MI_BASE_INFO *base); -char *my_n_base_info_read(char *ptr, MI_BASE_INFO *base); +char *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base); int mi_keyseg_write(File file, const HA_KEYSEG *keyseg); char *mi_keyseg_read(char *ptr, HA_KEYSEG *keyseg); uint mi_keydef_write(File file, MI_KEYDEF *keydef); diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index dc98d813266..de55b86252c 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -810,7 +810,7 @@ static int find_record_with_key(struct file_info *file_info, byte *record) for (key=0 ; key < info->s->base.keys ; key++) { - if ((((ulonglong) 1 << key) & info->s->state.key_map) && + if (mi_is_key_active(info->s->state.key_map, key) && info->s->keyinfo[key].flag & HA_NOSAME) { VOID(_mi_make_key(info,key,tmp_key,record,0L)); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index daf2bbdf85c..ba48cbf1b62 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -441,9 +441,9 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY))) goto error; - mrg->src_file_has_indexes_disabled|= ((mrg->file[i]->s->state.key_map != - (((ulonglong) 1) << - mrg->file[i]->s->base. keys) - 1)); + mrg->src_file_has_indexes_disabled|= + ! mi_is_all_keys_active(mrg->file[i]->s->state.key_map, + mrg->file[i]->s->base.keys); } /* Check that files are identical */ for (j=0 ; j < count-1 ; j++) @@ -2941,7 +2941,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.dellink= HA_OFFSET_ERROR; share->state.split=(ha_rows) mrg->records; share->state.version=(ulong) time((time_t*) 0); - if (share->state.key_map != (ULL(1) << share->base.keys) - 1) + if (! mi_is_all_keys_active(share->state.key_map, share->base.keys)) { /* Some indexes are disabled, cannot use current key_file_length value @@ -2955,7 +2955,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, original file so "myisamchk -rq" can use this value (this is necessary because index size cannot be easily calculated for fulltext keys) */ - share->state.key_map=0; + mi_clear_all_keys_active(share->state.key_map); for (key=0 ; key < share->base.keys ; key++) share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) @@ -2995,7 +2995,7 @@ static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length, } state.dellink= HA_OFFSET_ERROR; state.version=(ulong) time((time_t*) 0); - state.key_map=0; + mi_clear_all_keys_active(state.key_map); state.checksum=crc; if (isam_file->s->base.keys) isamchk_neaded=1; diff --git a/myisam/sort.c b/myisam/sort.c index 9d2af2e8c70..f2f8c8ef7ec 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -479,7 +479,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) } if (!got_error) { - share->state.key_map|=(ulonglong) 1 << sinfo->key; + mi_set_key_active(share->state.key_map, sinfo->key); if (param->testflag & T_STATISTICS) update_key_parts(sinfo->keyinfo, rec_per_key_part, sinfo->unique, (ulonglong) info->state->records); diff --git a/mysql-test/include/ctype_innodb_like.inc b/mysql-test/include/ctype_innodb_like.inc new file mode 100644 index 00000000000..ae43342885a --- /dev/null +++ b/mysql-test/include/ctype_innodb_like.inc @@ -0,0 +1,21 @@ +# +# Bug#11650: LIKE pattern matching using prefix index +# doesn't return correct result +# +--disable_warnings +# +# This query creates a column using +# character_set_connection and +# collation_connection. +# +create table t1 engine=innodb select repeat('a',50) as c1; +--enable_warnings +alter table t1 add index(c1(5)); + +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +select c1 from t1 where c1 like 'abcdef%' order by c1; +select c1 from t1 where c1 like 'abcde1%' order by c1; +select c1 from t1 where c1 like 'abcde11%' order by c1; +select c1 from t1 where c1 like 'abcde111%' order by c1; +drop table t1; diff --git a/mysql-test/include/federated.inc b/mysql-test/include/federated.inc new file mode 100644 index 00000000000..1c53b9ed2c5 --- /dev/null +++ b/mysql-test/include/federated.inc @@ -0,0 +1,21 @@ +--source ./include/have_federated_db.inc + +source ./include/master-slave.inc; + +# remote table creation + +connection slave; +--replicate-ignore-db=federated +stop slave; + +--disable_warnings +# at this point, we are connected to master +DROP DATABASE IF EXISTS federated; +--enable_warnings +CREATE DATABASE federated; + +connection master; +--disable_warnings +DROP DATABASE IF EXISTS federated; +--enable_warnings +CREATE DATABASE federated; diff --git a/mysql-test/include/federated_cleanup.inc b/mysql-test/include/federated_cleanup.inc new file mode 100644 index 00000000000..17a6e1e5100 --- /dev/null +++ b/mysql-test/include/federated_cleanup.inc @@ -0,0 +1,11 @@ +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +--enable_warnings + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +--enable_warnings diff --git a/mysql-test/include/have_gbk.inc b/mysql-test/include/have_gbk.inc new file mode 100644 index 00000000000..55805da0495 --- /dev/null +++ b/mysql-test/include/have_gbk.inc @@ -0,0 +1,4 @@ +-- require r/have_gbk.require +disable_query_log; +show collation like "gbk_chinese_ci"; +enable_query_log; diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index 77f9b18cb08..fa02b350425 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -553,7 +553,7 @@ CREATE TABLE proc ( 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE' - ) DEFAULT 0 NOT NULL, + ) DEFAULT '' NOT NULL, comment char(64) binary DEFAULT '' NOT NULL, PRIMARY KEY (db,name,type) ) comment='Stored Procedures'; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index d622127e8f0..eba8dddfe72 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -37,7 +37,7 @@ Note 1051 Unknown table 't1' create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap; ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key create table not_existing_database.test (a int); -Got one of the listed errors +ERROR 42000: Unknown database 'not_existing_database' create table `a/a` (a int); ERROR 42000: Incorrect table name 'a/a' create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); @@ -358,7 +358,7 @@ create table t3 like t1; create table t3 like mysqltest.t3; ERROR 42S01: Table 't3' already exists create table non_existing_database.t1 like t1; -Got one of the listed errors +ERROR 42000: Unknown database 'non_existing_database' create table t3 like non_existing_table; ERROR 42S02: Unknown table 'non_existing_table' create temporary table t3 like t1; diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index c63704f6d9d..8d2c39df853 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -67,6 +67,28 @@ big5_chinese_ci 6109 big5_chinese_ci 61 big5_chinese_ci 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +big5_chinese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; SET collation_connection='big5_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -77,6 +99,28 @@ big5_bin 6109 big5_bin 61 big5_bin 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +big5_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; SET NAMES big5; CREATE TABLE t1 (a text) character set big5; INSERT INTO t1 VALUES ('ùØ'); diff --git a/mysql-test/r/ctype_eucjpms.result b/mysql-test/r/ctype_eucjpms.result index a07ff9b28be..cdb28cd0fdd 100755 --- a/mysql-test/r/ctype_eucjpms.result +++ b/mysql-test/r/ctype_eucjpms.result @@ -9785,6 +9785,20 @@ DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +CREATE TABLE t1(c1 varchar(10)) default character set = eucjpms; +insert into t1 values(_ucs2 0x00F7); +insert into t1 values(_eucjpms 0xA1E0); +insert into t1 values(_ujis 0xA1E0); +insert into t1 values(_sjis 0x8180); +insert into t1 values(_cp932 0x8180); +SELECT HEX(c1) FROM t1; +HEX(c1) +A1E0 +A1E0 +A1E0 +A1E0 +A1E0 +DROP TABLE t1; SET collation_connection='eucjpms_japanese_ci'; create table t1 select repeat('a',4000) a; delete from t1; diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result new file mode 100644 index 00000000000..1a9dea28429 --- /dev/null +++ b/mysql-test/r/ctype_gbk.result @@ -0,0 +1,131 @@ +drop table if exists t1; +SET @test_character_set= 'gbk'; +SET @test_collation= 'gbk_chinese_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) gbk_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) gbk_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; +SET NAMES gbk; +SET collation_connection='gbk_chinese_ci'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gbk_chinese_ci 6109 +gbk_chinese_ci 61 +gbk_chinese_ci 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gbk_chinese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +SET collation_connection='gbk_bin'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gbk_bin 6109 +gbk_bin 61 +gbk_bin 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gbk_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +SET NAMES gbk; +CREATE TABLE t1 (a text) character set gbk; +INSERT INTO t1 VALUES (0xA3A0),(0xA1A1); +SELECT hex(a) FROM t1 ORDER BY a; +hex(a) +A1A1 +A3A0 +DROP TABLE t1; diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index 21c40e24fe2..95fca1575ef 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -168,7 +168,7 @@ hex(a) hex(@u:=convert(a using utf8)) hex(@l:=convert(@u using latin1)) a=@l 7E 7E 7E 1 7F 7F 7F 1 80 E282AC 80 1 -81 3F 3F 0 +81 C281 81 1 82 E2809A 82 1 83 C692 83 1 84 E2809E 84 1 @@ -180,10 +180,10 @@ hex(a) hex(@u:=convert(a using utf8)) hex(@l:=convert(@u using latin1)) a=@l 8A C5A0 8A 1 8B E280B9 8B 1 8C C592 8C 1 -8D 3F 3F 0 +8D C28D 8D 1 8E C5BD 8E 1 -8F 3F 3F 0 -90 3F 3F 0 +8F C28F 8F 1 +90 C290 90 1 91 E28098 91 1 92 E28099 92 1 93 E2809C 93 1 @@ -196,7 +196,7 @@ hex(a) hex(@u:=convert(a using utf8)) hex(@l:=convert(@u using latin1)) a=@l 9A C5A1 9A 1 9B E280BA 9B 1 9C C593 9C 1 -9D 3F 3F 0 +9D C29D 9D 1 9E C5BE 9E 1 9F C5B8 9F 1 A0 C2A0 A0 1 diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result index 98e5992f374..e6669c63621 100644 --- a/mysql-test/r/ctype_sjis.result +++ b/mysql-test/r/ctype_sjis.result @@ -81,6 +81,28 @@ sjis_japanese_ci 6109 sjis_japanese_ci 61 sjis_japanese_ci 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +sjis_japanese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; SET collation_connection='sjis_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -91,6 +113,28 @@ sjis_bin 6109 sjis_bin 61 sjis_bin 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +sjis_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; SET NAMES sjis; SELECT HEX('²“‘@\Œ\') FROM DUAL; HEX('²“‘@_Œ\') diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result index a00e68b596e..0bc101d491d 100644 --- a/mysql-test/r/ctype_ujis.result +++ b/mysql-test/r/ctype_ujis.result @@ -2217,6 +2217,28 @@ ujis_japanese_ci 6109 ujis_japanese_ci 61 ujis_japanese_ci 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +ujis_japanese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; SET collation_connection='ujis_bin'; create table t1 select repeat('a',4000) a; delete from t1; @@ -2227,3 +2249,25 @@ ujis_bin 6109 ujis_bin 61 ujis_bin 6120 drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +ujis_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 66db34bdf83..64c693a292a 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -954,6 +954,45 @@ char_length(a) length(a) a 2 2 12 2 4 ан drop table t1; +set names utf8; +select 'a\\' like 'a\\'; +'a\\' like 'a\\' +1 +select 'aa\\' like 'a%\\'; +'aa\\' like 'a%\\' +1 +create table t1 (a char(10), key(a)) character set utf8; +insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test"); +select * from t1 where a like "abc%"; +a +abc +abcd +select * from t1 where a like concat("abc","%"); +a +abc +abcd +select * from t1 where a like "ABC%"; +a +abc +abcd +select * from t1 where a like "test%"; +a +test +select * from t1 where a like "te_t"; +a +test +select * from t1 where a like "%a%"; +a +a +abc +abcd +select * from t1 where a like "%abcd%"; +a +abcd +select * from t1 where a like "%abc\d%"; +a +abcd +drop table t1; CREATE TABLE t1 ( a varchar(255) NOT NULL default '', KEY a (a) diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index 8217a0e7ba6..74ab1e35534 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -434,7 +434,7 @@ explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select makedate(1997,1) AS `makedate(1997,1)`,addtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'31.12.97 11.59.59.999999 PM') AS `addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,subtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'31.12.97 11.59.59.999999 PM') AS `subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,timediff(_latin1'01.01.97 11:59:59.000001 PM',_latin1'31.12.95 11:59:59.000002 PM') AS `timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM")`,cast(str_to_date(_latin1'15-01-2001 12:59:59',_latin1'%d-%m-%Y %H:%i:%S') as time) AS `cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME)`,maketime(23,11,12) AS `maketime(23,11,12)`,microsecond(_latin1'1997-12-31 23:59:59.000001') AS `microsecond("1997-12-31 23:59:59.000001")` +Note 1003 select makedate(1997,1) AS `makedate(1997,1)`,addtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'1 1.1.1.000002') AS `addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,subtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'1 1.1.1.000002') AS `subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,timediff(_latin1'01.01.97 11:59:59.000001 PM',_latin1'31.12.95 11:59:59.000002 PM') AS `timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM")`,cast(str_to_date(_latin1'15-01-2001 12:59:59',_latin1'%d-%m-%Y %H:%i:%S') as time) AS `cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME)`,maketime(23,11,12) AS `maketime(23,11,12)`,microsecond(_latin1'1997-12-31 23:59:59.000001') AS `microsecond("1997-12-31 23:59:59.000001")` create table t1 (d date); insert into t1 values ('2004-07-14'),('2005-07-14'); select date_format(d,"%d") from t1 order by 1; diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index d9c86a89c75..7692991c112 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -7,41 +7,47 @@ 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.t1; +Warnings: +Note 1051 Unknown table 't1' CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) DEFAULT CHARSET=latin1; -DROP DATABASE IF EXISTS federated; -CREATE DATABASE federated; +DROP TABLE IF EXISTS federated.t1; +Warnings: +Note 1051 Unknown table 't1' CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; -ERROR HY000: Can't create table 'connection string is not in the correct format' (errno: 0) +ERROR HY000: Can't create federated table. The data source connection string 'mysql://root@127.0.0.1:@/too/many/items/federated/t1' is not in the correct format CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1'; -ERROR HY000: Can't create table 'connection string is not in the correct format' (errno: 0) +ERROR HY000: Can't create federated table. The data source connection string 'mysql://root@127.0.0.1' is not in the correct format CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t3'; -ERROR HY000: Error running query on master: foreign table 't3' does not exist! +ERROR HY000: Can't create federated table. Foreign data src error : ': 1146 : Table 'federated.t3' doesn't exist' CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://user:pass@127.0.0.1:SLAVE_PORT/federated/t1'; -ERROR 08S01: Error connecting to master: unable to connect to database 'federated' on host '127.0.0.1 as user 'user' ! +ERROR HY000: Unable to connect to foreign data source - database ' database federated username user hostname 127.0.0.1'! DROP TABLE IF EXISTS federated.t1; Warnings: Note 1051 Unknown table 't1' @@ -124,18 +130,14 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '', `other` int(20) NOT NULL default '0', `created` datetime default '2004-04-04 04:04:04', -PRIMARY KEY (`id`), -KEY `name` (`name`), -KEY `other_key` (`other`)) +PRIMARY KEY (`id`)) DEFAULT CHARSET=latin1; CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32) NOT NULL default '', `other` int(20) NOT NULL default '0', `created` datetime default '2004-04-04 04:04:04', -PRIMARY KEY (`id`), -KEY `name` (`name`), -KEY `other_key` (`other`)) +PRIMARY KEY (`id`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111); @@ -169,9 +171,8 @@ id name other created SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name'; id name other created 6 Sixth Name 66666 2004-04-04 04:04:04 -SELECT * FROM federated.t1 WHERE other = 44444; +SELECT * FROM federated.t1 WHERE name = 'Sixth Name' AND other = 44444; id name other created -4 Fourth Name 44444 2004-04-04 04:04:04 SELECT * FROM federated.t1 WHERE name like '%th%'; id name other created 3 Third Name 33333 2004-04-04 04:04:04 @@ -257,6 +258,154 @@ DELETE FROM federated.t1; SELECT * FROM federated.t1 WHERE id = 5; id name other created DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int(20) NOT NULL auto_increment, +`name` varchar(32) NOT NULL default '', +`other` int(20) NOT NULL default '0', +`created` datetime NOT NULL, +PRIMARY KEY (`id`), +key name(`name`), +key other(`other`), +key created(`created`)) +DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int(20) NOT NULL auto_increment, +`name` varchar(32) NOT NULL default '', +`other` int(20) NOT NULL default '0', +`created` datetime NOT NULL, +PRIMARY KEY (`id`), +key name(`name`), +key other(`other`), +key created(`created`)) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +INSERT INTO federated.t1 (name, other, created) +VALUES ('First Name', 11111, '2004-01-01 01:01:01'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Second Name', 22222, '2004-01-23 02:43:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Third Name', 33333, '2004-02-14 02:14:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Fourth Name', 44444, '2003-04-05 00:00:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Fifth Name', 55555, '2001-02-02 02:02:02'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Sixth Name', 66666, '2005-06-06 15:30:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Seventh Name', 77777, '2003-12-12 18:32:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Eigth Name', 88888, '2005-03-12 11:00:00'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Ninth Name', 99999, '2005-03-12 11:00:01'); +INSERT INTO federated.t1 (name, other, created) +VALUES ('Tenth Name', 101010, '2005-03-12 12:00:01'); +SELECT * FROM federated.t1; +id name other created +1 First Name 11111 2004-01-01 01:01:01 +2 Second Name 22222 2004-01-23 02:43:00 +3 Third Name 33333 2004-02-14 02:14:00 +4 Fourth Name 44444 2003-04-05 00:00:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +6 Sixth Name 66666 2005-06-06 15:30:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +8 Eigth Name 88888 2005-03-12 11:00:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +10 Tenth Name 101010 2005-03-12 12:00:01 +SELECT * FROM federated.t1 WHERE id = 5; +id name other created +5 Fifth Name 55555 2001-02-02 02:02:02 +SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name'; +id name other created +6 Sixth Name 66666 2005-06-06 15:30:00 +SELECT * FROM federated.t1 WHERE other = 44444; +id name other created +4 Fourth Name 44444 2003-04-05 00:00:00 +SELECT * FROM federated.t1 WHERE name like '%th%'; +id name other created +3 Third Name 33333 2004-02-14 02:14:00 +4 Fourth Name 44444 2003-04-05 00:00:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +6 Sixth Name 66666 2005-06-06 15:30:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +8 Eigth Name 88888 2005-03-12 11:00:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +10 Tenth Name 101010 2005-03-12 12:00:01 +UPDATE federated.t1 SET name = '3rd name' WHERE id = 3; +SELECT * FROM federated.t1 WHERE name = '3rd name'; +id name other created +3 3rd name 33333 2004-02-14 02:14:00 +UPDATE federated.t1 SET name = 'Third name' WHERE name = '3rd name'; +SELECT * FROM federated.t1 WHERE name = 'Third name'; +id name other created +3 Third name 33333 2004-02-14 02:14:00 +SELECT * FROM federated.t1 ORDER BY id DESC; +id name other created +10 Tenth Name 101010 2005-03-12 12:00:01 +9 Ninth Name 99999 2005-03-12 11:00:01 +8 Eigth Name 88888 2005-03-12 11:00:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +6 Sixth Name 66666 2005-06-06 15:30:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +4 Fourth Name 44444 2003-04-05 00:00:00 +3 Third name 33333 2004-02-14 02:14:00 +2 Second Name 22222 2004-01-23 02:43:00 +1 First Name 11111 2004-01-01 01:01:01 +SELECT * FROM federated.t1 ORDER BY name; +id name other created +8 Eigth Name 88888 2005-03-12 11:00:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +1 First Name 11111 2004-01-01 01:01:01 +4 Fourth Name 44444 2003-04-05 00:00:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +2 Second Name 22222 2004-01-23 02:43:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +6 Sixth Name 66666 2005-06-06 15:30:00 +10 Tenth Name 101010 2005-03-12 12:00:01 +3 Third name 33333 2004-02-14 02:14:00 +SELECT * FROM federated.t1 ORDER BY name DESC; +id name other created +3 Third name 33333 2004-02-14 02:14:00 +10 Tenth Name 101010 2005-03-12 12:00:01 +6 Sixth Name 66666 2005-06-06 15:30:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +2 Second Name 22222 2004-01-23 02:43:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +4 Fourth Name 44444 2003-04-05 00:00:00 +1 First Name 11111 2004-01-01 01:01:01 +5 Fifth Name 55555 2001-02-02 02:02:02 +8 Eigth Name 88888 2005-03-12 11:00:00 +SELECT * FROM federated.t1 ORDER BY name ASC; +id name other created +8 Eigth Name 88888 2005-03-12 11:00:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +1 First Name 11111 2004-01-01 01:01:01 +4 Fourth Name 44444 2003-04-05 00:00:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +2 Second Name 22222 2004-01-23 02:43:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +6 Sixth Name 66666 2005-06-06 15:30:00 +10 Tenth Name 101010 2005-03-12 12:00:01 +3 Third name 33333 2004-02-14 02:14:00 +SELECT * FROM federated.t1 GROUP BY other; +id name other created +1 First Name 11111 2004-01-01 01:01:01 +2 Second Name 22222 2004-01-23 02:43:00 +3 Third name 33333 2004-02-14 02:14:00 +4 Fourth Name 44444 2003-04-05 00:00:00 +5 Fifth Name 55555 2001-02-02 02:02:02 +6 Sixth Name 66666 2005-06-06 15:30:00 +7 Seventh Name 77777 2003-12-12 18:32:00 +8 Eigth Name 88888 2005-03-12 11:00:00 +9 Ninth Name 99999 2005-03-12 11:00:01 +10 Tenth Name 101010 2005-03-12 12:00:01 +DELETE FROM federated.t1 WHERE id = 5; +SELECT * FROM federated.t1 WHERE id = 5; +id name other created +DELETE FROM federated.t1; +SELECT * FROM federated.t1 WHERE id = 5; +id name other created +DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32), @@ -303,15 +452,14 @@ UPDATE federated.t1 SET name = 'Fourth Name', other = 'four four four' WHERE name IS NULL AND other IS NULL; UPDATE federated.t1 SET other = 'two two two two' WHERE name = 'Second Name'; -UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sec%'; -UPDATE federated.t1 SET other = 'seven seven' WHERE name = 'Seventh Name'; +UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sev%'; UPDATE federated.t1 SET name = 'Tenth Name' WHERE other like 'fee fie%'; SELECT * FROM federated.t1 WHERE name IS NULL OR other IS NULL ; id name other SELECT * FROM federated.t1; id name other 1 First Name 11111 -2 Second Name seven seven +2 Second Name two two two two 3 Third Name 33333 4 Fourth Name four four four 5 Fifth Name 55555 @@ -418,6 +566,360 @@ id name bincol floatval other 3 third g 22.22 2222 DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( +`id` int NOT NULL auto_increment, +`col1` int(10) NOT NULL DEFAULT 0, +`col2` varchar(64) NOT NULL DEFAULT '', +`col3` int(20) NOT NULL, +`col4` int(40) NOT NULL, +primary key (`id`, `col1`, `col2`, `col3`, `col4`), +key col1(col1), +key col2(col2), +key col3(col3), +key col4(col4)); +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`id` int NOT NULL auto_increment, +`col1` int(10) NOT NULL DEFAULT 0, +`col2` varchar(64) NOT NULL DEFAULT '', +`col3` int(20) NOT NULL, +`col4` int(40) NOT NULL, +primary key (`id`, `col1`, `col2`, `col3`, `col4`), +key col1(col1), +key col2(col2), +key col3(col3), +key col4(col4)) +ENGINE="FEDERATED" + COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (1, 'one One', 11, 1111); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (2, 'Two two', 22, 2222); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (3, 'three Three', 33, 33333); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (4, 'fourfourfour', 444, 4444444); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (5, 'five 5 five five 5', 5, 55555); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (6, 'six six Sixsix', 6666, 6); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (7, 'seven Sevenseven', 77777, 7777); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (8, 'eight eight eight', 88888, 88); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (9, 'nine Nine', 999999, 999999); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES (10, 'Tenth ten TEN', 1010101, 1010); +SELECT * FROM federated.t1 WHERE col2 = 'two two'; +id col1 col2 col3 col4 +2 2 Two two 22 2222 +SELECT * FROM federated.t1 WHERE col2 = 'two Two'; +id col1 col2 col3 col4 +2 2 Two two 22 2222 +SELECT * FROM federated.t1 WHERE id = 3; +id col1 col2 col3 col4 +3 3 three Three 33 33333 +SELECT * FROM federated.t1 WHERE id = 3 AND col1 = 3; +id col1 col2 col3 col4 +3 3 three Three 33 33333 +SELECT * FROM federated.t1 WHERE id = 4 AND col1 = 4 AND col2 = 'Two two'; +id col1 col2 col3 col4 +SELECT * FROM federated.t1 WHERE id = 4 AND col1 = 4 AND col2 = 'fourfourfour'; +id col1 col2 col3 col4 +4 4 fourfourfour 444 4444444 +SELECT * FROM federated.t1 WHERE id = 5 AND col2 = 'five 5 five five 5' +AND col3 = 5; +id col1 col2 col3 col4 +5 5 five 5 five five 5 5 55555 +SELECT * FROM federated.t1 WHERE id = 5 AND col2 = 'five 5 five five 5' +AND col3 = 5 +AND col4 = 55555; +id col1 col2 col3 col4 +5 5 five 5 five five 5 5 55555 +SELECT * FROM federated.t1 WHERE id = 5 +AND col2 = 'Two two' AND col3 = 22 +AND col4 = 33; +id col1 col2 col3 col4 +SELECT * FROM federated.t1 WHERE id = 5 +AND col2 = 'five 5 five five 5' AND col3 = 5 +AND col4 = 55555; +id col1 col2 col3 col4 +5 5 five 5 five five 5 5 55555 +SELECT * FROM federated.t1 WHERE (id = 5 AND col2 = 'five 5 five five 5') +OR (col2 = 'three Three' AND col3 = 33); +id col1 col2 col3 col4 +5 5 five 5 five five 5 5 55555 +3 3 three Three 33 33333 +SELECT * FROM federated.t1 WHERE (id = 5 AND col2 = 'Two two') +OR (col2 = 444 AND col3 = 4444444); +id col1 col2 col3 col4 +SELECT * FROM federated.t1 WHERE id = 1 +OR col1 = 10 +OR col2 = 'Two two' +OR col3 = 33 +OR col4 = 4444444; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE id > 5; +id col1 col2 col3 col4 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +8 8 eight eight eight 88888 88 +9 9 nine Nine 999999 999999 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE id >= 5; +id col1 col2 col3 col4 +5 5 five 5 five five 5 5 55555 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +8 8 eight eight eight 88888 88 +9 9 nine Nine 999999 999999 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE id < 5; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +SELECT * FROM federated.t1 WHERE id <= 5; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +SELECT * FROM federated.t1 WHERE id != 5; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +8 8 eight eight eight 88888 88 +9 9 nine Nine 999999 999999 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE id > 3 AND id < 7; +id col1 col2 col3 col4 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +6 6 six six Sixsix 6666 6 +SELECT * FROM federated.t1 WHERE id > 3 AND id <= 7; +id col1 col2 col3 col4 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +SELECT * FROM federated.t1 WHERE id >= 3 AND id <= 7; +id col1 col2 col3 col4 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +SELECT * FROM federated.t1 WHERE id < 3 AND id <= 7; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +SELECT * FROM federated.t1 WHERE id < 3 AND id > 7; +id col1 col2 col3 col4 +SELECT * FROM federated.t1 WHERE id < 3 OR id > 7; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +8 8 eight eight eight 88888 88 +9 9 nine Nine 999999 999999 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE col2 = 'three Three'; +id col1 col2 col3 col4 +3 3 three Three 33 33333 +SELECT * FROM federated.t1 WHERE col2 > 'one'; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE col2 LIKE 's%'; +id col1 col2 col3 col4 +7 7 seven Sevenseven 77777 7777 +6 6 six six Sixsix 6666 6 +SELECT * FROM federated.t1 WHERE col2 LIKE 'si%'; +id col1 col2 col3 col4 +6 6 six six Sixsix 6666 6 +SELECT * FROM federated.t1 WHERE col2 LIKE 'se%'; +id col1 col2 col3 col4 +7 7 seven Sevenseven 77777 7777 +SELECT * FROM federated.t1 WHERE col2 NOT LIKE 'e%'; +id col1 col2 col3 col4 +1 1 one One 11 1111 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +9 9 nine Nine 999999 999999 +10 10 Tenth ten TEN 1010101 1010 +SELECT * FROM federated.t1 WHERE col2 <> 'one One'; +id col1 col2 col3 col4 +4 4 fourfourfour 444 4444444 +5 5 five 5 five five 5 5 55555 +8 8 eight eight eight 88888 88 +9 9 nine Nine 999999 999999 +2 2 Two two 22 2222 +3 3 three Three 33 33333 +6 6 six six Sixsix 6666 6 +7 7 seven Sevenseven 77777 7777 +10 10 Tenth ten TEN 1010101 1010 +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`col1` varchar(8) NOT NULL DEFAULT '', +`col2` varchar(128) NOT NULL DEFAULT '', +`col3` varchar(20) NOT NULL DEFAULT '', +`col4` varchar(40) NOT NULL DEFAULT '', +primary key (`col1`, `col2`, `col3`, `col4`), +key 3key(`col2`,`col3`,`col4`), +key 2key (`col3`,`col4`), +key col4(col4)); +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`col1` varchar(8) NOT NULL DEFAULT '', +`col2` varchar(128) NOT NULL DEFAULT '', +`col3` varchar(20) NOT NULL DEFAULT '', +`col4` varchar(40) NOT NULL DEFAULT '', +primary key (`col1`, `col2`, `col3`, `col4`), +key 3key(`col2`,`col3`,`col4`), +key 2key (`col3`,`col4`), +key col4(col4)) +ENGINE="FEDERATED" + COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('aaaa', 'aaaaaaaaaaaaaaaaaaa', 'ababababab', 'acacacacacacacac'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('bbbb', 'bbbbbbbbbbbbbbbbbbb', 'bababababa', 'bcbcbcbcbcbcbcbc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('cccc', 'ccccccccccccccccccc', 'cacacacaca', 'cbcbcbcbcbcbcbcb'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('dddd', 'ddddddddddddddddddd', 'dadadadada', 'dcdcdcdcdcdcdcdc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('eeee', 'eeeeeeeeeeeeeeeeeee', 'eaeaeaeaea', 'ecececececececec'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('ffff', 'fffffffffffffffffff', 'fafafafafa', 'fcfcfcfcfcfcfcfc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('gggg', 'ggggggggggggggggggg', 'gagagagaga', 'gcgcgcgcgcgcgcgc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) +VALUES ('hhhh', 'hhhhhhhhhhhhhhhhhhh', 'hahahahaha', 'hchchchchchchchc'); +SELECT * FROM federated.t1 WHERE col1 = 'cccc'; +col1 col2 col3 col4 +cccc ccccccccccccccccccc cacacacaca cbcbcbcbcbcbcbcb +SELECT * FROM federated.t1 WHERE col2 = 'eeeeeeeeeeeeeeeeeee'; +col1 col2 col3 col4 +eeee eeeeeeeeeeeeeeeeeee eaeaeaeaea ecececececececec +SELECT * FROM federated.t1 WHERE col3 = 'bababababa'; +col1 col2 col3 col4 +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +SELECT * FROM federated.t1 WHERE col1 = 'gggg' AND col2 = 'ggggggggggggggggggg'; +col1 col2 col3 col4 +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +SELECT * FROM federated.t1 WHERE col1 = 'gggg' AND col3 = 'gagagagaga'; +col1 col2 col3 col4 +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +SELECT * FROM federated.t1 WHERE col1 = 'ffff' AND col4 = 'fcfcfcfcfcfcfcfc'; +col1 col2 col3 col4 +ffff fffffffffffffffffff fafafafafa fcfcfcfcfcfcfcfc +SELECT * FROM federated.t1 WHERE col1 > 'bbbb'; +col1 col2 col3 col4 +cccc ccccccccccccccccccc cacacacaca cbcbcbcbcbcbcbcb +dddd ddddddddddddddddddd dadadadada dcdcdcdcdcdcdcdc +eeee eeeeeeeeeeeeeeeeeee eaeaeaeaea ecececececececec +ffff fffffffffffffffffff fafafafafa fcfcfcfcfcfcfcfc +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +hhhh hhhhhhhhhhhhhhhhhhh hahahahaha hchchchchchchchc +SELECT * FROM federated.t1 WHERE col1 >= 'bbbb'; +col1 col2 col3 col4 +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +cccc ccccccccccccccccccc cacacacaca cbcbcbcbcbcbcbcb +dddd ddddddddddddddddddd dadadadada dcdcdcdcdcdcdcdc +eeee eeeeeeeeeeeeeeeeeee eaeaeaeaea ecececececececec +ffff fffffffffffffffffff fafafafafa fcfcfcfcfcfcfcfc +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +hhhh hhhhhhhhhhhhhhhhhhh hahahahaha hchchchchchchchc +SELECT * FROM federated.t1 WHERE col1 < 'bbbb'; +col1 col2 col3 col4 +aaaa aaaaaaaaaaaaaaaaaaa ababababab acacacacacacacac +SELECT * FROM federated.t1 WHERE col1 <= 'bbbb'; +col1 col2 col3 col4 +aaaa aaaaaaaaaaaaaaaaaaa ababababab acacacacacacacac +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +SELECT * FROM federated.t1 WHERE col1 <> 'bbbb'; +col1 col2 col3 col4 +aaaa aaaaaaaaaaaaaaaaaaa ababababab acacacacacacacac +cccc ccccccccccccccccccc cacacacaca cbcbcbcbcbcbcbcb +dddd ddddddddddddddddddd dadadadada dcdcdcdcdcdcdcdc +eeee eeeeeeeeeeeeeeeeeee eaeaeaeaea ecececececececec +ffff fffffffffffffffffff fafafafafa fcfcfcfcfcfcfcfc +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +hhhh hhhhhhhhhhhhhhhhhhh hahahahaha hchchchchchchchc +SELECT * FROM federated.t1 WHERE col1 LIKE 'b%'; +col1 col2 col3 col4 +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +SELECT * FROM federated.t1 WHERE col4 LIKE '%b%'; +col1 col2 col3 col4 +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +cccc ccccccccccccccccccc cacacacaca cbcbcbcbcbcbcbcb +SELECT * FROM federated.t1 WHERE col1 NOT LIKE 'c%'; +col1 col2 col3 col4 +aaaa aaaaaaaaaaaaaaaaaaa ababababab acacacacacacacac +bbbb bbbbbbbbbbbbbbbbbbb bababababa bcbcbcbcbcbcbcbc +dddd ddddddddddddddddddd dadadadada dcdcdcdcdcdcdcdc +eeee eeeeeeeeeeeeeeeeeee eaeaeaeaea ecececececececec +ffff fffffffffffffffffff fafafafafa fcfcfcfcfcfcfcfc +gggg ggggggggggggggggggg gagagagaga gcgcgcgcgcgcgcgc +hhhh hhhhhhhhhhhhhhhhhhh hahahahaha hchchchchchchchc +SELECT * FROM federated.t1 WHERE col4 NOT LIKE '%c%'; +col1 col2 col3 col4 +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`col1` varchar(8) NOT NULL DEFAULT '', +`col2` int(8) NOT NULL DEFAULT 0, +`col3` varchar(8) NOT NULL DEFAULT '', +primary key (`col1`, `col2`, `col3`)); +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +`col1` varchar(8) NOT NULL DEFAULT '', +`col2` varchar(8) NOT NULL DEFAULT '', +`col3` varchar(8) NOT NULL DEFAULT '', +primary key (`col1`, `col2`, `col3`)) +ENGINE="FEDERATED" + DEFAULT CHARSET=latin1 +COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +INSERT INTO federated.t1 VALUES ('a00', '110', 'cc0'); +INSERT INTO federated.t1 VALUES ('aaa', '111', 'ccc'); +INSERT INTO federated.t1 VALUES ('bbb', '222', 'yyy'); +INSERT INTO federated.t1 VALUES ('ccc', '111', 'zzz'); +INSERT INTO federated.t1 VALUES ('ccd', '112', 'zzzz'); +SELECT col3 FROM federated.t1 WHERE ( +(col1 = 'aaa' AND col2 >= '111') OR col1 > 'aaa') AND +(col1 < 'ccc' OR ( col1 = 'ccc' AND col2 <= '111')); +col3 +ccc +yyy +zzz +SELECT col3 FROM federated.t1 WHERE ( +(col1 = 'aaa' AND col2 >= '111') OR col1 > 'aaa') AND +(col1 < 'ccc' OR ( col1 = 'ccc' AND col2 <= '111')); +col3 +ccc +yyy +zzz +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( `id` int, `name` varchar(32), `floatval` float, @@ -494,30 +996,6 @@ ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4); -EXPLAIN SELECT * FROM federated.t1 ORDER BY a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT * FROM federated.t1 ORDER BY b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT * FROM federated.t1 ORDER BY c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT a FROM federated.t1 ORDER BY a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT b FROM federated.t1 ORDER BY b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT a,b FROM federated.t1 ORDER BY b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using filesort -EXPLAIN SELECT a,b FROM federated.t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 -EXPLAIN SELECT a,b,c FROM federated.t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8 int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17 @@ -906,13 +1384,6 @@ INSERT INTO federated.t1 (name, country_id, other) VALUES ('Lenz', 2, 22222); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Marizio', 3, 33333); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Monty', 4, 33333); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Sanja', 5, 33333); -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1, federated.countries WHERE -federated.t1.country_id = federated.countries.id; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE countries ALL PRIMARY NULL NULL NULL 5 -1 SIMPLE t1 ref country_id country_id 4 federated.countries.id 120 SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1, federated.countries WHERE @@ -923,13 +1394,6 @@ Lenz 2 22222 Germany Marizio 3 33333 Italy Monty 4 33333 Finland Sanja 5 33333 Ukraine -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1 INNER JOIN federated.countries ON -federated.t1.country_id = federated.countries.id; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE countries ALL PRIMARY NULL NULL NULL 5 -1 SIMPLE t1 ref country_id country_id 4 federated.countries.id 120 SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1 INNER JOIN federated.countries ON @@ -940,14 +1404,6 @@ Lenz 2 22222 Germany Marizio 3 33333 Italy Monty 4 33333 Finland Sanja 5 33333 Ukraine -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1 INNER JOIN federated.countries ON -federated.t1.country_id = federated.countries.id -WHERE federated.t1.name = 'Monty'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE countries ALL PRIMARY NULL NULL NULL 5 -1 SIMPLE t1 ref country_id country_id 4 federated.countries.id 120 Using where SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1 INNER JOIN federated.countries ON @@ -955,13 +1411,6 @@ federated.t1.country_id = federated.countries.id WHERE federated.t1.name = 'Monty'; name country_id other country Monty 4 33333 Finland -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 LEFT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.countries.id; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using temporary; Using filesort -1 SIMPLE countries eq_ref PRIMARY PRIMARY 4 federated.t1.country_id 1 SELECT federated.t1.*, federated.countries.country FROM federated.t1 LEFT JOIN federated.countries ON federated.t1.country_id = federated.countries.id @@ -972,13 +1421,6 @@ id country_id name other country 3 3 Marizio 33333 Italy 4 4 Monty 33333 Finland 5 5 Sanja 33333 Ukraine -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 LEFT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.countries.country; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 10000 Using temporary; Using filesort -1 SIMPLE countries eq_ref PRIMARY PRIMARY 4 federated.t1.country_id 1 SELECT federated.t1.*, federated.countries.country FROM federated.t1 LEFT JOIN federated.countries ON federated.t1.country_id = federated.countries.id @@ -989,13 +1431,6 @@ id country_id name other country 1 1 Kumar 11111 India 3 3 Marizio 33333 Italy 5 5 Sanja 33333 Ukraine -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 RIGHT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.t1.country_id; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE countries ALL NULL NULL NULL NULL 5 Using temporary; Using filesort -1 SIMPLE t1 ref country_id country_id 4 federated.countries.id 120 SELECT federated.t1.*, federated.countries.country FROM federated.t1 RIGHT JOIN federated.countries ON federated.t1.country_id = federated.countries.id @@ -1007,6 +1442,21 @@ id country_id name other country 4 4 Monty 33333 Finland 5 5 Sanja 33333 Ukraine DROP TABLE federated.countries; +OPTIMIZE TABLE federated.t1; +Table Op Msg_type Msg_text +federated.t1 optimize status OK +REPAIR TABLE federated.t1; +Table Op Msg_type Msg_text +federated.t1 repair status OK +REPAIR TABLE federated.t1 QUICK; +Table Op Msg_type Msg_text +federated.t1 repair status OK +REPAIR TABLE federated.t1 EXTENDED; +Table Op Msg_type Msg_text +federated.t1 repair status OK +REPAIR TABLE federated.t1 USE_FRM; +Table Op Msg_type Msg_text +federated.t1 repair status OK DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 10afb61ba1d..184bd07b066 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -445,6 +445,30 @@ group_concat(distinct b order by b) Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() drop table t1; +create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci, +b varchar(255) character set koi8r); +insert into t1 values ('xxx','yyy'); +select collation(a) from t1; +collation(a) +cp1250_general_ci +select collation(group_concat(a)) from t1; +collation(group_concat(a)) +cp1250_general_ci +create table t2 select group_concat(a) as a from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(400) character set cp1250 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select collation(group_concat(a,_koi8r'test')) from t1; +collation(group_concat(a,_koi8r'test')) +cp1250_general_ci +select collation(group_concat(a,_koi8r 0xC1C2)) from t1; +ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,COERCIBLE) for operation 'group_concat' +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 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc @@ -500,3 +524,34 @@ group_concat(a) ABW ABW drop table t1; +CREATE TABLE t1 ( +aID smallint(5) unsigned NOT NULL auto_increment, +sometitle varchar(255) NOT NULL default '', +bID smallint(5) unsigned NOT NULL, +PRIMARY KEY (aID), +UNIQUE KEY sometitle (sometitle) +); +INSERT INTO t1 SET sometitle = 'title1', bID = 1; +INSERT INTO t1 SET sometitle = 'title2', bID = 1; +CREATE TABLE t2 ( +bID smallint(5) unsigned NOT NULL auto_increment, +somename varchar(255) NOT NULL default '', +PRIMARY KEY (bID), +UNIQUE KEY somename (somename) +); +INSERT INTO t2 SET somename = 'test'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +INSERT INTO t2 SET somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +DELETE FROM t2 WHERE somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +FROM t1 JOIN t2 ON t1.bID = t2.bID; +COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') +2 test +DROP TABLE t1,t2; diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 0db2ceb0e6b..1542794798a 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -795,6 +795,32 @@ show columns from t2; Field Type Null Key Default Extra f2 datetime NO 0000-00-00 00:00:00 drop table t2, t1; +CREATE TABLE t1( +id int PRIMARY KEY, +a int, +b int, +INDEX i_b_id(a,b,id), +INDEX i_id(a,id) +); +INSERT INTO t1 VALUES +(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +MAX(id) +NULL +DROP TABLE t1; +CREATE TABLE t1( +id int PRIMARY KEY, +a int, +b int, +INDEX i_id(a,id), +INDEX i_b_id(a,b,id) +); +INSERT INTO t1 VALUES +(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +MAX(id) +NULL +DROP TABLE t1; create table t2 (ff double); insert into t2 values (2.2); select cast(sum(distinct ff) as decimal(5,2)) from t2; @@ -860,32 +886,6 @@ select col1,sum(col1),max(col1),min(col1) from t1 group by col1; col1 sum(col1) max(col1) min(col1) 5.000000000010 10.000000000020 5.000000000010 5.000000000010 DROP TABLE t1; -CREATE TABLE t1( -id int PRIMARY KEY, -a int, -b int, -INDEX i_b_id(a,b,id), -INDEX i_id(a,id) -); -INSERT INTO t1 VALUES -(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); -SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; -MAX(id) -NULL -DROP TABLE t1; -CREATE TABLE t1( -id int PRIMARY KEY, -a int, -b int, -INDEX i_id(a,id), -INDEX i_b_id(a,b,id) -); -INSERT INTO t1 VALUES -(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); -SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; -MAX(id) -NULL -DROP TABLE t1; CREATE TABLE t1 (a VARCHAR(400)); INSERT INTO t1 (a) VALUES ("A"), ("a"), ("a "), ("a "), ("B"), ("b"), ("b "), ("b "); diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index f75fe0d1627..b0c0178328e 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -119,7 +119,7 @@ c char(1) character set latin1 collate latin1_danish_ci insert into t1 values ('A','B','C'); insert into t1 values ('a','c','c'); select * from t1 where a in (b); -ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '=' select * from t1 where a in (b,c); ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT), (latin1_swedish_ci,IMPLICIT), (latin1_danish_ci,IMPLICIT) for operation ' IN ' select * from t1 where 'a' in (a,b,c); @@ -193,3 +193,26 @@ select * from t1 where a in (NULL, 'aa'); a aa drop table t1; +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (44), (45), (46); +SELECT * FROM t1 WHERE a IN (45); +a +45 +SELECT * FROM t1 WHERE a NOT IN (0, 45); +a +44 +46 +SELECT * FROM t1 WHERE a NOT IN (45); +a +44 +46 +CREATE VIEW v1 AS SELECT * FROM t1 WHERE a NOT IN (45); +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` <> 45) +SELECT * FROM v1; +a +44 +46 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 5335f53d382..57942d1fcdf 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -879,3 +879,18 @@ drop table t1; select hex(29223372036854775809), hex(-29223372036854775809); hex(29223372036854775809) hex(-29223372036854775809) FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF +create table t1 (i int); +insert into t1 values (1000000000),(1); +select lpad(i, 7, ' ') as t from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def t 253 7 7 Y 128 31 63 +t +1000000 + 1 +select rpad(i, 7, ' ') as t from t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def t 253 7 7 Y 128 31 63 +t +1000000 +1 +drop table t1; diff --git a/mysql-test/r/have_gbk.require b/mysql-test/r/have_gbk.require new file mode 100644 index 00000000000..e19fead153a --- /dev/null +++ b/mysql-test/r/have_gbk.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +gbk_chinese_ci gbk 28 Yes Yes 1 diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 98f3d59485f..1781492af8b 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -48,6 +48,7 @@ TABLE_PRIVILEGES COLUMN_PRIVILEGES TABLE_CONSTRAINTS KEY_COLUMN_USAGE +TRIGGERS columns_priv db func @@ -77,6 +78,7 @@ c table_name TABLES TABLES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_CONSTRAINTS TABLE_CONSTRAINTS +TRIGGERS TRIGGERS tables_priv tables_priv time_zone time_zone time_zone_leap_second time_zone_leap_second @@ -94,6 +96,7 @@ c table_name TABLES TABLES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_CONSTRAINTS TABLE_CONSTRAINTS +TRIGGERS TRIGGERS tables_priv tables_priv time_zone time_zone time_zone_leap_second time_zone_leap_second @@ -111,6 +114,7 @@ c table_name TABLES TABLES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_CONSTRAINTS TABLE_CONSTRAINTS +TRIGGERS TRIGGERS tables_priv tables_priv time_zone time_zone time_zone_leap_second time_zone_leap_second @@ -153,7 +157,7 @@ c varchar(64) utf8_general_ci NO select,insert,update,references select * from information_schema.COLUMNS where table_name="t1" and column_name= "a"; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT -NULL mysqltest t1 a 1 NULL YES int NULL NULL 11 0 NULL NULL int(11) select,insert,update,references +NULL mysqltest t1 a 1 NULL YES int NULL NULL 10 NULL NULL NULL int(11) select,insert,update,references show columns from mysqltest.t1 where field like "%a%"; Field Type Null Key Default Extra a int(11) YES NULL @@ -178,13 +182,13 @@ drop database mysqltest; select * from information_schema.CHARACTER_SETS where CHARACTER_SET_NAME like 'latin1%'; CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN -latin1 latin1_swedish_ci ISO 8859-1 West European 1 +latin1 latin1_swedish_ci cp1252 West European 1 SHOW CHARACTER SET LIKE 'latin1%'; Charset Description Default collation Maxlen -latin1 ISO 8859-1 West European latin1_swedish_ci 1 +latin1 cp1252 West European latin1_swedish_ci 1 SHOW CHARACTER SET WHERE charset like 'latin1%'; Charset Description Default collation Maxlen -latin1 ISO 8859-1 West European latin1_swedish_ci 1 +latin1 cp1252 West European latin1_swedish_ci 1 select * from information_schema.COLLATIONS where COLLATION_NAME like 'latin1%'; COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN @@ -298,6 +302,9 @@ show create function sub2; Function sql_mode Create Function sub2 CREATE FUNCTION `test`.`sub2`(i int) RETURNS int(11) return i+1 +show function status like "sub2"; +Db Name Type Definer Modified Created Security_type Comment +test sub2 FUNCTION mysqltest_1@localhost # # DEFINER drop function sub2; show create procedure sel2; Procedure sql_mode Create Procedure @@ -494,7 +501,7 @@ create table t1 select * from information_schema.CHARACTER_SETS where CHARACTER_SET_NAME like "latin1"; select * from t1; CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN -latin1 latin1_swedish_ci ISO 8859-1 West European 1 +latin1 latin1_swedish_ci cp1252 West European 1 alter table t1 default character set utf8; show create table t1; Table Create Table @@ -520,7 +527,7 @@ c float(5,2) NULL NULL 5 2 d decimal(6,4) NULL NULL 6 4 e float NULL NULL 12 NULL f decimal(6,3) NULL NULL 6 3 -g int(11) NULL NULL 11 0 +g int(11) NULL NULL 10 NULL h double(10,3) NULL NULL 10 3 i double NULL NULL 22 NULL drop table t1; @@ -577,6 +584,7 @@ Tables_in_information_schema (T%) TABLES TABLE_PRIVILEGES TABLE_CONSTRAINTS +TRIGGERS create database information_schema; ERROR HY000: Can't create database 'information_schema'; database exists use information_schema; @@ -585,6 +593,7 @@ Tables_in_information_schema (T%) Table_type TABLES TEMPORARY TABLE_PRIVILEGES TEMPORARY TABLE_CONSTRAINTS TEMPORARY +TRIGGERS TEMPORARY create table t1(a int); ERROR 42S02: Unknown table 't1' in information_schema use test; @@ -596,6 +605,7 @@ Tables_in_information_schema (T%) TABLES TABLE_PRIVILEGES TABLE_CONSTRAINTS +TRIGGERS select table_name from tables where table_name='user'; table_name user @@ -690,7 +700,7 @@ CREATE TABLE t_crashme ( f1 BIGINT); CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1; CREATE VIEW a2 AS SELECT t_CRASHME FROM a1; count(*) -100 +101 drop view a2, a1; drop table t_crashme; select table_schema,table_name, column_name from @@ -701,6 +711,9 @@ information_schema COLUMNS COLUMN_TYPE information_schema ROUTINES ROUTINE_DEFINITION information_schema ROUTINES SQL_MODE information_schema VIEWS VIEW_DEFINITION +information_schema TRIGGERS ACTION_CONDITION +information_schema TRIGGERS ACTION_STATEMENT +information_schema TRIGGERS SQL_MODE select table_name, column_name, data_type from information_schema.columns where data_type = 'datetime'; table_name column_name data_type @@ -709,6 +722,7 @@ TABLES UPDATE_TIME datetime TABLES CHECK_TIME datetime ROUTINES CREATED datetime ROUTINES LAST_ALTERED datetime +TRIGGERS CREATED datetime SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A WHERE NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS B @@ -755,8 +769,71 @@ delete from mysql.db where user='mysqltest_4'; flush privileges; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; table_schema count(*) -information_schema 15 +information_schema 16 mysql 17 +create table t1 (i int, j int); +create trigger trg1 before insert on t1 for each row +begin +if new.j > 10 then +set new.j := 10; +end if; +end| +create trigger trg2 before update on t1 for each row +begin +if old.i % 2 = 0 then +set new.j := -1; +end if; +end| +create trigger trg3 after update on t1 for each row +begin +if new.j = -1 then +set @fired:= "Yes"; +end if; +end| +show triggers; +Trigger Event Table Statement Timing Created sql_mode +trg1 INSERT t1 +begin +if new.j > 10 then +set new.j := 10; +end if; +end BEFORE NULL +trg2 UPDATE t1 +begin +if old.i % 2 = 0 then +set new.j := -1; +end if; +end BEFORE NULL +trg3 UPDATE t1 +begin +if new.j = -1 then +set @fired:= "Yes"; +end if; +end AFTER NULL +select * from information_schema.triggers; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE +NULL test trg1 INSERT NULL test t1 0 NULL +begin +if new.j > 10 then +set new.j := 10; +end if; +end ROW BEFORE NULL NULL OLD NEW NULL +NULL test trg2 UPDATE NULL test t1 0 NULL +begin +if old.i % 2 = 0 then +set new.j := -1; +end if; +end ROW BEFORE NULL NULL OLD NEW NULL +NULL test trg3 UPDATE NULL test t1 0 NULL +begin +if new.j = -1 then +set @fired:= "Yes"; +end if; +end ROW AFTER NULL NULL OLD NEW NULL +drop trigger trg1; +drop trigger trg2; +drop trigger trg3; +drop table t1; create database mysqltest; create table mysqltest.t1 (f1 int, f2 int); create table mysqltest.t2 (f1 int); @@ -841,3 +918,35 @@ drop procedure p2; show create database information_schema; Database Create Database information_schema CREATE DATABASE `information_schema` /*!40100 DEFAULT CHARACTER SET utf8 */ +create table t1(f1 LONGBLOB, f2 LONGTEXT); +select column_name,data_type,CHARACTER_OCTET_LENGTH, +CHARACTER_MAXIMUM_LENGTH +from information_schema.columns +where table_name='t1'; +column_name data_type CHARACTER_OCTET_LENGTH CHARACTER_MAXIMUM_LENGTH +f1 longblob 4294967295 4294967295 +f2 longtext 4294967295 4294967295 +drop table t1; +create table t1(f1 tinyint, f2 SMALLINT, f3 mediumint, f4 int, +f5 BIGINT, f6 BIT, f7 bit(64)); +select column_name, NUMERIC_PRECISION, NUMERIC_SCALE +from information_schema.columns +where table_name='t1'; +column_name NUMERIC_PRECISION NUMERIC_SCALE +f1 3 NULL +f2 5 NULL +f3 7 NULL +f4 10 NULL +f5 19 NULL +f6 1 NULL +f7 64 NULL +drop table t1; +create table t1 (f1 integer); +create trigger tr1 after insert on t1 for each row set @test_var=42; +use information_schema; +select trigger_schema, trigger_name from triggers where +trigger_name='tr1'; +trigger_schema trigger_name +test tr1 +use test; +drop table t1; diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 3da5cc7bd11..ece30924055 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -16,11 +16,13 @@ TABLE_PRIVILEGES COLUMN_PRIVILEGES TABLE_CONSTRAINTS KEY_COLUMN_USAGE +TRIGGERS show tables from INFORMATION_SCHEMA like 'T%'; Tables_in_information_schema (T%) TABLES TABLE_PRIVILEGES TABLE_CONSTRAINTS +TRIGGERS create database `inf%`; use `inf%`; show tables; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 2c73cbeeea4..2bdec5125dd 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1452,16 +1452,16 @@ Error 1146 Table 'test.t4' doesn't exist checksum table t1, t2, t3, t4; Table Checksum test.t1 2948697075 -test.t2 1157260244 -test.t3 1157260244 +test.t2 3835700799 +test.t3 3835700799 test.t4 NULL Warnings: Error 1146 Table 'test.t4' doesn't exist checksum table t1, t2, t3, t4 extended; Table Checksum test.t1 3092701434 -test.t2 1157260244 -test.t3 1157260244 +test.t2 3835700799 +test.t3 3835700799 test.t4 NULL Warnings: Error 1146 Table 'test.t4' doesn't exist diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 3ad8571aadd..bce02a1cb0f 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -354,3 +354,28 @@ t1 CREATE TABLE `t1` ( KEY `a` (`a`,`b`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null unique); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI +b varchar(20) NO UNI +drop table t1; +create table t1 (a int not null primary key, b int not null unique); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI +b int(11) NO UNI +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, unique (b(10))); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI +b varchar(20) NO UNI +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, c varchar(20) not null, unique(b(10),c(10))); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI +b varchar(20) NO MUL +c varchar(20) NO +drop table t1; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index be2003bbc67..917724580cf 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1,6 +1,5 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; -drop database if exists db1; drop view if exists v1, v2, v3; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); @@ -357,46 +356,6 @@ CREATE TABLE `t1` ( 2 3 drop table t1; -create table t1(a int); -create view v1 as select * from t1; - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -DROP TABLE IF EXISTS `t1`; -CREATE TABLE `t1` ( - `a` int(11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - - -/*!40000 ALTER TABLE `t1` DISABLE KEYS */; -LOCK TABLES `t1` WRITE; -UNLOCK TABLES; -/*!40000 ALTER TABLE `t1` ENABLE KEYS */; -DROP TABLE IF EXISTS `v1`; -DROP VIEW IF EXISTS `v1`; -CREATE TABLE `v1` ( - `a` int(11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; -DROP TABLE IF EXISTS `v1`; -DROP VIEW IF EXISTS `v1`; -CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - -drop view v1; -drop table t1; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -605,38 +564,6 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; -CREATE TABLE t1 (a char(10)); -INSERT INTO t1 VALUES ('\''); - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -DROP TABLE IF EXISTS `t1`; -CREATE TABLE `t1` ( - `a` char(10) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - - -/*!40000 ALTER TABLE `t1` DISABLE KEYS */; -LOCK TABLES `t1` WRITE; -INSERT INTO `t1` VALUES ('\''); -UNLOCK TABLES; -/*!40000 ALTER TABLE `t1` ENABLE KEYS */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - -DROP TABLE t1; CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); INSERT INTO t1 VALUES (4),(5),(6); @@ -1428,59 +1355,6 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; -create database db1; -use db1; -CREATE TABLE t2 ( -a varchar(30) default NULL, -KEY a (a(5)) -); -INSERT INTO t2 VALUES ('alfred'); -INSERT INTO t2 VALUES ('angie'); -INSERT INTO t2 VALUES ('bingo'); -INSERT INTO t2 VALUES ('waffle'); -INSERT INTO t2 VALUES ('lemon'); -create view v2 as select * from t2 where a like 'a%' with check option; - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -DROP TABLE IF EXISTS `t2`; -CREATE TABLE `t2` ( - `a` varchar(30) default NULL, - KEY `a` (`a`(5)) -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - - -/*!40000 ALTER TABLE `t2` DISABLE KEYS */; -LOCK TABLES `t2` WRITE; -INSERT INTO `t2` VALUES ('alfred'),('angie'),('bingo'),('waffle'),('lemon'); -UNLOCK TABLES; -/*!40000 ALTER TABLE `t2` ENABLE KEYS */; -DROP TABLE IF EXISTS `v2`; -DROP VIEW IF EXISTS `v2`; -CREATE TABLE `v2` ( - `a` varchar(30) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; -DROP TABLE IF EXISTS `v2`; -DROP VIEW IF EXISTS `v2`; -CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from `db1`.`t2` where (`db1`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - -drop table t2; -drop view v2; -drop database db1; CREATE DATABASE mysqldump_test_db; USE mysqldump_test_db; CREATE TABLE t1 ( a INT ); @@ -1647,6 +1521,132 @@ insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thir </database> </mysqldump> drop table t1, t2; +create table t1(a int); +create view v1 as select * from t1; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `v1`; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE TABLE `v1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +/*!50001 DROP TABLE IF EXISTS `v1`*/; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`*/; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop view v1; +drop table t1; +create database mysqldump_test_db; +use mysqldump_test_db; +CREATE TABLE t2 ( +a varchar(30) default NULL, +KEY a (a(5)) +); +INSERT INTO t2 VALUES ('alfred'); +INSERT INTO t2 VALUES ('angie'); +INSERT INTO t2 VALUES ('bingo'); +INSERT INTO t2 VALUES ('waffle'); +INSERT INTO t2 VALUES ('lemon'); +create view v2 as select * from t2 where a like 'a%' with check option; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` varchar(30) default NULL, + KEY `a` (`a`(5)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +INSERT INTO `t2` VALUES ('alfred'),('angie'),('bingo'),('waffle'),('lemon'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; +DROP TABLE IF EXISTS `v2`; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE TABLE `v2` ( + `a` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1*/; +/*!50001 DROP TABLE IF EXISTS `v2`*/; +/*!50001 DROP VIEW IF EXISTS `v2`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED VIEW `mysqldump_test_db`.`v2` AS select `mysqldump_test_db`.`t2`.`a` AS `a` from `mysqldump_test_db`.`t2` where (`mysqldump_test_db`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION*/; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t2; +drop view v2; +drop database mysqldump_test_db; +use test; +CREATE TABLE t1 (a char(10)); +INSERT INTO t1 VALUES ('\''); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('\''); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +DROP TABLE t1; create table t1(a int, b int, c varchar(30)); insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three"); create view v3 as @@ -1673,3 +1673,205 @@ a b c 3 6 three drop view v1, v2, v3; drop table t1; +CREATE TABLE t1 (a int, b bigint default NULL); +CREATE TABLE t2 (a int); +create trigger trg1 before insert on t1 for each row +begin +if new.a > 10 then +set new.a := 10; +set new.a := 11; +end if; +end| +create trigger trg2 before update on t1 for each row begin +if old.a % 2 = 0 then set new.b := 12; end if; +end| +set sql_mode="traditional"| +create trigger trg3 after update on t1 for each row +begin +if new.a = -1 then +set @fired:= "Yes"; +end if; +end| +create trigger trg4 before insert on t2 for each row +begin +if new.a > 10 then +set @fired:= "No"; +end if; +end| +set sql_mode=default| +show triggers like "t1"; +Trigger Event Table Statement Timing Created sql_mode +trg1 INSERT t1 +begin +if new.a > 10 then +set new.a := 10; +set new.a := 11; +end if; +end BEFORE 0000-00-00 00:00:00 +trg2 UPDATE t1 begin +if old.a % 2 = 0 then set new.b := 12; end if; +end BEFORE 0000-00-00 00:00:00 +trg3 UPDATE t1 +begin +if new.a = -1 then +set @fired:= "Yes"; +end if; +end AFTER 0000-00-00 00:00:00 STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +INSERT INTO t1 (a) VALUES (1),(2),(3),(22); +update t1 set a = 4 where a=3; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL, + `b` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; +DELIMITER //; +/*!50003 SET SESSION SQL_MODE=""*/ // +/*!50003 CREATE TRIGGER `trg1` BEFORE INSERT ON `t1` FOR EACH ROW +begin +if new.a > 10 then +set new.a := 10; +set new.a := 11; +end if; +end*/ // + +/*!50003 SET SESSION SQL_MODE=""*/ // +/*!50003 CREATE TRIGGER `trg2` BEFORE UPDATE ON `t1` FOR EACH ROW begin +if old.a % 2 = 0 then set new.b := 12; end if; +end*/ // + +/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER"*/ // +/*!50003 CREATE TRIGGER `trg3` AFTER UPDATE ON `t1` FOR EACH ROW +begin +if new.a = -1 then +set @fired:= "Yes"; +end if; +end*/ // + +DELIMITER ;// +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/; + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/; +DELIMITER //; +/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER"*/ // +/*!50003 CREATE TRIGGER `trg4` BEFORE INSERT ON `t2` FOR EACH ROW +begin +if new.a > 10 then +set @fired:= "No"; +end if; +end*/ // + +DELIMITER ;// +/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/; + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL, + `b` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1,NULL),(2,NULL),(4,NULL),(11,NULL); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t1; +show tables; +Tables_in_test +t1 +t2 +show triggers; +Trigger Event Table Statement Timing Created sql_mode +trg1 INSERT t1 +begin +if new.a > 10 then +set new.a := 10; +set new.a := 11; +end if; +end BEFORE # +trg2 UPDATE t1 begin +if old.a % 2 = 0 then set new.b := 12; end if; +end BEFORE # +trg3 UPDATE t1 +begin +if new.a = -1 then +set @fired:= "Yes"; +end if; +end AFTER # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +trg4 INSERT t2 +begin +if new.a > 10 then +set @fired:= "No"; +end if; +end BEFORE # STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER +DROP TABLE t1, t2; diff --git a/mysql-test/r/ndb_config.result b/mysql-test/r/ndb_config.result new file mode 100644 index 00000000000..c2557f85c0b --- /dev/null +++ b/mysql-test/r/ndb_config.result @@ -0,0 +1,5 @@ +ndbd,1,localhost ndbd,2,localhost ndb_mgmd,3,localhost mysqld,4, mysqld,5, mysqld,6, mysqld,7, +1,localhost,41943040,12582912 2,localhost,41943040,12582912 +1 localhost 41943040 12582912 +2 localhost 41943040 12582912 +1 2 diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result new file mode 100644 index 00000000000..082ebe72ba4 --- /dev/null +++ b/mysql-test/r/not_embedded_server.result @@ -0,0 +1,5 @@ +prepare stmt1 from ' show full processlist '; +execute stmt1; +Id User Host db Command Time State Info +number root localhost test Execute time NULL show full processlist +deallocate prepare stmt1; diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index b9824cc4b81..7f746a3dbd8 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -369,3 +369,63 @@ select * from t1; id id2 1 1 drop table t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int, INDEX idx(a)); +CREATE TABLE t3 (b int, INDEX idx(b)); +CREATE TABLE t4 (b int, INDEX idx(b)); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1, 1), (3, 1); +INSERT INTO t3 VALUES +(NULL), (NULL), (NULL), (NULL), (NULL), +(NULL), (NULL), (NULL), (NULL), (NULL); +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t3 VALUES (2), (3); +ANALYZE table t1, t2, t3; +Table Op Msg_type Msg_text +test.t1 analyze status OK +test.t2 analyze status OK +test.t3 analyze status OK +SELECT COUNT(*) FROM t3; +COUNT(*) +15972 +EXPLAIN SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +LEFT JOIN t3 ON t2.b=t3.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 +1 SIMPLE t2 ref idx idx 5 test.t1.a 1 +1 SIMPLE t3 ref idx idx 5 test.t2.b 1 Using index +FLUSH STATUS ; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a +LEFT JOIN t3 ON t2.b=t3.b; +a a b b +1 1 1 NULL +2 NULL NULL NULL +3 3 1 NULL +4 NULL NULL NULL +SELECT FOUND_ROWS(); +FOUND_ROWS() +4 +SHOW STATUS LIKE "handler_read%"; +Variable_name Value +Handler_read_first 0 +Handler_read_key 6 +Handler_read_next 2 +Handler_read_prev 0 +Handler_read_rnd 0 +Handler_read_rnd_next 5 +DROP TABLE t1,t2,t3,t4; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index a19734d55b5..69871b2110b 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -577,3 +577,15 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; +a b c count +1 1 1 1 +1 1 NULL 1 +1 2 1 1 +1 2 NULL 1 +1 NULL NULL 2 +NULL NULL NULL 2 +DROP TABLE t1; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 64dc09f864c..5d0e1d703a6 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -2976,25 +2976,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 792d74231f2..da0421d2caa 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -2959,25 +2959,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 7dcb8546a83..ff52847a0dc 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -2960,25 +2960,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 77b1a242452..9af8f6ed6ce 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -2896,25 +2896,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 @@ -5908,25 +5908,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 0489c7ef078..b7d63b97c09 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -2959,25 +2959,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index b0049b3e943..c54c09cf6aa 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -2959,25 +2959,25 @@ Warnings: Warning 1265 Data truncated for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 Warnings: Warning 1264 Out of range value adjusted for column 'c13' at row 1 -Warning 1265 Data truncated for column 'c14' at row 1 +Warning 1264 Out of range value adjusted for column 'c14' at row 1 Warning 1265 Data truncated for column 'c15' at row 1 Warning 1264 Out of range value adjusted for column 'c16' at row 1 Warning 1264 Out of range value adjusted for column 'c17' at row 1 diff --git a/mysql-test/r/ps_grant.result b/mysql-test/r/ps_grant.result index 651ac171e5d..fdc1f97bb4c 100644 --- a/mysql-test/r/ps_grant.result +++ b/mysql-test/r/ps_grant.result @@ -54,6 +54,7 @@ my_col 4 execute s_t9 ; ERROR 42S02: Table 'mysqltest.t9' doesn't exist +deallocate prepare s_t9; revoke all privileges on mysqltest.t1 from second_user@localhost identified by 'looser' ; show grants for second_user@localhost ; @@ -87,8 +88,3 @@ revoke all privileges on test.t1 from drop_user@localhost ; prepare stmt3 from ' drop user drop_user@localhost '; ERROR HY000: This command is not supported in the prepared statement protocol yet drop user drop_user@localhost; -prepare stmt4 from ' show full processlist '; -execute stmt4; -Id User Host db Command Time State Info -number root localhost test Execute time NULL show full processlist -deallocate prepare stmt4; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 699d81d4cef..985b72ed401 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -852,6 +852,7 @@ Qcache_hits 6 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 4 +SET NAMES default; DROP TABLE t1; CREATE TABLE t1 (a int(1)); CREATE DATABASE mysqltest; @@ -1007,6 +1008,8 @@ abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba flush query cache; drop table t1, t2; +set GLOBAL query_cache_size=1355776 +#; flush status; CREATE TABLE t1 ( `date` datetime NOT NULL default '0000-00-00 00:00:00', @@ -1123,4 +1126,80 @@ a f1() 2 2 drop procedure p1// drop table t1// +flush query cache; +reset query cache; +flush status; +create table t1 (s1 int)// +create procedure f1 () begin +select sql_cache * from t1; +select sql_cache * from t1; +end;// +call f1(); +s1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +call f1(); +s1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +call f1(); +s1 +select sql_cache * from t1; +s1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +insert into t1 values (1); +select sql_cache * from t1; +s1 +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 5 +call f1(); +s1 +1 +call f1(); +s1 +1 +select sql_cache * from t1; +s1 +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 9 +drop procedure f1; +drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 5e0eec6305d..be8d5291ad9 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -69,12 +69,12 @@ master-bin.000002 346 Query 1 434 use `test`; insert into t1 values (1) master-bin.000002 434 Query 1 510 use `test`; drop table t1 show binary logs; Log_name File_size -master-bin.000001 0 +master-bin.000001 1389 master-bin.000002 510 start slave; show binary logs; Log_name File_size -slave-bin.000001 0 +slave-bin.000001 1559 slave-bin.000002 348 show binlog events in 'slave-bin.000001' from 4; Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index a6d3697987a..bf2ef98c87f 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -27,8 +27,8 @@ insert into t2 values (34),(67),(123); flush logs; show binary logs; Log_name File_size -master-bin.000001 0 -master-bin.000002 0 +master-bin.000001 592 +master-bin.000002 363 master-bin.000003 98 create table t3 select * from temp_table; select * from t3; @@ -43,12 +43,12 @@ start slave; purge master logs to 'master-bin.000002'; show master logs; Log_name File_size -master-bin.000002 0 +master-bin.000002 363 master-bin.000003 407 purge binary logs to 'master-bin.000002'; show binary logs; Log_name File_size -master-bin.000002 0 +master-bin.000002 363 master-bin.000003 407 purge master logs before now(); show binary logs; @@ -74,8 +74,8 @@ count(*) create table t4 select * from temp_table; show binary logs; Log_name File_size -master-bin.000003 0 -master-bin.000004 0 +master-bin.000003 4185 +master-bin.000004 4190 master-bin.000005 2032 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 64e09839f1b..15180abe8fd 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -237,7 +237,7 @@ select * from t1; a 10 delete from t1; -drop trigger t1.trg; +drop trigger trg; insert into t1 values (1); select * from t1; a @@ -248,7 +248,7 @@ master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 -master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger t1.trg +master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger trg master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) select * from t1; a diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d327b491ebf..a0f6bb7084f 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2492,6 +2492,99 @@ select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid id name gid uid ident level 1 fs NULL NULL 0 READ drop table t1,t2,t3; +CREATE TABLE t1 ( +acct_id int(11) NOT NULL default '0', +profile_id smallint(6) default NULL, +UNIQUE KEY t1$acct_id (acct_id), +KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); +CREATE TABLE t2 ( +profile_id smallint(6) default NULL, +queue_id int(11) default NULL, +seq int(11) default NULL, +KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); +CREATE TABLE t3 ( +id int(11) NOT NULL default '0', +qtype int(11) default NULL, +seq int(11) default NULL, +warn_lvl int(11) default NULL, +crit_lvl int(11) default NULL, +rr1 tinyint(4) NOT NULL default '0', +rr2 int(11) default NULL, +default_queue tinyint(4) NOT NULL default '0', +KEY t3$qtype (qtype), +KEY t3$id (id) +); +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), +(36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE +(pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND +(pq.queue_id = q.id) AND (q.rr1 <> 1); +COUNT(*) +4 +drop table t1,t2,t3; +create table t1 (f1 int); +insert into t1 values (1),(NULL); +create table t2 (f2 int, f3 int, f4 int); +create index idx1 on t2 (f4); +insert into t2 values (1,2,3),(2,4,6); +select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) +from t2 C where A.f4 = C.f4) or A.f3 IS NULL; +f2 +1 +NULL +drop table t1,t2; +create table t2 (a tinyint unsigned); +create index t2i on t2(a); +insert into t2 values (0), (254), (255); +explain select * from t2 where a > -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index t2i t2i 2 NULL 3 Using where; Using index +select * from t2 where a > -1; +a +0 +254 +255 +drop table t2; +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 +SELECT 50, 3, 3 FROM DUAL +WHERE NOT EXISTS +(SELECT * FROM t1 WHERE a = 50 AND b = 3); +SELECT * FROM t1; +a b c +50 3 3 +INSERT INTO t1 +SELECT 50, 3, 3 FROM DUAL +WHERE NOT EXISTS +(SELECT * FROM t1 WHERE a = 50 AND b = 3); +select found_rows(); +found_rows() +0 +SELECT * FROM t1; +a b c +50 3 3 +select count(*) from t1; +count(*) +1 +select found_rows(); +found_rows() +1 +select count(*) from t1 limit 2,3; +count(*) +select found_rows(); +found_rows() +0 +select SQL_CALC_FOUND_ROWS count(*) from t1 limit 2,3; +count(*) +select found_rows(); +found_rows() +1 +DROP TABLE t1; CREATE TABLE t1 ( city char(30) ); INSERT INTO t1 VALUES ('London'); INSERT INTO t1 VALUES ('Paris'); @@ -2593,51 +2686,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 1 SIMPLE t2 ref a a 23 test.t1.a 2 DROP TABLE t1, t2; -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); -SELECT * FROM t1 WHERE city='London'; -city -London -SELECT * FROM t1 WHERE city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city='London' AND city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -city -London -DROP TABLE t1; -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -a-b -0 -1 -18446744073709551615 -select a-b , (a-b < 0) from t1 order by 1; -a-b (a-b < 0) -0 0 -1 0 -18446744073709551615 0 -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -d (a-b >= 0) b -1 1 0 -0 1 1 -18446744073709551615 1 2 -select cast((a - b) as unsigned) from t1 order by 1; -cast((a - b) as unsigned) -0 -1 -18446744073709551615 -drop table t1; create table t1 (a int, b int); create table t2 like t1; select t1.a from (t1 inner join t2 on t1.a=t2.a) where t2.a=1; @@ -2711,49 +2759,3 @@ DROP TABLE t1,t2; select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; x'10' + 0 X'10' + 0 b'10' + 0 B'10' + 0 16 16 2 2 -CREATE TABLE t1 ( -acct_id int(11) NOT NULL default '0', -profile_id smallint(6) default NULL, -UNIQUE KEY t1$acct_id (acct_id), -KEY t1$profile_id (profile_id) -); -INSERT INTO t1 VALUES (132,17),(133,18); -CREATE TABLE t2 ( -profile_id smallint(6) default NULL, -queue_id int(11) default NULL, -seq int(11) default NULL, -KEY t2$queue_id (queue_id) -); -INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); -CREATE TABLE t3 ( -id int(11) NOT NULL default '0', -qtype int(11) default NULL, -seq int(11) default NULL, -warn_lvl int(11) default NULL, -crit_lvl int(11) default NULL, -rr1 tinyint(4) NOT NULL default '0', -rr2 int(11) default NULL, -default_queue tinyint(4) NOT NULL default '0', -KEY t3$qtype (qtype), -KEY t3$id (id) -); -INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), -(36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); -SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q -WHERE -(pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND -(pq.queue_id = q.id) AND (q.rr1 <> 1); -COUNT(*) -4 -drop table t1,t2,t3; -create table t1 (f1 int); -insert into t1 values (1),(NULL); -create table t2 (f2 int, f3 int, f4 int); -create index idx1 on t2 (f4); -insert into t2 values (1,2,3),(2,4,6); -select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) -from t2 C where A.f4 = C.f4) or A.f3 IS NULL; -f2 -1 -NULL -drop table t1,t2; diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index 7a29db42dd9..5d458c40f34 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -60,9 +60,6 @@ a b 3 a 4 a 5 a -SELECT @@MAX_SEEKS_FOR_KEY; -@@MAX_SEEKS_FOR_KEY -4294967295 analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index fd63204e32f..04d49bf4b3b 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -2658,20 +2658,20 @@ call avg ()| drop procedure avg| drop procedure if exists bug6129| set @old_mode= @@sql_mode; -set @@sql_mode= ""; +set @@sql_mode= "ERROR_FOR_DIVISION_BY_ZERO"; create procedure bug6129() select @@sql_mode| call bug6129()| @@sql_mode - +ERROR_FOR_DIVISION_BY_ZERO set @@sql_mode= "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO"| call bug6129()| @@sql_mode -NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO +ERROR_FOR_DIVISION_BY_ZERO set @@sql_mode= "NO_ZERO_IN_DATE"| call bug6129()| @@sql_mode -NO_ZERO_IN_DATE +ERROR_FOR_DIVISION_BY_ZERO set @@sql_mode=@old_mode; drop procedure bug6129| drop procedure if exists bug9856| @@ -3099,4 +3099,28 @@ select @@sort_buffer_size| 1000000 set @@sort_buffer_size = @x| drop procedure bug9538| +drop procedure if exists bug8692| +create table t3 (c1 varchar(5), c2 char(5), c3 enum('one','two'), c4 text, c5 blob, c6 char(5), c7 varchar(5))| +insert into t3 values ('', '', '', '', '', '', NULL)| +Warnings: +Warning 1265 Data truncated for column 'c3' at row 1 +create procedure bug8692() +begin +declare v1 VARCHAR(10); +declare v2 VARCHAR(10); +declare v3 VARCHAR(10); +declare v4 VARCHAR(10); +declare v5 VARCHAR(10); +declare v6 VARCHAR(10); +declare v7 VARCHAR(10); +declare c8692 cursor for select c1,c2,c3,c4,c5,c6,c7 from t3; +open c8692; +fetch c8692 into v1,v2,v3,v4,v5,v6,v7; +select v1, v2, v3, v4, v5, v6, v7; +end| +call bug8692()| +v1 v2 v3 v4 v5 v6 v7 + NULL +drop procedure bug8692| +drop table t3| drop table t1,t2; diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index adc22cd1ac2..6299e8dcc88 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1245,3 +1245,44 @@ t1 CREATE TABLE `t1` ( `b` date NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +set @@sql_mode='traditional'; +create table t1 (d date); +insert into t1 values ('2000-10-00'); +ERROR 22007: Incorrect date value: '2000-10-00' for column 'd' at row 1 +insert into t1 values (1000); +ERROR 22007: Incorrect date value: '1000' for column 'd' at row 1 +insert into t1 values ('2000-10-01'); +update t1 set d = 1100; +ERROR 22007: Incorrect date value: '1100' for column 'd' at row 1 +select * from t1; +d +2000-10-01 +drop table t1; +set @@sql_mode='traditional'; +create table t1(a int, b timestamp); +alter table t1 add primary key(a); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(a int, b timestamp default 20050102030405); +alter table t1 add primary key(a); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` timestamp NOT NULL default '2005-01-02 03:04:05', + PRIMARY KEY (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @@sql_mode='traditional'; +create table t1(a bit(2)); +insert into t1 values(b'101'); +ERROR 22001: Data too long for column 'a' at row 1 +select * from t1; +a +drop table t1; diff --git a/mysql-test/r/timezone2.result b/mysql-test/r/timezone2.result index a90bdf9ad5b..df51a6aac9b 100644 --- a/mysql-test/r/timezone2.result +++ b/mysql-test/r/timezone2.result @@ -40,6 +40,12 @@ insert into t1 (i, ts) values Warnings: Warning 1299 Invalid TIMESTAMP value in column 'ts' at row 2 insert into t1 (i, ts) values +(unix_timestamp(20030330015959),20030330015959), +(unix_timestamp(20030330023000),20030330023000), +(unix_timestamp(20030330030000),20030330030000); +Warnings: +Warning 1299 Invalid TIMESTAMP value in column 'ts' at row 2 +insert into t1 (i, ts) values (unix_timestamp('2003-05-01 00:00:00'),'2003-05-01 00:00:00'); insert into t1 (i, ts) values (unix_timestamp('2003-10-26 01:00:00'),'2003-10-26 01:00:00'), @@ -54,6 +60,9 @@ i ts 1048985999 2003-03-30 00:59:59 1048986000 2003-03-30 01:00:00 1048986000 2003-03-30 01:00:00 +1048985999 2003-03-30 00:59:59 +1048986000 2003-03-30 01:00:00 +1048986000 2003-03-30 01:00:00 1051740000 2003-04-30 22:00:00 1067122800 2003-10-25 23:00:00 1067126400 2003-10-26 00:00:00 diff --git a/mysql-test/r/timezone_grant.result b/mysql-test/r/timezone_grant.result index dfe0b75ee43..3758f3c2645 100644 --- a/mysql-test/r/timezone_grant.result +++ b/mysql-test/r/timezone_grant.result @@ -47,6 +47,13 @@ select * from mysql.time_zone_name; ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' select Name, convert_tz('2004-11-30 12:00:00', Name, 'UTC') from mysql.time_zone_name; ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' +drop table t1, t2; +create table t1 (a int, b datetime); +create table t2 (a int, b varchar(40)); +update t1 set b = '2005-01-01 10:00'; +update t1 set b = convert_tz(b, 'UTC', 'UTC'); +update t1 join t2 on (t1.a = t2.a) set t1.b = '2005-01-01 10:00' where t2.b = 'foo'; +update t1 join t2 on (t1.a = t2.a) set t1.b = convert_tz('2005-01-01 10:00','UTC','UTC') where t2.b = 'foo'; delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; delete from mysql.tables_priv where user like 'mysqltest\_%'; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index efd09ba08fc..52bf307a686 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -12,13 +12,13 @@ insert into t1 values (1); select @a; @a 1 -drop trigger t1.trg; +drop trigger trg; create trigger trg before insert on t1 for each row set @a:=new.i; insert into t1 values (123); select @a; @a 123 -drop trigger t1.trg; +drop trigger trg; drop table t1; create table t1 (i int not null, j int); create trigger trg before insert on t1 for each row @@ -33,7 +33,7 @@ select * from t1| i j 1 10 2 3 -drop trigger t1.trg| +drop trigger trg| drop table t1| create table t1 (i int not null primary key); create trigger trg after insert on t1 for each row @@ -43,7 +43,7 @@ insert into t1 values (2),(3),(4),(5); select @a; @a 2:3:4:5 -drop trigger t1.trg; +drop trigger trg; drop table t1; create table t1 (aid int not null primary key, balance int not null default 0); insert into t1 values (1, 1000), (2,3000); @@ -65,7 +65,7 @@ Too big change for aid = 2 aid balance 1 1500 2 3000 -drop trigger t1.trg| +drop trigger trg| drop table t1| create table t1 (i int); insert into t1 values (1),(2),(3),(4); @@ -76,7 +76,7 @@ update t1 set i=3; select @total_change; @total_change 2 -drop trigger t1.trg; +drop trigger trg; drop table t1; create table t1 (i int); insert into t1 values (1),(2),(3),(4); @@ -87,7 +87,7 @@ delete from t1 where i <= 3; select @del_sum; @del_sum 6 -drop trigger t1.trg; +drop trigger trg; drop table t1; create table t1 (i int); insert into t1 values (1),(2),(3),(4); @@ -97,7 +97,7 @@ delete from t1 where i <> 0; select @del; @del 1 -drop trigger t1.trg; +drop trigger trg; drop table t1; create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row @@ -137,9 +137,9 @@ i j 1 20 2 -1 3 20 -drop trigger t1.trg1; -drop trigger t1.trg2; -drop trigger t1.trg3; +drop trigger trg1; +drop trigger trg2; +drop trigger trg3; drop table t1; create table t1 (id int not null primary key, data int); create trigger t1_bi before insert on t1 for each row @@ -197,7 +197,7 @@ select * from t2; event INSERT INTO t1 id=1 data='one' INSERT INTO t1 id=2 data='two' -drop trigger t1.t1_ai; +drop trigger t1_ai; create trigger t1_bi before insert on t1 for each row begin if exists (select id from t3 where id=new.fk) then @@ -271,6 +271,7 @@ id copy 3 NULL drop table t1, t2; create table t1 (i int); +create table t3 (i int); create trigger trg before insert on t1 for each row set @a:= old.i; ERROR HY000: There is no OLD row in on INSERT trigger create trigger trg before delete on t1 for each row set @a:= new.i; @@ -292,14 +293,19 @@ create trigger trg after insert on t1 for each row set @a:=1; ERROR HY000: Trigger already exists create trigger trg2 before insert on t1 for each row set @a:=1; ERROR HY000: Trigger already exists -drop trigger t1.trg; -drop trigger t1.trg; +create trigger trg before insert on t3 for each row set @a:=1; +ERROR HY000: Trigger already exists +create trigger trg2 before insert on t3 for each row set @a:=1; +drop trigger trg2; +drop trigger trg; +drop trigger trg; ERROR HY000: Trigger does not exist create view v1 as select * from t1; create trigger trg before insert on v1 for each row set @a:=1; ERROR HY000: 'test.v1' is not BASE TABLE drop view v1; drop table t1; +drop table t3; create temporary table t1 (i int); create trigger trg before insert on t1 for each row set @a:=1; ERROR HY000: Trigger's 't1' is view or temporary table @@ -307,7 +313,7 @@ drop table t1; create table t1 (x1col char); create trigger tx1 before insert on t1 for each row set new.x1col = 'x'; insert into t1 values ('y'); -drop trigger t1.tx1; +drop trigger tx1; drop table t1; create table t1 (i int) engine=myisam; insert into t1 values (1), (2); @@ -318,8 +324,8 @@ delete from t1; select @del_before, @del_after; @del_before @del_after 3 3 -drop trigger t1.trg1; -drop trigger t1.trg2; +drop trigger trg1; +drop trigger trg2; drop table t1; create table t1 (a int); create trigger trg1 before insert on t1 for each row set new.a= 10; @@ -336,6 +342,15 @@ create table t1 (i int); create trigger trg1 before insert on t1 for each row set @a:= 1; drop database mysqltest; use test; +create database mysqltest; +create table mysqltest.t1 (i int); +create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1; +ERROR HY000: Trigger in wrong schema +use mysqltest; +create trigger test.trg1 before insert on t1 for each row set @a:= 1; +ERROR HY000: Trigger in wrong schema +drop database mysqltest; +use test; create table t1 (i int, j int default 10, k int not null, key (k)); create table t2 (i int); insert into t1 (i, k) values (1, 1); @@ -549,7 +564,7 @@ i k 1 1 2 2 alter table t1 add primary key (i); -drop trigger t1.bi; +drop trigger bi; insert into t1 values (2, 4) on duplicate key update k= k + 10; ERROR 42S22: Unknown column 'bt' in 'NEW' select * from t1; @@ -578,5 +593,45 @@ create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); drop function bug5893; update t1 set col2 = 4; ERROR 42000: FUNCTION test.bug5893 does not exist -drop trigger t1.t1_bu; +drop trigger t1_bu; +drop table t1; +set sql_mode='ansi'; +create table t1 ("t1 column" int); +create trigger t1_bi before insert on t1 for each row set new."t1 column" = 5; +set sql_mode=""; +insert into t1 values (0); +create trigger t1_af after insert on t1 for each row set @a=10; +insert into t1 values (0); +select * from t1; +t1 column +5 +5 +select @a; +@a +10 +show triggers; +Trigger Event Table Statement Timing Created sql_mode +t1_bi INSERT t1 set new."t1 column" = 5 BEFORE # REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI +t1_af INSERT t1 set @a=10 AFTER # +drop table t1; +set sql_mode="traditional"; +create table t1 (a date); +insert into t1 values ('2004-01-00'); +ERROR 22007: Incorrect date value: '2004-01-00' for column 'a' at row 1 +set sql_mode=""; +create trigger t1_bi before insert on t1 for each row set new.a = '2004-01-00'; +set sql_mode="traditional"; +insert into t1 values ('2004-01-01'); +select * from t1; +a +2004-01-00 +set sql_mode=default; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` date default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show triggers; +Trigger Event Table Statement Timing Created sql_mode +t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # drop table t1; diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 98f7829ca1c..33c7e837997 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -100,12 +100,12 @@ create table t1 (t datetime); insert into t1 values (20030102030460),(20030102036301),(20030102240401), (20030132030401),(20031302030401),(100001202030401); Warnings: -Warning 1265 Data truncated for column 't' at row 1 -Warning 1265 Data truncated for column 't' at row 2 -Warning 1265 Data truncated for column 't' at row 3 -Warning 1265 Data truncated for column 't' at row 4 -Warning 1265 Data truncated for column 't' at row 5 -Warning 1265 Data truncated for column 't' at row 6 +Warning 1264 Out of range value adjusted for column 't' at row 1 +Warning 1264 Out of range value adjusted for column 't' at row 2 +Warning 1264 Out of range value adjusted for column 't' at row 3 +Warning 1264 Out of range value adjusted for column 't' at row 4 +Warning 1264 Out of range value adjusted for column 't' at row 5 +Warning 1264 Out of range value adjusted for column 't' at row 6 select * from t1; t 0000-00-00 00:00:00 diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c1039189a43..d39d2e3401d 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -946,6 +946,13 @@ t1 CREATE TABLE `t1` ( `sl` decimal(5,5) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (sl decimal(65, 30)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sl` decimal(65,30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; create table t1 ( f1 decimal unsigned not null default 17.49, f2 decimal unsigned not null default 17.68, @@ -969,3 +976,13 @@ select * from t1; f1 f2 f3 f4 f5 f6 f7 f8 1 18 99 100 104 200 1000 10000 drop table t1; +create table t1 ( +f0 decimal (30,30) zerofill not null DEFAULT 0, +f1 decimal (0,0) zerofill not null default 0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f0` decimal(30,30) unsigned zerofill NOT NULL default '0.000000000000000000000000000000', + `f1` decimal(10,0) unsigned zerofill NOT NULL default '0000000000' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index b0055346d61..42fb8064044 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -240,3 +240,14 @@ update t1, t2 set t1.a = t2.a where t2.b = t1.b; show warnings; Level Code Message drop table t1, t2; +create table t1(f1 int, f2 int); +create table t2(f3 int, f4 int); +create index idx on t2(f3); +insert into t1 values(1,0),(2,0); +insert into t2 values(1,1),(2,2); +UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); +select * from t1; +f1 f2 +1 1 +2 2 +drop table t1,t2; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 5468508165c..932be65532b 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -525,3 +525,11 @@ set @@warning_count=1; ERROR HY000: Variable 'warning_count' is a read only variable set @@global.error_count=1; ERROR HY000: Variable 'error_count' is a read only variable +set @@max_heap_table_size= 4294967296; +select @@max_heap_table_size > 0; +@@max_heap_table_size > 0 +1 +set global max_heap_table_size= 4294967296; +select @@global.max_heap_table_size > 0; +@@global.max_heap_table_size > 0 +1 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a132279c6bc..730e180cbd9 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1245,7 +1245,7 @@ select * from v1; s1 select * from t1; s1 -drop trigger t1.t1_bi; +drop trigger t1_bi; drop view v1; drop table t1; create table t1 (s1 tinyint); @@ -2016,3 +2016,34 @@ CALL p1(); DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; +create table t1(f1 datetime); +insert into t1 values('2005.01.01 12:0:0'); +create view v1 as select f1, subtime(f1, '1:1:1') as sb from t1; +select * from v1; +f1 sb +2005-01-01 12:00:00 2005-01-01 10:58:59 +drop view v1; +drop table t1; +CREATE TABLE t1 ( +aid int PRIMARY KEY, +fn varchar(20) NOT NULL, +ln varchar(20) NOT NULL +); +CREATE TABLE t2 ( +aid int NOT NULL, +pid int NOT NULL +); +INSERT INTO t1 VALUES(1,'a','b'), (2,'c','d'); +INSERT INTO t2 values (1,1), (2,1), (2,2); +CREATE VIEW v1 AS SELECT t1.*,t2.pid FROM t1,t2 WHERE t1.aid = t2.aid; +SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM t1,t2 +WHERE t1.aid = t2.aid GROUP BY pid; +pid GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) +1 a b,c d +2 c d +SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM v1 GROUP BY pid; +pid GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) +1 a b,c d +2 c d +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/alias.test b/mysql-test/t/alias.test index cfa8ec7f18a..2746409c7e5 100644 --- a/mysql-test/t/alias.test +++ b/mysql-test/t/alias.test @@ -86,3 +86,5 @@ UPDATE t1 SET t1.xstatus_vor = Greatest(t1.xstatus_vor,1) WHERE t1.aufnr = ASC LIMIT 1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index c3ba2c8a7a4..a237b21f403 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -360,3 +360,5 @@ create table t1 ( a timestamp ); --error 1089 alter table t1 add unique ( a(1) ); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index f5523f83226..2003feee163 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -48,6 +48,8 @@ insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),( select * from t1 procedure analyse(); drop table t1; +# End of 4.1 tests + #decimal-related test create table t1 (df decimal(5,1)); diff --git a/mysql-test/t/analyze.test b/mysql-test/t/analyze.test index faf30279c68..3c3b3933bc3 100644 --- a/mysql-test/t/analyze.test +++ b/mysql-test/t/analyze.test @@ -1,16 +1,18 @@ # # Bug #10901 Analyze Table on new table destroys table # This is minimal test case to get error -# The problem was that analyze table wrote the shared state to the file and this -# didn't include the inserts while locked. A check was needed to ensure that -# state information was not updated when executing analyze table for a locked table. -# The analyze table had to be within locks and check table had to be after unlocking -# since then it brings the wrong state from disk rather than from the currently -# correct internal state. The insert is needed since it changes the file state, -# number of records. -# The fix is to synchronise the state of the shared state and the current state before -# calling mi_state_info_write +# The problem was that analyze table wrote the shared state to the +# file and this didn't include the inserts while locked. A check was +# needed to ensure that state information was not updated when +# executing analyze table for a locked table. The analyze table had +# to be within locks and check table had to be after unlocking since +# then it brings the wrong state from disk rather than from the +# currently correct internal state. The insert is needed since it +# changes the file state, number of records. The fix is to +# synchronise the state of the shared state and the current state +# before calling mi_state_info_write # + create table t1 (a bigint); lock tables t1 write; insert into t1 values(0); @@ -37,3 +39,4 @@ check table t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/ansi.test b/mysql-test/t/ansi.test index 9d235df5b46..444bf982b8a 100644 --- a/mysql-test/t/ansi.test +++ b/mysql-test/t/ansi.test @@ -25,3 +25,5 @@ SELECT id FROM t1 GROUP BY id2; drop table t1; SET @@SQL_MODE=""; + +# End of 4.1 tests diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index a42a42b2a4e..d756bf765be 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1333,3 +1333,5 @@ INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily','' # Cleanup, test is over # drop table t1, t2, t4; + +# End of 4.1 tests diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index afc4c722051..b20fe80303d 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -219,6 +219,8 @@ INSERT INTO t1 (b) VALUES ('bbbb'); CHECK TABLE t1; DROP TABLE IF EXISTS t1; +# End of 4.1 tests + # # Bug #11080 & #11005 Multi-row REPLACE fails on a duplicate key error # diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test index 8b3a46724ab..3034129ad4b 100644 --- a/mysql-test/t/backup.test +++ b/mysql-test/t/backup.test @@ -52,3 +52,5 @@ unlock tables; connection con1; reap; drop table t5; + +# End of 4.1 tests diff --git a/mysql-test/t/bdb-alter-table-1.test b/mysql-test/t/bdb-alter-table-1.test index 18b6c70758f..9cb469a8df6 100644 --- a/mysql-test/t/bdb-alter-table-1.test +++ b/mysql-test/t/bdb-alter-table-1.test @@ -14,3 +14,5 @@ select * from t1; alter table t1 drop column test; # Now we do a reboot and continue with the next test + +# End of 4.1 tests diff --git a/mysql-test/t/bdb-alter-table-2.test b/mysql-test/t/bdb-alter-table-2.test index a474efe42e1..15b8938a11d 100644 --- a/mysql-test/t/bdb-alter-table-2.test +++ b/mysql-test/t/bdb-alter-table-2.test @@ -6,3 +6,5 @@ -- source include/have_bdb.inc select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/bdb-crash.test b/mysql-test/t/bdb-crash.test index 3cd78821000..75f4d04d5df 100644 --- a/mysql-test/t/bdb-crash.test +++ b/mysql-test/t/bdb-crash.test @@ -47,3 +47,5 @@ set autocommit=0; insert into t1 values(1); analyze table t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/bdb-deadlock.test b/mysql-test/t/bdb-deadlock.test index 5e6ca666cc2..88243cfc860 100644 --- a/mysql-test/t/bdb-deadlock.test +++ b/mysql-test/t/bdb-deadlock.test @@ -55,3 +55,5 @@ select * from t2; commit; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/bdb-deadlock.tminus b/mysql-test/t/bdb-deadlock.tminus index d86403fcffc..3918a8ffe9d 100644 --- a/mysql-test/t/bdb-deadlock.tminus +++ b/mysql-test/t/bdb-deadlock.tminus @@ -55,3 +55,5 @@ select * from t2; commit; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/bdb.test b/mysql-test/t/bdb.test index f4895318818..c1abe011be4 100644 --- a/mysql-test/t/bdb.test +++ b/mysql-test/t/bdb.test @@ -937,6 +937,8 @@ SELECT id FROM t1 WHERE (list_id = 1) AND (term = "lettera"); SELECT id FROM t1 WHERE (list_id = 1) AND (term = "letterd"); DROP TABLE t1; +# End of 4.1 tests + # # alter temp table # diff --git a/mysql-test/t/bdb_cache.test b/mysql-test/t/bdb_cache.test index 401456711ac..85328920d71 100644 --- a/mysql-test/t/bdb_cache.test +++ b/mysql-test/t/bdb_cache.test @@ -49,3 +49,5 @@ show status like "Qcache_hits"; commit; show status like "Qcache_queries_in_cache"; drop table if exists t1, t2, t3; + +# End of 4.1 tests diff --git a/mysql-test/t/bench_count_distinct.test b/mysql-test/t/bench_count_distinct.test index 3ffb95a69c2..131208f1fa1 100644 --- a/mysql-test/t/bench_count_distinct.test +++ b/mysql-test/t/bench_count_distinct.test @@ -18,3 +18,5 @@ enable_query_log; select count(distinct n) from t1; explain extended select count(distinct n) from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 99c8a13d0b5..5c06ef89676 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -104,6 +104,8 @@ t2.value64=t1.value64; drop table t1, t2; +# End of 4.1 tests + # # Test of CREATE ... SELECT and unsigned integers # diff --git a/mysql-test/t/binary.test b/mysql-test/t/binary.test index 54ad8e92237..02773b32302 100644 --- a/mysql-test/t/binary.test +++ b/mysql-test/t/binary.test @@ -87,3 +87,5 @@ drop table t1; create table t1 (a binary); show create table t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/blackhole.test b/mysql-test/t/blackhole.test index d1fcfc971a9..257770d311c 100644 --- a/mysql-test/t/blackhole.test +++ b/mysql-test/t/blackhole.test @@ -125,3 +125,5 @@ let $VERSION=`select version()`; show binlog events; drop table t1,t2,t3; + +# End of 4.1 tests diff --git a/mysql-test/t/bool.test b/mysql-test/t/bool.test index 53230dd5fa3..34c51c648d3 100644 --- a/mysql-test/t/bool.test +++ b/mysql-test/t/bool.test @@ -58,3 +58,5 @@ select ifnull(A, 'N') as A, ifnull(B, 'N') as B, ifnull(not A, 'N') as nA, ifnul select ifnull(A=1, 'N') as A, ifnull(B=1, 'N') as B, ifnull(not (A=1), 'N') as nA, ifnull(not (B=1), 'N') as nB, ifnull((A=1) and (B=1), 'N') as AB, ifnull(not ((A=1) and (B=1)), 'N') as `n(AB)`, ifnull((not (A=1) or not (B=1)), 'N') as nAonB, ifnull((A=1) or (B=1), 'N') as AoB, ifnull(not((A=1) or (B=1)), 'N') as `n(AoB)`, ifnull(not (A=1) and not (B=1), 'N') as nAnB from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/bulk_replace.test b/mysql-test/t/bulk_replace.test index 755d34083f8..4e567c43104 100644 --- a/mysql-test/t/bulk_replace.test +++ b/mysql-test/t/bulk_replace.test @@ -11,3 +11,4 @@ select * from t1; check table t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index e942333d5fe..555e34d5cf2 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -122,6 +122,9 @@ SELECT 'case+union+test' UNION SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; +# End of 4.1 tests + + # # Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL # diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 356b69daf38..2049c17580e 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -156,6 +156,9 @@ select cast(concat('184467440','73709551615') as signed); select cast(repeat('1',20) as unsigned); select cast(repeat('1',20) as signed); +# End of 4.1 tests + + #decimal-related additions select cast('1.2' as decimal(3,2)); select 1e18 * cast('1.2' as decimal(3,2)); diff --git a/mysql-test/t/check.test b/mysql-test/t/check.test index c502655818d..8d9d70bd29a 100644 --- a/mysql-test/t/check.test +++ b/mysql-test/t/check.test @@ -22,6 +22,8 @@ connection con1; reap; drop table t1; +# End of 4.1 tests + # # Bug #9897 Views: 'Check Table' crashes MySQL, with a view and a table # in the statement diff --git a/mysql-test/t/comments.test b/mysql-test/t/comments.test index 087df60f3f5..52273ec9523 100644 --- a/mysql-test/t/comments.test +++ b/mysql-test/t/comments.test @@ -17,3 +17,5 @@ select 1 --2 select 1 # The rest of the row will be ignored ; /* line with only comment */; + +# End of 4.1 tests diff --git a/mysql-test/t/compare.test b/mysql-test/t/compare.test index bc20786227b..a42ba5ac88a 100644 --- a/mysql-test/t/compare.test +++ b/mysql-test/t/compare.test @@ -35,3 +35,5 @@ DROP TABLE t1; SELECT CHAR(31) = '', '' = CHAR(31); # Extra test SELECT CHAR(30) = '', '' = CHAR(30); + +# End of 4.1 tests diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 5d2d53a2a90..64b170970ca 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -76,3 +76,5 @@ show tables; delete from mysql.user where user=_binary"test"; flush privileges; + +# End of 4.1 tests diff --git a/mysql-test/t/consistent_snapshot.test b/mysql-test/t/consistent_snapshot.test index 7afdae36325..8da8e9ce660 100644 --- a/mysql-test/t/consistent_snapshot.test +++ b/mysql-test/t/consistent_snapshot.test @@ -39,3 +39,5 @@ select * from t1; # if consistent snapshot was not set, as expected, we commit; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/constraints.test b/mysql-test/t/constraints.test index dbc34a0dff1..ed268ab5846 100644 --- a/mysql-test/t/constraints.test +++ b/mysql-test/t/constraints.test @@ -27,3 +27,5 @@ alter table t1 add constraint unique key_1(a); alter table t1 add constraint constraint_2 unique key_2(a); show create table t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/count_distinct.test b/mysql-test/t/count_distinct.test index be67026e268..e63bdabdb95 100644 --- a/mysql-test/t/count_distinct.test +++ b/mysql-test/t/count_distinct.test @@ -55,6 +55,8 @@ create table t1 (f int); select count(distinct f) from t1; drop table t1; +# End of 4.1 tests + # # Bug #6515 # diff --git a/mysql-test/t/count_distinct2.test b/mysql-test/t/count_distinct2.test index 2b982e3e620..8dcb2a70065 100644 --- a/mysql-test/t/count_distinct2.test +++ b/mysql-test/t/count_distinct2.test @@ -79,3 +79,4 @@ select count(distinct s) from t1; show status like 'Created_tmp_disk_tables'; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/count_distinct3.test b/mysql-test/t/count_distinct3.test index 9d2bb0d139a..52a4f271dac 100644 --- a/mysql-test/t/count_distinct3.test +++ b/mysql-test/t/count_distinct3.test @@ -56,3 +56,5 @@ SELECT COUNT(DISTINCT id) FROM t1 GROUP BY grp; DROP TABLE t1; set @@read_buffer_size=default; + +# End of 4.1 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index d870ff368d3..4e86a51e131 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -39,7 +39,7 @@ drop table if exists t1; --error 1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap; --- error 1044,1 +-- error 1049 create table not_existing_database.test (a int); --error 1103 create table `a/a` (a int); @@ -305,7 +305,7 @@ select * from t2; create table t3 like t1; --error 1050 create table t3 like mysqltest.t3; ---error ER_DBACCESS_DENIED_ERROR,1 +--error 1049 create table non_existing_database.t1 like t1; --error 1051 create table t3 like non_existing_table; @@ -514,3 +514,5 @@ create table test.t1 like x; --disable_warnings drop table if exists test.t1; --enable_warnings + +# End of 4.1 tests diff --git a/mysql-test/t/create_select_tmp.test b/mysql-test/t/create_select_tmp.test index d81a3799d98..2e4c0f22997 100644 --- a/mysql-test/t/create_select_tmp.test +++ b/mysql-test/t/create_select_tmp.test @@ -27,3 +27,5 @@ select * from t2; CREATE TEMPORARY TABLE t2 ( PRIMARY KEY (a) ) ENGINE=MYISAM SELECT a FROM t1; --error 1146; select * from t2; + +# End of 4.1 tests diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 591fab3961a..2ac46d75f9a 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1313,3 +1313,5 @@ INSERT INTO t1 VALUES (9410,9412); select period from t1; drop table if exists t1,t2,t3,t4; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_big5.test b/mysql-test/t/ctype_big5.test index b5cf610d941..e4fb1d2a32b 100644 --- a/mysql-test/t/ctype_big5.test +++ b/mysql-test/t/ctype_big5.test @@ -14,8 +14,10 @@ SET @test_collation= 'big5_chinese_ci'; SET NAMES big5; SET collation_connection='big5_chinese_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc SET collation_connection='big5_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc # # Bugs#9357: TEXT columns break string with special word in BIG5 charset. @@ -25,3 +27,5 @@ CREATE TABLE t1 (a text) character set big5; INSERT INTO t1 VALUES ('ùØ'); SELECT * FROM t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_collate.test b/mysql-test/t/ctype_collate.test index b65067a36cf..e59693680bf 100644 --- a/mysql-test/t/ctype_collate.test +++ b/mysql-test/t/ctype_collate.test @@ -206,3 +206,5 @@ EXPLAIN SELECT * FROM t1 WHERE s1 LIKE 'a' COLLATE latin1_german1_ci; EXPLAIN SELECT * FROM t1 WHERE s2 LIKE 'a' COLLATE latin1_german1_ci; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_cp1250_ch.test b/mysql-test/t/ctype_cp1250_ch.test index 814da628fb7..ea4b35a44a3 100644 --- a/mysql-test/t/ctype_cp1250_ch.test +++ b/mysql-test/t/ctype_cp1250_ch.test @@ -22,3 +22,5 @@ INSERT INTO t1 VALUES ('2005-01-1'); SELECT * FROM t1 WHERE popisek = '2005-01-1'; SELECT * FROM t1 WHERE popisek LIKE '2005-01-1'; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_cp1251.test b/mysql-test/t/ctype_cp1251.test index 76873e6fa0e..1aafe7b7266 100644 --- a/mysql-test/t/ctype_cp1251.test +++ b/mysql-test/t/ctype_cp1251.test @@ -46,3 +46,5 @@ insert into t1 (a) values ('air'), select * from t1 where a like 'we_%'; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_create.test b/mysql-test/t/ctype_create.test index e97017ab416..e88004bbb8c 100644 --- a/mysql-test/t/ctype_create.test +++ b/mysql-test/t/ctype_create.test @@ -98,3 +98,5 @@ show create database mysqltest2; drop database mysqltest2; --error 1046 ALTER DATABASE DEFAULT CHARACTER SET latin2; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_eucjpms.test b/mysql-test/t/ctype_eucjpms.test index cec1e2a9861..3609407fe96 100644 --- a/mysql-test/t/ctype_eucjpms.test +++ b/mysql-test/t/ctype_eucjpms.test @@ -346,6 +346,18 @@ DROP TABLE t2; DROP TABLE t3; DROP TABLE t4; +#Test bug#11717 +CREATE TABLE t1(c1 varchar(10)) default character set = eucjpms; + +insert into t1 values(_ucs2 0x00F7); +insert into t1 values(_eucjpms 0xA1E0); +insert into t1 values(_ujis 0xA1E0); +insert into t1 values(_sjis 0x8180); +insert into t1 values(_cp932 0x8180); + +SELECT HEX(c1) FROM t1; + +DROP TABLE t1; SET collation_connection='eucjpms_japanese_ci'; -- source include/ctype_filesort.inc diff --git a/mysql-test/t/ctype_gbk.test b/mysql-test/t/ctype_gbk.test new file mode 100644 index 00000000000..2210891454e --- /dev/null +++ b/mysql-test/t/ctype_gbk.test @@ -0,0 +1,32 @@ +-- source include/have_gbk.inc + +# +# Tests with the gbk character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET @test_character_set= 'gbk'; +SET @test_collation= 'gbk_chinese_ci'; +-- source include/ctype_common.inc + +SET NAMES gbk; +SET collation_connection='gbk_chinese_ci'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +SET collation_connection='gbk_bin'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc + +# +# Bug#11987 mysql will truncate the text when +# the text contain GBK char:"0xA3A0" and "0xA1" +# +SET NAMES gbk; +CREATE TABLE t1 (a text) character set gbk; +INSERT INTO t1 VALUES (0xA3A0),(0xA1A1); +SELECT hex(a) FROM t1 ORDER BY a; +DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test index 6006ee4c527..1b83373da29 100644 --- a/mysql-test/t/ctype_latin1.test +++ b/mysql-test/t/ctype_latin1.test @@ -75,3 +75,5 @@ SET collation_connection='latin1_bin'; --error 1064 CREATE TABLE „a (a int); SELECT '„a' as str; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index 88eb840a787..d6a11a22857 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -133,6 +133,8 @@ ALTER TABLE t1 ADD KEY ifword(col1); SELECT * FROM t1 WHERE col1='ß' ORDER BY col1, BINARY col1; DROP TABLE t1; +# End of 4.1 tests + # # Bug#9509 # diff --git a/mysql-test/t/ctype_latin2.test b/mysql-test/t/ctype_latin2.test index cc232adeaec..676b472e7b8 100644 --- a/mysql-test/t/ctype_latin2.test +++ b/mysql-test/t/ctype_latin2.test @@ -48,3 +48,5 @@ a, lower(a) l, upper(a) u from t1 order by ha; # SELECT group_concat(a collate latin2_croatian_ci order by binary a) from t1 group by a collate latin2_croatian_ci; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_many.test b/mysql-test/t/ctype_many.test index 454e2c63cbb..22e844c6868 100644 --- a/mysql-test/t/ctype_many.test +++ b/mysql-test/t/ctype_many.test @@ -209,3 +209,5 @@ SET CHARACTER SET 'binary'; SELECT * FROM t1; SELECT min(comment),count(*) FROM t1 GROUP BY ucs2_f; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_mb.test b/mysql-test/t/ctype_mb.test index b0ccab8e345..6e369e3fa0b 100644 --- a/mysql-test/t/ctype_mb.test +++ b/mysql-test/t/ctype_mb.test @@ -24,3 +24,5 @@ ALTER TABLE t1 CHANGE a a CHAR(4) CHARACTER SET utf8; SHOW CREATE TABLE t1; SHOW KEYS FROM t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test index 0e5e954c720..9949ef88da4 100644 --- a/mysql-test/t/ctype_recoding.test +++ b/mysql-test/t/ctype_recoding.test @@ -179,3 +179,5 @@ select rpad(c1,3,'ö'), rpad('ö',3,c1) from t1; # TODO #select case c1 when 'ß' then 'ß' when 'ö' then 'ö' else 'c' end from t1; #select export_set(5,c1,'ö'), export_set(5,'ö',c1) from t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_sjis.test b/mysql-test/t/ctype_sjis.test index 50d286f28b9..252f0a0b6c8 100644 --- a/mysql-test/t/ctype_sjis.test +++ b/mysql-test/t/ctype_sjis.test @@ -66,8 +66,10 @@ drop table t1; SET collation_connection='sjis_japanese_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc SET collation_connection='sjis_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc # Check parsing of string literals in SJIS with multibyte characters that # have an embedded \ in them. (Bug #8303) @@ -75,3 +77,5 @@ SET collation_connection='sjis_bin'; --character_set sjis SET NAMES sjis; SELECT HEX('²“‘@\Œ\') FROM DUAL; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_tis620.test b/mysql-test/t/ctype_tis620.test index 87047db9b54..d649828eda3 100644 --- a/mysql-test/t/ctype_tis620.test +++ b/mysql-test/t/ctype_tis620.test @@ -157,3 +157,5 @@ SET collation_connection='tis620_thai_ci'; -- source include/ctype_filesort.inc SET collation_connection='tis620_bin'; -- source include/ctype_filesort.inc + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index e5c2acc8b4e..098ea33c6b2 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -456,6 +456,8 @@ drop table t1; SET collation_connection='utf8_unicode_ci'; -- source include/ctype_filesort.inc +# End of 4.1 tests + # # Check UPPER/LOWER changeing length # diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index d032c1249df..668edb3fafe 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -419,6 +419,8 @@ insert into t1 values (0x005b); select hex(a) from t1; drop table t1; +# End of 4.1 tests + # # Conversion from an UCS2 string to a decimal column # diff --git a/mysql-test/t/ctype_ucs_binlog.test b/mysql-test/t/ctype_ucs_binlog.test index 226f128c1c2..1ce55edd469 100644 --- a/mysql-test/t/ctype_ucs_binlog.test +++ b/mysql-test/t/ctype_ucs_binlog.test @@ -17,4 +17,4 @@ show binlog events from 98; --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 drop table t2; - +# End of 4.1 tests diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test index 407287be30a..88386500c9f 100644 --- a/mysql-test/t/ctype_ujis.test +++ b/mysql-test/t/ctype_ujis.test @@ -1145,5 +1145,9 @@ DROP TABLE t1; SET collation_connection='ujis_japanese_ci'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc SET collation_connection='ujis_bin'; -- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index bcb8ec2ba76..ce259f465d9 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -810,6 +810,27 @@ 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#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0 +# +set names utf8; +select 'a\\' like 'a\\'; +select 'aa\\' like 'a%\\'; + +create table t1 (a char(10), key(a)) character set utf8; +insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test"); +select * from t1 where a like "abc%"; +select * from t1 where a like concat("abc","%"); +select * from t1 where a like "ABC%"; +select * from t1 where a like "test%"; +select * from t1 where a like "te_t"; +select * from t1 where a like "%a%"; +select * from t1 where a like "%abcd%"; +select * from t1 where a like "%abc\d%"; +drop table t1; + + # # Bug#9557 MyISAM utf8 table crash # @@ -822,6 +843,8 @@ insert into t1 values (_utf8 0x5b); select hex(a) from t1; drop table t1; +# End of 4.1 tests + # # Test for bug #11484: wrong results for a DISTINCT varchar column in uft8. # diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index e8bd8965b96..f76f51fd12d 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -260,3 +260,5 @@ select str_to_date("2003-01-02 10:11:12.0012ABCD", "%Y-%m-%d %H:%i:%S.%f") as f1 select str_to_date("2003-04-05 g", "%Y-%m-%d") as f1, str_to_date("2003-04-05 10:11:12.101010234567", "%Y-%m-%d %H:%i:%S.%f") as f2; --enable_ps_protocol + +# End of 4.1 tests diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test index 513de990165..3030ac20304 100644 --- a/mysql-test/t/delayed.test +++ b/mysql-test/t/delayed.test @@ -36,3 +36,5 @@ insert delayed into t1 values (3,"this will give an","error"); show status like 'not_flushed_delayed_rows'; select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 265089adfa2..4284bd2a06d 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -153,6 +153,8 @@ DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1; SELECT * FROM t1; DROP TABLE t1; +# End of 4.1 tests + # # Test of multi-delete where we are not scanning the first table # diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 1e3ffd5160b..8d51b4666e7 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -248,3 +248,5 @@ insert into t3 values(3),(3); select * from t1 union distinct select * from t2 union all select * from t3; select * from (select * from t1 union distinct select * from t2 union all select * from t3) X; drop table t1, t2, t3; + +# End of 4.1 tests diff --git a/mysql-test/t/dirty_close.test b/mysql-test/t/dirty_close.test index f965df8cfea..f1c2c88ae83 100644 --- a/mysql-test/t/dirty_close.test +++ b/mysql-test/t/dirty_close.test @@ -12,3 +12,5 @@ create table t1 (n int); insert into t1 values (1),(2),(3); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index c5f96ec4201..7d397ff2112 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,3 +11,4 @@ ############################################################################## sp-goto:GOTO is currently is disabled - will be fixed in the future +ndb_condition_pushdown:Bug #12021 diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 057c9bd9239..562926d160c 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -340,3 +340,5 @@ create table t1 (id int, dsc varchar(50)); insert into t1 values (1, "line number one"), (2, "line number two"), (3, "line number three"); select distinct id, IFNULL(dsc, '-') from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 5e123ca0de8..2cd7866caf5 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -79,3 +79,5 @@ unlock tables; create table t1(n int); show tables; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/drop_temp_table.test b/mysql-test/t/drop_temp_table.test index dbe7959acb2..38c13e3e5e4 100644 --- a/mysql-test/t/drop_temp_table.test +++ b/mysql-test/t/drop_temp_table.test @@ -23,3 +23,5 @@ let $VERSION=`select version()`; --replace_column 2 # 5 # show binlog events; drop database `drop-temp+table-test`; + +# End of 4.1 tests diff --git a/mysql-test/t/empty_table.test b/mysql-test/t/empty_table.test index db0a8e6a247..e8e532832f4 100644 --- a/mysql-test/t/empty_table.test +++ b/mysql-test/t/empty_table.test @@ -11,3 +11,5 @@ select count(*) from t1; select * from t1; select * from t1 limit 0; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/endspace.test b/mysql-test/t/endspace.test index 3d27c44c3b9..c4d53450910 100644 --- a/mysql-test/t/endspace.test +++ b/mysql-test/t/endspace.test @@ -94,3 +94,5 @@ select text1, length(text1) from t1 where text1='teststring' or text1 like 'test select text1, length(text1) from t1 where text1='teststring' or text1 >= 'teststring\t'; select concat('|', text1, '|') from t1 order by text1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index b558c90b0c6..93668ffdd3d 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -29,3 +29,5 @@ select 1 from t1 order by t1.b; --error 1054 select count(*),b from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/exampledb.test b/mysql-test/t/exampledb.test index c60a9d7f930..946d25325dc 100644 --- a/mysql-test/t/exampledb.test +++ b/mysql-test/t/exampledb.test @@ -14,3 +14,5 @@ CREATE TABLE t1 ( ) ENGINE=example; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 050939e5ad2..2a3a23c5f96 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -41,3 +41,5 @@ insert into ÔÁ (ËÏÌ0) values (2); explain select ËÏÌ0 from ÔÁ where ËÏÌ0=1; drop table ÔÁÂ; set names latin1; + +# End of 4.1 tests diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index 1e33efe1c0e..255b9dc22d7 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1,19 +1,7 @@ ---source include/have_federated_db.inc - -source include/master-slave.inc; - -# remote table creation +source include/federated.inc; connection slave; ---replicate-ignore-db=federated -stop slave; - ---disable_warnings -# at this point, we are connected to master -DROP DATABASE IF EXISTS federated; ---enable_warnings -CREATE DATABASE federated; - +DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' @@ -21,14 +9,10 @@ CREATE TABLE federated.t1 ( DEFAULT CHARSET=latin1; connection master; ---disable_warnings -DROP DATABASE IF EXISTS federated; ---enable_warnings -CREATE DATABASE federated; - +DROP TABLE IF EXISTS federated.t1; # test too many items (malformed) in the comment string url ---error 1005 -eval CREATE TABLE federated.t1 ( +--error 1432 +CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) @@ -36,8 +20,8 @@ eval CREATE TABLE federated.t1 ( COMMENT='mysql://root@127.0.0.1:@/too/many/items/federated/t1'; # test not enough items (malformed) in the comment string url ---error 1005 -eval CREATE TABLE federated.t1 ( +--error 1432 +CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) @@ -46,7 +30,7 @@ eval CREATE TABLE federated.t1 ( # test non-existant table --replace_result $SLAVE_MYPORT SLAVE_PORT ---error 1219 +--error 1434 eval CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' @@ -56,7 +40,7 @@ eval CREATE TABLE federated.t1 ( # test bad user/password --replace_result $SLAVE_MYPORT SLAVE_PORT ---error 1218 +--error 1429 eval CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' @@ -150,12 +134,9 @@ CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '', `other` int(20) NOT NULL default '0', `created` datetime default '2004-04-04 04:04:04', - PRIMARY KEY (`id`), - KEY `name` (`name`), - KEY `other_key` (`other`)) + PRIMARY KEY (`id`)) DEFAULT CHARSET=latin1; - connection master; --replace_result $SLAVE_MYPORT SLAVE_PORT eval CREATE TABLE federated.t1 ( @@ -163,9 +144,7 @@ eval CREATE TABLE federated.t1 ( `name` varchar(32) NOT NULL default '', `other` int(20) NOT NULL default '0', `created` datetime default '2004-04-04 04:04:04', - PRIMARY KEY (`id`), - KEY `name` (`name`), - KEY `other_key` (`other`)) + PRIMARY KEY (`id`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; @@ -184,8 +163,84 @@ INSERT INTO federated.t1 (name, other) VALUES ('Tenth Name', 101010); SELECT * FROM federated.t1; # with PRIMARY KEY index_read_idx SELECT * FROM federated.t1 WHERE id = 5; -# with regular key index_read -> index_read_idx SELECT * FROM federated.t1 WHERE name = 'Sixth Name'; +SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name'; +SELECT * FROM federated.t1 WHERE name = 'Sixth Name' AND other = 44444; +SELECT * FROM federated.t1 WHERE name like '%th%'; +UPDATE federated.t1 SET name = '3rd name' WHERE id = 3; +SELECT * FROM federated.t1 WHERE name = '3rd name'; +UPDATE federated.t1 SET name = 'Third name' WHERE name = '3rd name'; +SELECT * FROM federated.t1 WHERE name = 'Third name'; +# rnd_post, ::position +SELECT * FROM federated.t1 ORDER BY id DESC; +SELECT * FROM federated.t1 ORDER BY name; +SELECT * FROM federated.t1 ORDER BY name DESC; +SELECT * FROM federated.t1 ORDER BY name ASC; +SELECT * FROM federated.t1 GROUP BY other; + +# ::delete_row +DELETE FROM federated.t1 WHERE id = 5; +SELECT * FROM federated.t1 WHERE id = 5; + +# ::delete_all_rows +DELETE FROM federated.t1; +SELECT * FROM federated.t1 WHERE id = 5; + +# previous test, but this time with indexes +connection slave; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( + `id` int(20) NOT NULL auto_increment, + `name` varchar(32) NOT NULL default '', + `other` int(20) NOT NULL default '0', + `created` datetime NOT NULL, + PRIMARY KEY (`id`), + key name(`name`), + key other(`other`), + key created(`created`)) + DEFAULT CHARSET=latin1; + +connection master; +DROP TABLE IF EXISTS federated.t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `id` int(20) NOT NULL auto_increment, + `name` varchar(32) NOT NULL default '', + `other` int(20) NOT NULL default '0', + `created` datetime NOT NULL, + PRIMARY KEY (`id`), + key name(`name`), + key other(`other`), + key created(`created`)) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +INSERT INTO federated.t1 (name, other, created) + VALUES ('First Name', 11111, '2004-01-01 01:01:01'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Second Name', 22222, '2004-01-23 02:43:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Third Name', 33333, '2004-02-14 02:14:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Fourth Name', 44444, '2003-04-05 00:00:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Fifth Name', 55555, '2001-02-02 02:02:02'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Sixth Name', 66666, '2005-06-06 15:30:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Seventh Name', 77777, '2003-12-12 18:32:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Eigth Name', 88888, '2005-03-12 11:00:00'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Ninth Name', 99999, '2005-03-12 11:00:01'); +INSERT INTO federated.t1 (name, other, created) + VALUES ('Tenth Name', 101010, '2005-03-12 12:00:01'); + +# basic select +SELECT * FROM federated.t1; +# with PRIMARY KEY index_read_idx +SELECT * FROM federated.t1 WHERE id = 5; +# with regular key index_read -> index_read_idx # regular and PRIMARY KEY index_read_idx SELECT * FROM federated.t1 WHERE id = 6 and name = 'Sixth Name'; # with regular key index_read -> index_read_idx @@ -211,7 +266,6 @@ SELECT * FROM federated.t1 WHERE id = 5; # ::delete_all_rows DELETE FROM federated.t1; SELECT * FROM federated.t1 WHERE id = 5; - connection slave; DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( @@ -253,8 +307,7 @@ SET name = 'Fourth Name', other = 'four four four' WHERE name IS NULL AND other IS NULL; UPDATE federated.t1 SET other = 'two two two two' WHERE name = 'Second Name'; -UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sec%'; -UPDATE federated.t1 SET other = 'seven seven' WHERE name = 'Seventh Name'; +UPDATE federated.t1 SET other = 'seven seven' WHERE name like 'Sev%'; UPDATE federated.t1 SET name = 'Tenth Name' WHERE other like 'fee fie%'; SELECT * FROM federated.t1 WHERE name IS NULL OR other IS NULL ; SELECT * FROM federated.t1; @@ -338,6 +391,201 @@ SELECT * FROM federated.t1 WHERE name='third'; SELECT * FROM federated.t1 WHERE other=2222; SELECT * FROM federated.t1 WHERE name='third' and other=2222; +# more multi-column indexes, in the primary key +connection slave; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( + `id` int NOT NULL auto_increment, + `col1` int(10) NOT NULL DEFAULT 0, + `col2` varchar(64) NOT NULL DEFAULT '', + `col3` int(20) NOT NULL, + `col4` int(40) NOT NULL, + primary key (`id`, `col1`, `col2`, `col3`, `col4`), + key col1(col1), + key col2(col2), + key col3(col3), + key col4(col4)); + +connection master; +DROP TABLE IF EXISTS federated.t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `id` int NOT NULL auto_increment, + `col1` int(10) NOT NULL DEFAULT 0, + `col2` varchar(64) NOT NULL DEFAULT '', + `col3` int(20) NOT NULL, + `col4` int(40) NOT NULL, + primary key (`id`, `col1`, `col2`, `col3`, `col4`), + key col1(col1), + key col2(col2), + key col3(col3), + key col4(col4)) + ENGINE="FEDERATED" + COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (1, 'one One', 11, 1111); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (2, 'Two two', 22, 2222); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (3, 'three Three', 33, 33333); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (4, 'fourfourfour', 444, 4444444); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (5, 'five 5 five five 5', 5, 55555); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (6, 'six six Sixsix', 6666, 6); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (7, 'seven Sevenseven', 77777, 7777); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (8, 'eight eight eight', 88888, 88); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (9, 'nine Nine', 999999, 999999); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES (10, 'Tenth ten TEN', 1010101, 1010); + +SELECT * FROM federated.t1 WHERE col2 = 'two two'; +SELECT * FROM federated.t1 WHERE col2 = 'two Two'; +SELECT * FROM federated.t1 WHERE id = 3; +SELECT * FROM federated.t1 WHERE id = 3 AND col1 = 3; +SELECT * FROM federated.t1 WHERE id = 4 AND col1 = 4 AND col2 = 'Two two'; +SELECT * FROM federated.t1 WHERE id = 4 AND col1 = 4 AND col2 = 'fourfourfour'; +SELECT * FROM federated.t1 WHERE id = 5 AND col2 = 'five 5 five five 5' + AND col3 = 5; +SELECT * FROM federated.t1 WHERE id = 5 AND col2 = 'five 5 five five 5' + AND col3 = 5 + AND col4 = 55555; +SELECT * FROM federated.t1 WHERE id = 5 + AND col2 = 'Two two' AND col3 = 22 + AND col4 = 33; +SELECT * FROM federated.t1 WHERE id = 5 + AND col2 = 'five 5 five five 5' AND col3 = 5 + AND col4 = 55555; +SELECT * FROM federated.t1 WHERE (id = 5 AND col2 = 'five 5 five five 5') + OR (col2 = 'three Three' AND col3 = 33); +SELECT * FROM federated.t1 WHERE (id = 5 AND col2 = 'Two two') + OR (col2 = 444 AND col3 = 4444444); +SELECT * FROM federated.t1 WHERE id = 1 + OR col1 = 10 + OR col2 = 'Two two' + OR col3 = 33 + OR col4 = 4444444; +SELECT * FROM federated.t1 WHERE id > 5; +SELECT * FROM federated.t1 WHERE id >= 5; +SELECT * FROM federated.t1 WHERE id < 5; +SELECT * FROM federated.t1 WHERE id <= 5; +SELECT * FROM federated.t1 WHERE id != 5; +SELECT * FROM federated.t1 WHERE id > 3 AND id < 7; +SELECT * FROM federated.t1 WHERE id > 3 AND id <= 7; +SELECT * FROM federated.t1 WHERE id >= 3 AND id <= 7; +SELECT * FROM federated.t1 WHERE id < 3 AND id <= 7; +SELECT * FROM federated.t1 WHERE id < 3 AND id > 7; +SELECT * FROM federated.t1 WHERE id < 3 OR id > 7; +SELECT * FROM federated.t1 WHERE col2 = 'three Three'; +SELECT * FROM federated.t1 WHERE col2 > 'one'; +SELECT * FROM federated.t1 WHERE col2 LIKE 's%'; +SELECT * FROM federated.t1 WHERE col2 LIKE 'si%'; +SELECT * FROM federated.t1 WHERE col2 LIKE 'se%'; +SELECT * FROM federated.t1 WHERE col2 NOT LIKE 'e%'; +SELECT * FROM federated.t1 WHERE col2 <> 'one One'; + +# more multi-column indexes, in the primary key +connection slave; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( + `col1` varchar(8) NOT NULL DEFAULT '', + `col2` varchar(128) NOT NULL DEFAULT '', + `col3` varchar(20) NOT NULL DEFAULT '', + `col4` varchar(40) NOT NULL DEFAULT '', + primary key (`col1`, `col2`, `col3`, `col4`), + key 3key(`col2`,`col3`,`col4`), + key 2key (`col3`,`col4`), + key col4(col4)); + +connection master; +DROP TABLE IF EXISTS federated.t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `col1` varchar(8) NOT NULL DEFAULT '', + `col2` varchar(128) NOT NULL DEFAULT '', + `col3` varchar(20) NOT NULL DEFAULT '', + `col4` varchar(40) NOT NULL DEFAULT '', + primary key (`col1`, `col2`, `col3`, `col4`), + key 3key(`col2`,`col3`,`col4`), + key 2key (`col3`,`col4`), + key col4(col4)) + ENGINE="FEDERATED" + COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('aaaa', 'aaaaaaaaaaaaaaaaaaa', 'ababababab', 'acacacacacacacac'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('bbbb', 'bbbbbbbbbbbbbbbbbbb', 'bababababa', 'bcbcbcbcbcbcbcbc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('cccc', 'ccccccccccccccccccc', 'cacacacaca', 'cbcbcbcbcbcbcbcb'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('dddd', 'ddddddddddddddddddd', 'dadadadada', 'dcdcdcdcdcdcdcdc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('eeee', 'eeeeeeeeeeeeeeeeeee', 'eaeaeaeaea', 'ecececececececec'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('ffff', 'fffffffffffffffffff', 'fafafafafa', 'fcfcfcfcfcfcfcfc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('gggg', 'ggggggggggggggggggg', 'gagagagaga', 'gcgcgcgcgcgcgcgc'); +INSERT INTO federated.t1 (col1, col2, col3, col4) + VALUES ('hhhh', 'hhhhhhhhhhhhhhhhhhh', 'hahahahaha', 'hchchchchchchchc'); + +SELECT * FROM federated.t1 WHERE col1 = 'cccc'; +SELECT * FROM federated.t1 WHERE col2 = 'eeeeeeeeeeeeeeeeeee'; +SELECT * FROM federated.t1 WHERE col3 = 'bababababa'; +SELECT * FROM federated.t1 WHERE col1 = 'gggg' AND col2 = 'ggggggggggggggggggg'; +SELECT * FROM federated.t1 WHERE col1 = 'gggg' AND col3 = 'gagagagaga'; +SELECT * FROM federated.t1 WHERE col1 = 'ffff' AND col4 = 'fcfcfcfcfcfcfcfc'; +SELECT * FROM federated.t1 WHERE col1 > 'bbbb'; +SELECT * FROM federated.t1 WHERE col1 >= 'bbbb'; +SELECT * FROM federated.t1 WHERE col1 < 'bbbb'; +SELECT * FROM federated.t1 WHERE col1 <= 'bbbb'; +SELECT * FROM federated.t1 WHERE col1 <> 'bbbb'; +SELECT * FROM federated.t1 WHERE col1 LIKE 'b%'; +SELECT * FROM federated.t1 WHERE col4 LIKE '%b%'; +SELECT * FROM federated.t1 WHERE col1 NOT LIKE 'c%'; +SELECT * FROM federated.t1 WHERE col4 NOT LIKE '%c%'; +connection slave; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( + `col1` varchar(8) NOT NULL DEFAULT '', + `col2` int(8) NOT NULL DEFAULT 0, + `col3` varchar(8) NOT NULL DEFAULT '', + primary key (`col1`, `col2`, `col3`)); + +connection master; +DROP TABLE IF EXISTS federated.t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.t1 ( + `col1` varchar(8) NOT NULL DEFAULT '', + `col2` varchar(8) NOT NULL DEFAULT '', + `col3` varchar(8) NOT NULL DEFAULT '', + primary key (`col1`, `col2`, `col3`)) + ENGINE="FEDERATED" + DEFAULT CHARSET=latin1 + COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +INSERT INTO federated.t1 VALUES ('a00', '110', 'cc0'); +INSERT INTO federated.t1 VALUES ('aaa', '111', 'ccc'); +INSERT INTO federated.t1 VALUES ('bbb', '222', 'yyy'); +INSERT INTO federated.t1 VALUES ('ccc', '111', 'zzz'); +INSERT INTO federated.t1 VALUES ('ccd', '112', 'zzzz'); + +# let's see what the foreign database says +connection slave; +SELECT col3 FROM federated.t1 WHERE ( +(col1 = 'aaa' AND col2 >= '111') OR col1 > 'aaa') AND +(col1 < 'ccc' OR ( col1 = 'ccc' AND col2 <= '111')); + +connection master; +SELECT col3 FROM federated.t1 WHERE ( +(col1 = 'aaa' AND col2 >= '111') OR col1 > 'aaa') AND +(col1 < 'ccc' OR ( col1 = 'ccc' AND col2 <= '111')); + # test NULLs connection slave; DROP TABLE IF EXISTS federated.t1; @@ -422,14 +670,6 @@ eval CREATE TABLE federated.t1 ( COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; INSERT INTO federated.t1 VALUES (3,3,3),(1,1,1),(2,2,2),(4,4,4); -EXPLAIN SELECT * FROM federated.t1 ORDER BY a; -EXPLAIN SELECT * FROM federated.t1 ORDER BY b; -EXPLAIN SELECT * FROM federated.t1 ORDER BY c; -EXPLAIN SELECT a FROM federated.t1 ORDER BY a; -EXPLAIN SELECT b FROM federated.t1 ORDER BY b; -EXPLAIN SELECT a,b FROM federated.t1 ORDER BY b; -EXPLAIN SELECT a,b FROM federated.t1; -EXPLAIN SELECT a,b,c FROM federated.t1; connection slave; DROP TABLE IF EXISTS federated.t1; @@ -862,32 +1102,16 @@ INSERT INTO federated.t1 (name, country_id, other) VALUES ('Monty', 4, 33333); INSERT INTO federated.t1 (name, country_id, other) VALUES ('Sanja', 5, 33333); #inner join -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1, federated.countries WHERE -federated.t1.country_id = federated.countries.id; - SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1, federated.countries WHERE federated.t1.country_id = federated.countries.id; -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1 INNER JOIN federated.countries ON -federated.t1.country_id = federated.countries.id; - SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1 INNER JOIN federated.countries ON federated.t1.country_id = federated.countries.id; -EXPLAIN SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, -federated.t1.other AS other, federated.countries.country AS country -FROM federated.t1 INNER JOIN federated.countries ON -federated.t1.country_id = federated.countries.id -WHERE federated.t1.name = 'Monty'; - SELECT federated.t1.name AS name, federated.t1.country_id AS country_id, federated.t1.other AS other, federated.countries.country AS country FROM federated.t1 INNER JOIN federated.countries ON @@ -895,32 +1119,17 @@ federated.t1.country_id = federated.countries.id WHERE federated.t1.name = 'Monty'; #left join -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 LEFT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.countries.id; - SELECT federated.t1.*, federated.countries.country FROM federated.t1 LEFT JOIN federated.countries ON federated.t1.country_id = federated.countries.id ORDER BY federated.countries.id; -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 LEFT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.countries.country; - SELECT federated.t1.*, federated.countries.country FROM federated.t1 LEFT JOIN federated.countries ON federated.t1.country_id = federated.countries.id ORDER BY federated.countries.country; #right join -EXPLAIN SELECT federated.t1.*, federated.countries.country -FROM federated.t1 RIGHT JOIN federated.countries -ON federated.t1.country_id = federated.countries.id -ORDER BY federated.t1.country_id; - SELECT federated.t1.*, federated.countries.country FROM federated.t1 RIGHT JOIN federated.countries ON federated.t1.country_id = federated.countries.id @@ -928,14 +1137,11 @@ ORDER BY federated.t1.country_id; DROP TABLE federated.countries; -connection master; ---disable_warnings -DROP TABLE IF EXISTS federated.t1; -DROP DATABASE IF EXISTS federated; ---enable_warnings +# optimize and repair tests +OPTIMIZE TABLE federated.t1; +REPAIR TABLE federated.t1; +REPAIR TABLE federated.t1 QUICK; +REPAIR TABLE federated.t1 EXTENDED; +REPAIR TABLE federated.t1 USE_FRM; -connection slave; ---disable_warnings -DROP TABLE IF EXISTS federated.t1; -DROP DATABASE IF EXISTS federated; ---enable_warnings +source include/federated_cleanup.inc; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index 62af9d4932b..f2bfa45ba59 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -69,3 +69,5 @@ connection con2; insert into t1 values (345); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/flush_block_commit.test b/mysql-test/t/flush_block_commit.test index 29ef7b8a0b9..ebb48242a4d 100644 --- a/mysql-test/t/flush_block_commit.test +++ b/mysql-test/t/flush_block_commit.test @@ -77,6 +77,8 @@ show create database test; drop table t1; +# End of 4.1 tests + # FLUSH TABLES WITH READ LOCK should block writes to binlog too connection con1; create table t1 (a int) engine=innodb; diff --git a/mysql-test/t/flush_table.test b/mysql-test/t/flush_table.test index afb30d21da7..0330582bc34 100644 --- a/mysql-test/t/flush_table.test +++ b/mysql-test/t/flush_table.test @@ -72,3 +72,5 @@ handler t1 read next limit 1; handler t1 read next limit 1; handler t1 close; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/foreign_key.test b/mysql-test/t/foreign_key.test index 8c35fd65f74..0a3708e6dc8 100644 --- a/mysql-test/t/foreign_key.test +++ b/mysql-test/t/foreign_key.test @@ -21,3 +21,5 @@ create table t1 ( create index a on t1 (a); create unique index b on t1 (a,b); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 3c4d5dc93da..b0b70d40e5c 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -338,3 +338,5 @@ SET NAMES latin1; INSERT INTO t1 VALUES('Mit freundlichem Grüß aus Osnabrück'); SELECT COUNT(*) FROM t1 WHERE MATCH(t) AGAINST ('"osnabrück"' IN BOOLEAN MODE); DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test index 1d3a5307412..bcd39b9ea04 100644 --- a/mysql-test/t/fulltext2.test +++ b/mysql-test/t/fulltext2.test @@ -182,3 +182,4 @@ select count(*) from t1 where match a against ('aaazzz' in boolean mode); drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_cache.test b/mysql-test/t/fulltext_cache.test index b01f0d18b76..ea05f699506 100644 --- a/mysql-test/t/fulltext_cache.test +++ b/mysql-test/t/fulltext_cache.test @@ -42,3 +42,5 @@ SELECT t1.q, t2.item, t2.id, MATCH t2.item AGAINST ('sushi' IN BOOLEAN MODE) as x FROM t2, t1 WHERE (t2.id2 = t1.id) ORDER BY x DESC,t2.id; drop table t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_distinct.test b/mysql-test/t/fulltext_distinct.test index 1f4cb8cd7bc..bf773c36844 100644 --- a/mysql-test/t/fulltext_distinct.test +++ b/mysql-test/t/fulltext_distinct.test @@ -42,3 +42,5 @@ WHERE MATCH (t1.value) AGAINST ('baz333' IN BOOLEAN MODE) AND t1.id = t2.id_t1; DROP TABLE t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_left_join.test b/mysql-test/t/fulltext_left_join.test index 96751ef8678..3bb1f0b7309 100644 --- a/mysql-test/t/fulltext_left_join.test +++ b/mysql-test/t/fulltext_left_join.test @@ -45,3 +45,4 @@ select * from t1 left join t2 on (venue_id = entity_id and match(name) against(' select * from t1 left join t2 on (venue_id = entity_id and match(name) against('aberdeen')) where dt = '2003-05-23 19:30:00'; drop table t1,t2; +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_multi.test b/mysql-test/t/fulltext_multi.test index 3a622a551bc..fe64fe88599 100644 --- a/mysql-test/t/fulltext_multi.test +++ b/mysql-test/t/fulltext_multi.test @@ -21,3 +21,5 @@ SELECT a, round(MATCH b AGAINST ('lala lkjh'),5) FROM t1; SELECT a, round(MATCH c AGAINST ('lala lkjh'),5) FROM t1; SELECT a, round(MATCH b,c AGAINST ('lala lkjh'),5) FROM t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_order_by.test b/mysql-test/t/fulltext_order_by.test index 3101242613a..a0bd7954674 100644 --- a/mysql-test/t/fulltext_order_by.test +++ b/mysql-test/t/fulltext_order_by.test @@ -137,3 +137,4 @@ order by drop table t1,t2,t3; +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_update.test b/mysql-test/t/fulltext_update.test index a1d133ba3fe..14eb0de58a5 100644 --- a/mysql-test/t/fulltext_update.test +++ b/mysql-test/t/fulltext_update.test @@ -25,3 +25,5 @@ update test set url='test', shortdesc='ggg', longdesc='mmm', description='ddd', name='nam' where gnr=2; check table test; drop table test; + +# End of 4.1 tests diff --git a/mysql-test/t/fulltext_var.test b/mysql-test/t/fulltext_var.test index 8cc8acf60a6..6b0b8aa463b 100644 --- a/mysql-test/t/fulltext_var.test +++ b/mysql-test/t/fulltext_var.test @@ -25,3 +25,4 @@ set global ft_boolean_syntax='@ -><()~*:""@|'; set global ft_boolean_syntax='+ -><()~*:""@!|'; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test index 9c32313e967..a78017ddb2f 100644 --- a/mysql-test/t/func_compress.test +++ b/mysql-test/t/func_compress.test @@ -47,3 +47,4 @@ set @@max_allowed_packet=1048576*100; --replace_result "''" XXX "'1'" XXX eval select compress(repeat('aaaaaaaaaa', IF('$LOW_MEMORY', 10, 10000000))) is null; +# End of 4.1 tests diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test index 4f13ce7513c..37fc0e105b8 100644 --- a/mysql-test/t/func_concat.test +++ b/mysql-test/t/func_concat.test @@ -52,3 +52,4 @@ select 'a' union select concat('a', -0.0); --replace_result a-0.0000 a0.0000 select 'a' union select concat('a', -0.0000); +# End of 4.1 tests diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index f352a98e3cd..5e0283feb28 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -48,3 +48,5 @@ select old_password('idkfa'); select old_password(' i d k f a '); explain extended select password('idkfa '), old_password('idkfa'); + +# End of 4.1 tests diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index 29c13793b78..b768e4fec61 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -40,3 +40,5 @@ having mts < DATE_SUB(NOW(),INTERVAL 3 MONTH); select visitor_id,max(ts) as mts from t1 group by visitor_id having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW(); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_default.test b/mysql-test/t/func_default.test index af7ebcf588b..7bebd4b4b72 100644 --- a/mysql-test/t/func_default.test +++ b/mysql-test/t/func_default.test @@ -18,6 +18,8 @@ explain select * from t1 where str <> default(str); drop table t1; +# End of 4.1 tests + # # Bug #11314 (HAVING DEFAULT() hangs) # diff --git a/mysql-test/t/func_des_encrypt.test b/mysql-test/t/func_des_encrypt.test index 201a0051c58..5d102bd02eb 100644 --- a/mysql-test/t/func_des_encrypt.test +++ b/mysql-test/t/func_des_encrypt.test @@ -7,3 +7,5 @@ # Bug #11643: des_encrypt() causes server to die # select des_encrypt('hello'); + +# End of 4.1 tests diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test index 52aca7f9dcb..a7364fa43da 100644 --- a/mysql-test/t/func_encrypt.test +++ b/mysql-test/t/func_encrypt.test @@ -86,3 +86,5 @@ select hex(des_decrypt(des_encrypt("hello",4),'password2')); select hex(des_decrypt(des_encrypt("hello","hidden"))); explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden")); + +# End of 4.1 tests diff --git a/mysql-test/t/func_encrypt_nossl.test b/mysql-test/t/func_encrypt_nossl.test index 95c104ce046..11866db1da7 100644 --- a/mysql-test/t/func_encrypt_nossl.test +++ b/mysql-test/t/func_encrypt_nossl.test @@ -35,3 +35,4 @@ select hex("hello"); select hex(des_decrypt(des_encrypt("hello",4),'password2')); select hex(des_decrypt(des_encrypt("hello","hidden"))); +# End of 4.1 tests diff --git a/mysql-test/t/func_equal.test b/mysql-test/t/func_equal.test index f446e277c92..4c88ed170a1 100644 --- a/mysql-test/t/func_equal.test +++ b/mysql-test/t/func_equal.test @@ -33,3 +33,5 @@ select * from t1 where id <=>id; select * from t1 where value <=> value; select * from t1 where id <=> value or value<=>id; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 96cd51f58db..e30dcfae973 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -264,6 +264,24 @@ select group_concat(distinct b order by b) from t1 group by a; drop table t1; # +# Bug#10201 +# +create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci, + b varchar(255) character set koi8r); +insert into t1 values ('xxx','yyy'); +select collation(a) from t1; +select collation(group_concat(a)) from t1; +create table t2 select group_concat(a) as a from t1; +show create table t2; +select collation(group_concat(a,_koi8r'test')) from t1; +--error 1267 +select collation(group_concat(a,_koi8r 0xC1C2)) from t1; +--error 1267 +select collation(group_concat(a,b)) from t1; +drop table t1; +drop table t2; + +# # bug #7769: group_concat returning null is checked in having # CREATE TABLE t1 (id int); @@ -299,3 +317,37 @@ create table t1 (a char(3), b char(20), primary key (a, b)); insert into t1 values ('ABW', 'Dutch'), ('ABW', 'English'); select group_concat(a) from t1 group by b; drop table t1; +# +# Bug #12095: GROUP_CONCAT for one row table +# + +CREATE TABLE t1 ( + aID smallint(5) unsigned NOT NULL auto_increment, + sometitle varchar(255) NOT NULL default '', + bID smallint(5) unsigned NOT NULL, + PRIMARY KEY (aID), + UNIQUE KEY sometitle (sometitle) +); +INSERT INTO t1 SET sometitle = 'title1', bID = 1; +INSERT INTO t1 SET sometitle = 'title2', bID = 1; + +CREATE TABLE t2 ( + bID smallint(5) unsigned NOT NULL auto_increment, + somename varchar(255) NOT NULL default '', + PRIMARY KEY (bID), + UNIQUE KEY somename (somename) +); +INSERT INTO t2 SET somename = 'test'; + +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; +INSERT INTO t2 SET somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; +DELETE FROM t2 WHERE somename = 'test2'; +SELECT COUNT(*), GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |') + FROM t1 JOIN t2 ON t1.bID = t2.bID; + +DROP TABLE t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 459a40cfe87..fb9470c16dd 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -509,7 +509,41 @@ create table t2 select f2 from (select now() f2 from t1) a; show columns from t2; drop table t2, t1; +# +# Bug 8893: wrong result for min/max optimization with 2 indexes +# + +CREATE TABLE t1( + id int PRIMARY KEY, + a int, + b int, + INDEX i_b_id(a,b,id), + INDEX i_id(a,id) +); +INSERT INTO t1 VALUES + (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +DROP TABLE t1; + +# change the order of the last two index definitions + +CREATE TABLE t1( + id int PRIMARY KEY, + a int, + b int, + INDEX i_id(a,id), + INDEX i_b_id(a,b,id) +); +INSERT INTO t1 VALUES + (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); +SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; +DROP TABLE t1; + +# End of 4.1 tests + +# # decimal-related tests +# create table t2 (ff double); insert into t2 values (2.2); select cast(sum(distinct ff) as decimal(5,2)) from t2; @@ -566,36 +600,6 @@ select col1,sum(col1),max(col1),min(col1) from t1 group by col1; DROP TABLE t1; # -# Bug 8893: wrong result for min/max optimization with 2 indexes -# - -CREATE TABLE t1( - id int PRIMARY KEY, - a int, - b int, - INDEX i_b_id(a,b,id), - INDEX i_id(a,id) -); -INSERT INTO t1 VALUES - (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); -SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; -DROP TABLE t1; - -# change the order of the last two index definitions - -CREATE TABLE t1( - id int PRIMARY KEY, - a int, - b int, - INDEX i_id(a,id), - INDEX i_b_id(a,b,id) -); -INSERT INTO t1 VALUES - (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1); -SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; -DROP TABLE t1; - -# # Test that new VARCHAR correctly works with COUNT(DISTINCT) # diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 03590dea8d1..4e0f426c10b 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -87,3 +87,5 @@ SELECT a, NULLIF(a,'') FROM t1; SELECT a, NULLIF(a,'') FROM t1 WHERE NULLIF(a,'') IS NULL; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 6e0883b821f..7bf737402ef 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -101,3 +101,23 @@ create table t1 (a char(20) character set binary); insert into t1 values ('aa'), ('bb'); select * from t1 where a in (NULL, 'aa'); drop table t1; + +# End of 4.1 tests + +# +# Bug #11885: WHERE condition with NOT IN (one element) +# + +CREATE TABLE t1 (a int PRIMARY KEY); +INSERT INTO t1 VALUES (44), (45), (46); + +SELECT * FROM t1 WHERE a IN (45); +SELECT * FROM t1 WHERE a NOT IN (0, 45); +SELECT * FROM t1 WHERE a NOT IN (45); + +CREATE VIEW v1 AS SELECT * FROM t1 WHERE a NOT IN (45); +SHOW CREATE VIEW v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/func_isnull.test b/mysql-test/t/func_isnull.test index 506efada0eb..6218efb882f 100644 --- a/mysql-test/t/func_isnull.test +++ b/mysql-test/t/func_isnull.test @@ -11,3 +11,5 @@ insert into t1 values (0,"2002-05-01"),(0,"2002-05-01"),(0,"2002-05-01"); flush tables; select * from t1 where isnull(to_days(mydate)); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 4ca2f28fa6e..684d7032038 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -96,3 +96,4 @@ DROP TABLE t1; # select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +# End of 4.1 tests diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index da4b8335e07..bc3a1cd239c 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -68,6 +68,8 @@ explain extended select degrees(pi()),radians(360); --error 1054 select rand(rand); +# End of 4.1 tests + # # Bug #8459 (FORMAT returns incorrect result) # diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 78ff0907b39..5079e2605ce 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -38,11 +38,11 @@ select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); drop table t1; +# End of 4.1 tests + +# # Test for BUG#9535 +# create table t1 as select uuid(), length(uuid()); show create table t1; drop table t1; - - - - diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index 33a2884b424..24266150e4c 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -16,3 +16,5 @@ select 1 | -1, 1 ^ -1, 1 & -1; select 0 | -1, 0 ^ -1, 0 & -1; select -1 >> 0, -1 << 0; select -1 >> 1, -1 << 1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test index 1a771d466fa..23070c71fe9 100644 --- a/mysql-test/t/func_regexp.test +++ b/mysql-test/t/func_regexp.test @@ -73,3 +73,5 @@ set @a="^R.*"; execute stmt1 using @a; deallocate prepare stmt1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test index bb9159eefbe..6189712b5fe 100644 --- a/mysql-test/t/func_sapdb.test +++ b/mysql-test/t/func_sapdb.test @@ -128,3 +128,5 @@ select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; --disable_ps_protocol select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f"); --enable_ps_protocol + +# End of 4.1 tests diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 0c79dec7cc2..710b9b90a05 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -54,3 +54,4 @@ select find_in_set(binary 'a', 'A,B,C'); # select find_in_set('1','3,1,'); +# End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index efad2721ae5..c66f3eaa294 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -613,3 +613,16 @@ drop table t1; # Bug #9854 hex() and out of range handling # select hex(29223372036854775809), hex(-29223372036854775809); + +# +# Bug #11311: Incorrect length returned from LPAD() and RPAD() +# +create table t1 (i int); +insert into t1 values (1000000000),(1); +--enable_metadata +select lpad(i, 7, ' ') as t from t1; +select rpad(i, 7, ' ') as t from t1; +--disable_metadata +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test index bbfef25bcfe..d7e215f5d48 100644 --- a/mysql-test/t/func_system.test +++ b/mysql-test/t/func_system.test @@ -41,3 +41,5 @@ select * from t1 where a=user(); insert into t1 values ('a'); select left(concat(a,version()),1) from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 732cdc12cae..424c0d1456b 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -108,6 +108,8 @@ select 5.1 mod 3, 5.1 mod -3, -5.1 mod 3, -5.1 mod -3; select 5 mod 3, 5 mod -3, -5 mod 3, -5 mod -3; +# End of 4.1 tests + # # Bug#6726: NOT BETWEEN parse failure # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 66ff460fc61..0538e6111b9 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -334,6 +334,9 @@ INSERT INTO t1 VALUES (NOW()); SELECT count(*) FROM t1 WHERE d>FROM_DAYS(TO_DAYS(@TMP)) AND d<=FROM_DAYS(TO_DAYS(@TMP)+1); DROP TABLE t1; + +# End of 4.1 tests + explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1, timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a2; diff --git a/mysql-test/t/func_timestamp.test b/mysql-test/t/func_timestamp.test index 8583c16073d..e1bb7e878ee 100644 --- a/mysql-test/t/func_timestamp.test +++ b/mysql-test/t/func_timestamp.test @@ -13,3 +13,5 @@ SELECT CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit) AS Date, UNIX_TIMESTAMP(CONCAT(Jahr,'-',Monat,'-',Tag,' ',Zeit)) AS Unix FROM t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/gcc296.test b/mysql-test/t/gcc296.test index ebca4dbc897..bfcd56ff396 100644 --- a/mysql-test/t/gcc296.test +++ b/mysql-test/t/gcc296.test @@ -18,3 +18,5 @@ INSERT INTO t1 VALUES ('0104000000','xxx','XXX'); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 522f7a6f637..52fe6add3b8 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -171,3 +171,5 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); --error 1416 INSERT INTO t2 SELECT GeomFromText(st) FROM t1; drop table t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index b7071019e9d..661616c0a6c 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -371,3 +371,5 @@ insert into t1 values ("qwerty"); insert into t1 values (pointfromtext('point(1,1)')); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index bb21873a0c4..05094b29589 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -479,3 +479,5 @@ insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_gr flush privileges; delete from tables_priv where host = '' and user = 'mysqltest_1'; flush privileges; + +# End of 4.1 tests diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 07bd6d53c4e..c6b8bfe2916 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -312,3 +312,5 @@ connection default; REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0'; drop table mysqltest_1.t1; drop database mysqltest_1; + +# End of 4.1 tests diff --git a/mysql-test/t/grant_cache.test b/mysql-test/t/grant_cache.test index f4423a68717..7e17a03ec21 100644 --- a/mysql-test/t/grant_cache.test +++ b/mysql-test/t/grant_cache.test @@ -149,3 +149,5 @@ drop table test.t1,mysqltest.t1,mysqltest.t2; drop database mysqltest; set GLOBAL query_cache_size=default; + +# End of 4.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 6f1880ae8fb..bfbdd098426 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -592,6 +592,8 @@ SELECT n+1 AS n FROM t1 GROUP BY n; --enable_ps_protocol DROP TABLE t1; +# End of 4.1 tests + # # Bug#11211: Ambiguous column reference in GROUP BY. # diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 3de8e8ae784..eb970e7a710 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -346,3 +346,5 @@ drop table t2; drop table t3; drop table t4; drop table t5; + +# End of 4.1 tests diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 3221b0d4624..fb223d2a9af 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -123,6 +123,7 @@ group by a.id, a.description having (a.description is not null) and (c=0); drop table t1,t2,t3; +# End of 4.1 tests # # Tests for WL#1972 CORRECT EVALUATION OF COLUMN REFERENCES IN THE HAVING CLAUSE @@ -233,7 +234,6 @@ where t1.col2 in group by col_t1 having col_t1 <= 20; - # # nested HAVING clauses # diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 75ef5a73cb0..6a9ff5c8284 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -435,3 +435,5 @@ insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd --error 1062 insert into t1 values ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/heap_auto_increment.test b/mysql-test/t/heap_auto_increment.test index 9d0fefa4d52..016bc946209 100644 --- a/mysql-test/t/heap_auto_increment.test +++ b/mysql-test/t/heap_auto_increment.test @@ -31,3 +31,5 @@ insert into t1 values (NULL, "hey"); select * from t1; select _rowid,t1._rowid,skey,sval from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test index 6fec2ac1703..5e493c2643b 100644 --- a/mysql-test/t/heap_btree.test +++ b/mysql-test/t/heap_btree.test @@ -163,3 +163,5 @@ INSERT into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11); DELETE from t1 where a < 100; SELECT * from t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/heap_hash.test b/mysql-test/t/heap_hash.test index 21ac69ef3a1..28a75a5ee11 100644 --- a/mysql-test/t/heap_hash.test +++ b/mysql-test/t/heap_hash.test @@ -259,3 +259,5 @@ insert into t1 values (1),(2),(3),(4),(5); select a from t1 where a in (1,3); explain select a from t1 where a in (1,3); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/help.test b/mysql-test/t/help.test index 3f3e99e1556..ff431fb4ebd 100644 --- a/mysql-test/t/help.test +++ b/mysql-test/t/help.test @@ -113,3 +113,5 @@ delete from mysql.help_relation where help_keyword_id=@keyword1_id and help_topi delete from mysql.help_relation where help_keyword_id=@keyword2_id and help_topic_id=@topic1_id; delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic3_id; delete from mysql.help_relation where help_keyword_id=@keyword3_id and help_topic_id=@topic4_id; + +# End of 4.1 tests diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 7c0624b67fd..a8fc75f8aa4 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -157,6 +157,8 @@ select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES; show create procedure sel2; show create function sub1; show create function sub2; +--replace_column 5 # 6 # +show function status like "sub2"; connection default; disconnect user1; drop function sub2; @@ -505,6 +507,41 @@ flush privileges; # SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; + +# +# TRIGGERS table test +# +create table t1 (i int, j int); + +delimiter |; +create trigger trg1 before insert on t1 for each row +begin + if new.j > 10 then + set new.j := 10; + end if; +end| +create trigger trg2 before update on t1 for each row +begin + if old.i % 2 = 0 then + set new.j := -1; + end if; +end| +create trigger trg3 after update on t1 for each row +begin + if new.j = -1 then + set @fired:= "Yes"; + end if; +end| +delimiter ;| +show triggers; +select * from information_schema.triggers; + +drop trigger trg1; +drop trigger trg2; +drop trigger trg3; +drop table t1; + + # # Bug #10964 Information Schema:Authorization check on privilege tables is improper # @@ -569,3 +606,30 @@ drop procedure p2; # Bug #9434 SHOW CREATE DATABASE information_schema; # show create database information_schema; + +# +# Bug #11057 information_schema: columns table has some questionable contents +# +create table t1(f1 LONGBLOB, f2 LONGTEXT); +select column_name,data_type,CHARACTER_OCTET_LENGTH, + CHARACTER_MAXIMUM_LENGTH +from information_schema.columns +where table_name='t1'; +drop table t1; +create table t1(f1 tinyint, f2 SMALLINT, f3 mediumint, f4 int, + f5 BIGINT, f6 BIT, f7 bit(64)); +select column_name, NUMERIC_PRECISION, NUMERIC_SCALE +from information_schema.columns +where table_name='t1'; +drop table t1; + +# +# Bug #12127 triggers do not show in info_schema before they are used if set to the database +# +create table t1 (f1 integer); +create trigger tr1 after insert on t1 for each row set @test_var=42; +use information_schema; +select trigger_schema, trigger_name from triggers where +trigger_name='tr1'; +use test; +drop table t1; diff --git a/mysql-test/t/init_connect.test b/mysql-test/t/init_connect.test index d9682eb8122..2e3c67a7d38 100644 --- a/mysql-test/t/init_connect.test +++ b/mysql-test/t/init_connect.test @@ -32,3 +32,5 @@ connection con5; select @a; connection con0; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/init_file.test b/mysql-test/t/init_file.test index 604d0a01794..de6aca455bd 100644 --- a/mysql-test/t/init_file.test +++ b/mysql-test/t/init_file.test @@ -5,3 +5,5 @@ # See mysql-test/std_data/init_file.dat and # mysql-test/t/init_file-master.opt for the actual test # + +# End of 4.1 tests diff --git a/mysql-test/t/innodb-deadlock.test b/mysql-test/t/innodb-deadlock.test index 7a7f657f35d..9d15a23da3c 100644 --- a/mysql-test/t/innodb-deadlock.test +++ b/mysql-test/t/innodb-deadlock.test @@ -113,3 +113,5 @@ select * from t1; commit; drop table t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 887a664e262..dd7f4319892 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -100,3 +100,5 @@ reap; commit; select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/t/innodb-replace.test index 516f058a68e..51b70f34b65 100644 --- a/mysql-test/t/innodb-replace.test +++ b/mysql-test/t/innodb-replace.test @@ -19,3 +19,4 @@ replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text select * from t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 2d0e2a4dd65..05f47f36e42 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1230,6 +1230,8 @@ SELECT * FROM (SELECT t1.*,GROUP_CONCAT(t2.b_id SEPARATOR ',') as b_list FROM (t DROP TABLE t2; DROP TABLE t1; +# End of 4.1 tests + # # range optimizer problem # @@ -1368,7 +1370,6 @@ insert into t1 (val) values ('1'),('2'); select * from t1; drop table t1; - # # Test that update does not change internal auto-increment value # diff --git a/mysql-test/t/innodb_cache.test b/mysql-test/t/innodb_cache.test index 101dde37f89..a811d660bd7 100644 --- a/mysql-test/t/innodb_cache.test +++ b/mysql-test/t/innodb_cache.test @@ -80,3 +80,4 @@ commit; select t1.* from t1, t2, t3 where t3.state & 1 = 0 and t3.t1_id = t1.id and t3.t2_id = t2.id and t1.id = 1 order by t1.a asc; drop table t3,t2,t1; +# End of 4.1 tests diff --git a/mysql-test/t/innodb_handler.test b/mysql-test/t/innodb_handler.test index 65728519e7b..18cec97af0d 100644 --- a/mysql-test/t/innodb_handler.test +++ b/mysql-test/t/innodb_handler.test @@ -93,3 +93,4 @@ HANDLER t1 READ `primary` = (1, 1000); HANDLER t1 READ `primary` PREV; DROP TABLE t1; +# End of 4.1 tests diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index e977de94871..51d936f5b4f 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -151,6 +151,12 @@ insert into t1 values(null,@value,@value,@value,@value,@value,@value,@value,@val drop table t1; --enable_ps_protocol +# End of 4.1 tests + +# +# Test automatic result buffering with INSERT INTO t1 ... SELECT ... FROM t1 +# + create table t1(id1 int not null auto_increment primary key, t char(12)); create table t2(id2 int not null, t char(12)); create table t3(id3 int not null, t char(12), index(id3)); diff --git a/mysql-test/t/insert_select-binlog.test b/mysql-test/t/insert_select-binlog.test index 9bb1ec274ef..d4041f86ab5 100644 --- a/mysql-test/t/insert_select-binlog.test +++ b/mysql-test/t/insert_select-binlog.test @@ -32,3 +32,4 @@ let $VERSION=`select version()`; show binlog events; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 92e8c7f1231..4a463c1d52e 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -201,3 +201,5 @@ insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; --error 1109 insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; drop table t1,t2,t3; + +# End of 4.1 tests diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 64a76aafa5e..5948f92d4e0 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -100,3 +100,5 @@ insert into t1 select a from t1 on duplicate key update a=a+1 ; --error 1052 insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 1d18e020543..2715f30b6cf 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -325,3 +325,5 @@ select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; drop table t1,t2,t3; + +# End of 4.1 tests diff --git a/mysql-test/t/join_crash.test b/mysql-test/t/join_crash.test index 2d2222ad67a..68fd9226e41 100644 --- a/mysql-test/t/join_crash.test +++ b/mysql-test/t/join_crash.test @@ -124,3 +124,5 @@ from client_name asc, project_name asc; DROP TABLE t1,t2,t3,t4; + +# End of 4.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 7dd35f164d5..f48ae985e56 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -662,6 +662,8 @@ 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; +# End of 4.1 tests + # # BUG#10162 - ON is merged with WHERE, left join is convered to a regular join # @@ -706,8 +708,5 @@ CREATE TABLE t1 (c11 int); CREATE TABLE t2 (c21 int); INSERT INTO t1 VALUES (30), (40), (50); INSERT INTO t2 VALUES (300), (400), (500); - SELECT * FROM t1 LEFT JOIN t2 ON (c11=c21 AND c21=30) WHERE c11=40; - DROP TABLE t1, t2; - diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 9db1523be51..91bd1ada8a4 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -337,3 +337,21 @@ show create table t1; alter table t1 modify a varchar(20); show create table t1; drop table t1; + +# +# Bug #11227: Incorrectly reporting 'MUL' vs. 'UNI' on varchar +# +create table t1 (a int not null primary key, b varchar(20) not null unique); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b int not null unique); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, unique (b(10))); +desc t1; +drop table t1; +create table t1 (a int not null primary key, b varchar(20) not null, c varchar(20) not null, unique(b(10),c(10))); +desc t1; +drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test index 5ff26b315e2..5d0f904a716 100644 --- a/mysql-test/t/key_cache.test +++ b/mysql-test/t/key_cache.test @@ -167,3 +167,5 @@ set GLOBAL key_cache_block_size=2048; check table t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/key_diff.test b/mysql-test/t/key_diff.test index b4e4339ae33..b490c613c61 100644 --- a/mysql-test/t/key_diff.test +++ b/mysql-test/t/key_diff.test @@ -20,3 +20,5 @@ explain select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B; select t1.*,t2.* from t1,t1 as t2 where t1.A=t2.B order by binary t1.a,t2.a; select * from t1 where a='a'; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/key_primary.test b/mysql-test/t/key_primary.test index 816365c517c..1ca2059b871 100644 --- a/mysql-test/t/key_primary.test +++ b/mysql-test/t/key_primary.test @@ -16,3 +16,5 @@ select * from t1 where t1 like "a_\%"; describe select * from t1 where t1="ABC"; describe select * from t1 where t1="ABCD"; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test index 3392bfa1b3b..de0159a950e 100644 --- a/mysql-test/t/keywords.test +++ b/mysql-test/t/keywords.test @@ -17,3 +17,5 @@ create table events(binlog int); insert into events values(1); select events.binlog from events; drop table events; + +# End of 4.1 tests diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 37e11e14df5..09ad3f59c10 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -39,6 +39,8 @@ connection con2; select 4; drop table t1; +# End of 4.1 tests + # # test of blocking of sending ERROR after OK or EOF # diff --git a/mysql-test/t/limit.test b/mysql-test/t/limit.test index 3dc56295375..6df865278f6 100644 --- a/mysql-test/t/limit.test +++ b/mysql-test/t/limit.test @@ -59,3 +59,5 @@ insert into t1 values (1); select 1 as a from t1 union all select 1 from dual limit 1; (select 1 as a from t1) union all (select 1 from dual) limit 1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 14ef749c802..fe6828916a3 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -31,6 +31,8 @@ load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated select * from t1; drop table t1; +# End of 4.1 tests + # # Let us test extended LOAD DATA features # diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 127cbb54a88..4815c1a30b7 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -73,3 +73,5 @@ delete from t2 using t1,t2 where t1.a=t2.a; --error 1099 delete t2 from t1,t2 where t1.a=t2.a; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 43cff90332b..0d2266fc2ae 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -95,10 +95,11 @@ reap; connection locker; drop table t1; +# End of 4.1 tests # # BUG#9998 - MySQL client hangs on USE "database" - +# create table t1(a int); lock tables t1 write; connection reader; diff --git a/mysql-test/t/lock_tables_lost_commit.test b/mysql-test/t/lock_tables_lost_commit.test index 8c1ad97c0cc..d31b4b7dfb5 100644 --- a/mysql-test/t/lock_tables_lost_commit.test +++ b/mysql-test/t/lock_tables_lost_commit.test @@ -20,3 +20,5 @@ connection con2; # binlog-ignore-db select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index 9332c47cb2f..e6f681e4f90 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -94,3 +94,4 @@ use com1; --error 1049 use prn; +# End of 4.1 tests diff --git a/mysql-test/t/lowercase_table2.test b/mysql-test/t/lowercase_table2.test index f5cf292482e..c02ae8f5073 100644 --- a/mysql-test/t/lowercase_table2.test +++ b/mysql-test/t/lowercase_table2.test @@ -137,3 +137,5 @@ create table t2aA (col1 int); create table t1Aa (col1 int); select t1Aa.col1 from t1aA,t2Aa where t1Aa.col1 = t2aA.col1; drop table t2aA, t1Aa; + +# End of 4.1 tests diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test index 9841059a26b..7d34ba649cf 100644 --- a/mysql-test/t/lowercase_table3.test +++ b/mysql-test/t/lowercase_table3.test @@ -35,3 +35,5 @@ CREATE TABLE t1 (a int) ENGINE=INNODB; --error 1146 SELECT * from T1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/lowercase_table_grant.test b/mysql-test/t/lowercase_table_grant.test index 3d6adb477a3..7449231fca5 100644 --- a/mysql-test/t/lowercase_table_grant.test +++ b/mysql-test/t/lowercase_table_grant.test @@ -26,3 +26,5 @@ flush privileges; drop user mysqltest_1@localhost; drop database MYSQLtest; + +# End of 4.1 tests diff --git a/mysql-test/t/lowercase_table_qcache.test b/mysql-test/t/lowercase_table_qcache.test index 5077a41402a..e63ad3b2c16 100644 --- a/mysql-test/t/lowercase_table_qcache.test +++ b/mysql-test/t/lowercase_table_qcache.test @@ -27,3 +27,5 @@ enable_result_log; show status like "Qcache_queries_in_cache"; set GLOBAL query_cache_size=0; + +# End of 4.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 165c16823a2..7d708243a10 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -320,3 +320,4 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3; SELECT b FROM t2; DROP TABLE t1, t2; +# End of 4.1 tests diff --git a/mysql-test/t/metadata.test b/mysql-test/t/metadata.test index ebd58ef4ebb..b4edd15f5ef 100644 --- a/mysql-test/t/metadata.test +++ b/mysql-test/t/metadata.test @@ -48,3 +48,5 @@ select * from (select 1 union select 1) aaa; drop table t1; --disable_metadata + +# End of 4.1 tests diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index 0641acb552f..2e804f4c986 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -229,3 +229,5 @@ select (@after-@before) >= 2; # cleanup drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/multi_statement.test b/mysql-test/t/multi_statement.test index 2abec332878..eb8d867f3f0 100644 --- a/mysql-test/t/multi_statement.test +++ b/mysql-test/t/multi_statement.test @@ -29,3 +29,5 @@ show status like 'Slow_queries'|||| drop table t1|||| delimiter ;|||| + +# End of 4.1 tests diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 0ca42e86204..5e3be6d45eb 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -452,6 +452,8 @@ insert into t2 values(1,null); delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1'; drop table t1, t2; +# End of 4.1 tests + # # Test for bug #1980. # diff --git a/mysql-test/t/myisam-blob.test b/mysql-test/t/myisam-blob.test index 7af8c661c02..ac1b45b8c6c 100644 --- a/mysql-test/t/myisam-blob.test +++ b/mysql-test/t/myisam-blob.test @@ -39,3 +39,5 @@ INSERT INTO t1 (data) VALUES (NULL); UPDATE t1 set data=repeat('a',18*1024*1024); select length(data) from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index fccc7642eb0..d949e39b05b 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -675,3 +675,4 @@ show keys from t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 3639fc2e262..ccf5e0bf66a 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -8,3 +8,5 @@ --disable_result_log --exec echo $MYSQL_CLIENT_TEST --exec $MYSQL_CLIENT_TEST + +# End of 4.1 tests diff --git a/mysql-test/t/mysql_protocols.test b/mysql-test/t/mysql_protocols.test index 6e2d4f20429..0253c2b5d17 100644 --- a/mysql-test/t/mysql_protocols.test +++ b/mysql-test/t/mysql_protocols.test @@ -10,3 +10,4 @@ --exec echo "select ' ok' as 'MEMORY'" | $MYSQL --protocol=MEMORY 2>&1 || true --exec echo "select ' ok' as 'NullS'" | $MYSQL --protocol=NullS 2>&1 || true +# End of 4.1 tests diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 49b8237d99f..e5bd8c554cb 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -110,3 +110,4 @@ select "--- reading stdin --" as ""; # clean up drop table t1, t2; +# End of 4.1 tests diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test index 6e2eda07695..a2f1aba05b0 100644 --- a/mysql-test/t/mysqlbinlog2.test +++ b/mysql-test/t/mysqlbinlog2.test @@ -157,3 +157,5 @@ select "--- to-last-log --" as ""; select "--- end of test --" as ""; --enable_query_log drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 811875a36f5..27bea937dcf 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -4,7 +4,6 @@ --disable_warnings DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; -drop database if exists db1; drop view if exists v1, v2, v3; --enable_warnings @@ -135,15 +134,6 @@ insert into t1 values (1),(2),(3); drop table t1; # -# dump of view -# -create table t1(a int); -create view v1 as select * from t1; ---exec $MYSQL_DUMP --skip-comments test -drop view v1; -drop table t1; - -# # Bug #6101: create database problem # @@ -198,15 +188,6 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A); DROP TABLE t1; # -# Bug #9756 -# - -CREATE TABLE t1 (a char(10)); -INSERT INTO t1 VALUES ('\''); ---exec $MYSQL_DUMP --skip-comments test t1 -DROP TABLE t1; - -# # Test for --insert-ignore # @@ -564,29 +545,6 @@ CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); --exec $MYSQL_DUMP --add-drop-database --skip-comments --databases test DROP TABLE t1; - -# -# Bug #10213 mysqldump crashes when dumping VIEWs(on MacOS X) -# - -create database db1; -use db1; - -CREATE TABLE t2 ( - a varchar(30) default NULL, - KEY a (a(5)) -); - -INSERT INTO t2 VALUES ('alfred'); -INSERT INTO t2 VALUES ('angie'); -INSERT INTO t2 VALUES ('bingo'); -INSERT INTO t2 VALUES ('waffle'); -INSERT INTO t2 VALUES ('lemon'); -create view v2 as select * from t2 where a like 'a%' with check option; ---exec $MYSQL_DUMP --skip-comments db1 -drop table t2; -drop view v2; -drop database db1; # # Bug #9558 mysqldump --no-data db t1 t2 format still dumps data # @@ -620,6 +578,7 @@ select '------ Testing with illegal table names ------' as test_sequence ; --enable_query_log --error 6 --exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\d-2-1.sql" 2>&1 + --error 6 --exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\t1" 2>&1 @@ -678,6 +637,50 @@ insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thir --exec $MYSQL_DUMP --skip-comments --xml --no-create-info test drop table t1, t2; +# End of 4.1 tests + +# +# dump of view +# +create table t1(a int); +create view v1 as select * from t1; +--exec $MYSQL_DUMP --skip-comments test +drop view v1; +drop table t1; + +# +# Bug #10213 mysqldump crashes when dumping VIEWs(on MacOS X) +# + +create database mysqldump_test_db; +use mysqldump_test_db; + +CREATE TABLE t2 ( + a varchar(30) default NULL, + KEY a (a(5)) +); + +INSERT INTO t2 VALUES ('alfred'); +INSERT INTO t2 VALUES ('angie'); +INSERT INTO t2 VALUES ('bingo'); +INSERT INTO t2 VALUES ('waffle'); +INSERT INTO t2 VALUES ('lemon'); +create view v2 as select * from t2 where a like 'a%' with check option; +--exec $MYSQL_DUMP --skip-comments mysqldump_test_db +drop table t2; +drop view v2; +drop database mysqldump_test_db; +use test; + +# +# Bug #9756 +# + +CREATE TABLE t1 (a char(10)); +INSERT INTO t1 VALUES ('\''); +--exec $MYSQL_DUMP --skip-comments test t1 +DROP TABLE t1; + # # Bug #10927 mysqldump: Can't reload dump with view that consist of other view # @@ -709,3 +712,52 @@ select * from v1; drop view v1, v2, v3; drop table t1; +# +# Test for dumping triggers +# + +CREATE TABLE t1 (a int, b bigint default NULL); +CREATE TABLE t2 (a int); +delimiter |; +create trigger trg1 before insert on t1 for each row +begin + if new.a > 10 then + set new.a := 10; + set new.a := 11; + end if; +end| +create trigger trg2 before update on t1 for each row begin + if old.a % 2 = 0 then set new.b := 12; end if; +end| +set sql_mode="traditional"| +create trigger trg3 after update on t1 for each row +begin + if new.a = -1 then + set @fired:= "Yes"; + end if; +end| +create trigger trg4 before insert on t2 for each row +begin + if new.a > 10 then + set @fired:= "No"; + end if; +end| +set sql_mode=default| +delimiter ;| +--replace_column 6 '0000-00-00 00:00:00' +show triggers like "t1"; +INSERT INTO t1 (a) VALUES (1),(2),(3),(22); +update t1 set a = 4 where a=3; +# Triggers should be dumped by default +--exec $MYSQL_DUMP --skip-comments --databases test +# Skip dumping triggers +--exec $MYSQL_DUMP --skip-comments --databases --skip-triggers test +# Dump and reload... +--exec $MYSQL_DUMP --skip-comments --databases test > var/tmp/mysqldump.sql +drop table t1; +--exec $MYSQL test < var/tmp/mysqldump.sql +# Check that tables have been reloaded +show tables; +--replace_column 6 # +show triggers; +DROP TABLE t1, t2; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 14b8c1d1127..29588419642 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -287,6 +287,7 @@ select 3 from t1 ; # #select 3 from t1 ; +# End of 4.1 tests # # Bug #10251: Identifiers containing quotes not handled correctly @@ -296,8 +297,6 @@ select 1 as `a'b`, 2 as `a"b`; # Test escaping of quotes select 'aaa\\','aa''a',"aa""a"; - - # # Check of include/show_msg.inc and include/show_msg80.inc # diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 2e5e2293b5c..bfc278d709b 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -179,3 +179,5 @@ drop table t1; #truncate table t2; #select count(*) from t2; #drop table t2; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test index c2068329d41..6bbb1c2f2f2 100644 --- a/mysql-test/t/ndb_autodiscover.test +++ b/mysql-test/t/ndb_autodiscover.test @@ -544,3 +544,5 @@ create table t10 ( insert into t10 values (1, 'kalle'); --exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test `$NDB_TOOLS_DIR/ndb_show_tables --no-defaults | grep BLOB` >> $NDB_TOOLS_OUTPUT 2>&1 || true + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_autodiscover2.test b/mysql-test/t/ndb_autodiscover2.test index 76baa31a2a9..f12d3d31fdd 100644 --- a/mysql-test/t/ndb_autodiscover2.test +++ b/mysql-test/t/ndb_autodiscover2.test @@ -18,3 +18,4 @@ drop table t9; select * from t10; drop table t10; +# End of 4.1 tests diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test index c0d5b14c2ea..1c78a4b8744 100644 --- a/mysql-test/t/ndb_basic.test +++ b/mysql-test/t/ndb_basic.test @@ -606,6 +606,7 @@ select * from t1 order by counter; drop table t1; +# End of 4.1 tests # # Test long table name diff --git a/mysql-test/t/ndb_blob.test b/mysql-test/t/ndb_blob.test index b265809b75f..a12ebee2f0d 100644 --- a/mysql-test/t/ndb_blob.test +++ b/mysql-test/t/ndb_blob.test @@ -404,3 +404,5 @@ Proper fix: Set inline bytes to multiple of mbmaxlen and validate it (after the 8 byte length).'); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_cache.test b/mysql-test/t/ndb_cache.test index b61422a58fb..9c299b61c24 100644 --- a/mysql-test/t/ndb_cache.test +++ b/mysql-test/t/ndb_cache.test @@ -119,4 +119,4 @@ show status like "Qcache_queries_in_cache"; SET GLOBAL query_cache_size=0; - +# End of 4.1 tests diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test index becbe9a4d06..fb43e1831f3 100644 --- a/mysql-test/t/ndb_charset.test +++ b/mysql-test/t/ndb_charset.test @@ -246,3 +246,5 @@ replace into t1 values ('jonas % '); replace into t1 values ('jonas % '); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_config.test b/mysql-test/t/ndb_config.test new file mode 100644 index 00000000000..66287bf6d29 --- /dev/null +++ b/mysql-test/t/ndb_config.test @@ -0,0 +1,9 @@ +-- source include/have_ndb.inc +-- source include/not_embedded.inc + +--exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=type,nodeid,host 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=nodeid,host,DataMemory,IndexMemory --type=ndbd 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --no-defaults -r \\n -f " " --query=nodeid,host,DataMemory,IndexMemory --type=ndbd 2> /dev/null +--exec $NDB_TOOLS_DIR/ndb_config --no-defaults --query=nodeid --type=ndbd --host=localhost 2> /dev/null + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_database.test b/mysql-test/t/ndb_database.test index 1264c3fa73b..2e924ba2dcc 100644 --- a/mysql-test/t/ndb_database.test +++ b/mysql-test/t/ndb_database.test @@ -48,3 +48,5 @@ show tables; drop table if exists t1; drop database if exists mysqltest; --enable_warnings + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_grant.later b/mysql-test/t/ndb_grant.later index b4885d2c5fc..5431d94e1f8 100644 --- a/mysql-test/t/ndb_grant.later +++ b/mysql-test/t/ndb_grant.later @@ -381,3 +381,5 @@ alter table time_zone_transition_type engine=myisam; alter table user engine=myisam; use test; flush privileges; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_index.test b/mysql-test/t/ndb_index.test index 93085dea587..272f30e3e6f 100644 --- a/mysql-test/t/ndb_index.test +++ b/mysql-test/t/ndb_index.test @@ -126,5 +126,6 @@ select port, accessnode, pop, accesstype from t1 where pop='pop98' and accessno select port, accessnode, pop, accesstype from t1 where pop='pop98' and accessnode='node78' and port='port67' and customer_id='kllopmn'; select port, accessnode, pop, accesstype from t1 where pop='pop98' and accessnode='node78' and port='port67' and customer_id='foo'; - drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_index_ordered.test b/mysql-test/t/ndb_index_ordered.test index 9c9d5d5a84f..9b70919ab2a 100644 --- a/mysql-test/t/ndb_index_ordered.test +++ b/mysql-test/t/ndb_index_ordered.test @@ -348,3 +348,5 @@ connection con1; select a from t1 where b = 2; show tables; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_index_unique.test b/mysql-test/t/ndb_index_unique.test index d6de013c1e2..2185276c2c6 100644 --- a/mysql-test/t/ndb_index_unique.test +++ b/mysql-test/t/ndb_index_unique.test @@ -308,3 +308,5 @@ INSERT INTO t1 (month, year, code) VALUES (5,2004,'12'); select * from t1 where code = '12' and month = 4 and year = 2004 ; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_insert.test b/mysql-test/t/ndb_insert.test index 68f3817e134..92bc51bcf4f 100644 --- a/mysql-test/t/ndb_insert.test +++ b/mysql-test/t/ndb_insert.test @@ -616,3 +616,5 @@ INSERT IGNORE INTO t1 VALUES (1); INSERT IGNORE INTO t1 VALUES (1); SELECT * FROM t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_limit.test b/mysql-test/t/ndb_limit.test index 0df3b2f7566..01613606d66 100644 --- a/mysql-test/t/ndb_limit.test +++ b/mysql-test/t/ndb_limit.test @@ -81,3 +81,5 @@ SELECT DATE_FORMAT(day, '%Y%m%d') as date, DATE_FORMAT(day, '%d-%m-%Y') as date_formatted FROM t2 GROUP BY day ORDER BY day DESC LIMIT 2; drop table t2; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_lock.test b/mysql-test/t/ndb_lock.test index b93abbd564b..6945f91ee39 100644 --- a/mysql-test/t/ndb_lock.test +++ b/mysql-test/t/ndb_lock.test @@ -69,3 +69,4 @@ insert into t1 values (1,1,1); drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/ndb_minmax.test b/mysql-test/t/ndb_minmax.test index 97ea84f98ef..a3ac677cd2a 100644 --- a/mysql-test/t/ndb_minmax.test +++ b/mysql-test/t/ndb_minmax.test @@ -62,6 +62,4 @@ select MAX(c) from t2; select * from t2 order by a; drop table t2; - - - +# End of 4.1 tests diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test index 85950c72cf9..760150c6f6a 100644 --- a/mysql-test/t/ndb_multi.test +++ b/mysql-test/t/ndb_multi.test @@ -68,4 +68,4 @@ drop table t1, t2, t3, t4; connection server2; drop table t1, t3, t4; - +# End of 4.1 tests diff --git a/mysql-test/t/ndb_replace.test b/mysql-test/t/ndb_replace.test index 1c06a9a6633..b97a0322a6a 100644 --- a/mysql-test/t/ndb_replace.test +++ b/mysql-test/t/ndb_replace.test @@ -26,3 +26,5 @@ insert into t1 (gesuchnr,benutzer_id) values (1,1); replace into t1 (gesuchnr,benutzer_id) values (1,1); select * from t1 order by gesuchnr; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_restore.test b/mysql-test/t/ndb_restore.test index 0173fabd46f..049b07d5a8b 100644 --- a/mysql-test/t/ndb_restore.test +++ b/mysql-test/t/ndb_restore.test @@ -215,3 +215,5 @@ drop table if exists t1_c,t2_c,t3_c,t4_c,t5_c,t6_c,t7_c,t8_c,t9_c; # --exec $NDB_TOOLS_DIR/ndb_select_all --no-defaults -d sys -D , SYSTAB_0 | grep 520093696 + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_subquery.test b/mysql-test/t/ndb_subquery.test index 095fdbcfa13..93c45c521a0 100644 --- a/mysql-test/t/ndb_subquery.test +++ b/mysql-test/t/ndb_subquery.test @@ -38,8 +38,11 @@ drop table t2; # bug#5367 ########## -### +# End of 4.1 tests + +# # bug#11205 +# create table t1 (p int not null primary key, u int not null) engine=ndb; insert into t1 values (1,1),(2,2),(3,3); diff --git a/mysql-test/t/ndb_transaction.test b/mysql-test/t/ndb_transaction.test index ae02059786d..d3ebadb1a78 100644 --- a/mysql-test/t/ndb_transaction.test +++ b/mysql-test/t/ndb_transaction.test @@ -295,4 +295,4 @@ select count(*) from t2; drop table test.t1, t2; drop database mysqltest; - +# End of 4.1 tests diff --git a/mysql-test/t/ndb_truncate.test b/mysql-test/t/ndb_truncate.test index 7c0f79bcc59..73af70d0d0f 100644 --- a/mysql-test/t/ndb_truncate.test +++ b/mysql-test/t/ndb_truncate.test @@ -32,3 +32,5 @@ truncate table t2; select count(*) from t2; drop table t2; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_types.test b/mysql-test/t/ndb_types.test index d4bf4133807..3446a409b2a 100644 --- a/mysql-test/t/ndb_types.test +++ b/mysql-test/t/ndb_types.test @@ -81,3 +81,5 @@ from t1; select time_stamp>@now from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ndb_update.test b/mysql-test/t/ndb_update.test index 5453e41f937..45e3add4639 100644 --- a/mysql-test/t/ndb_update.test +++ b/mysql-test/t/ndb_update.test @@ -32,3 +32,5 @@ select * from t1 order by pk1; --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings + +# End of 4.1 tests diff --git a/mysql-test/t/negation_elimination.test b/mysql-test/t/negation_elimination.test index c50a9678edb..0e0d8891e1f 100644 --- a/mysql-test/t/negation_elimination.test +++ b/mysql-test/t/negation_elimination.test @@ -70,3 +70,5 @@ select a, not(not(a)) from t1; explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a)); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/not_embedded_server.test b/mysql-test/t/not_embedded_server.test new file mode 100644 index 00000000000..83ec03d6706 --- /dev/null +++ b/mysql-test/t/not_embedded_server.test @@ -0,0 +1,18 @@ +# +# Here we collect tests that doesn't work with the embedded server +# + +-- source include/not_embedded.inc + +# +# Show full process list with prepare +# To not show other connections, this must be the first test and we must +# have a server restart before this one +# + +prepare stmt1 from ' show full processlist '; +--replace_column 1 number 6 time 3 localhost +execute stmt1; +deallocate prepare stmt1; + +# End of 4.1 tests diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 4cd20979319..183308880ed 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -189,3 +189,5 @@ select # Restore charset to the default value. set names latin1; + +# End of 4.1 tests diff --git a/mysql-test/t/null_key.test b/mysql-test/t/null_key.test index d7f6a634d1e..e15aec01d2a 100644 --- a/mysql-test/t/null_key.test +++ b/mysql-test/t/null_key.test @@ -193,3 +193,50 @@ select * from t1 where id2 is null or id2 > 0; delete from t1 where id <=> NULL; select * from t1; drop table t1; + +# +# Test for bug #12144: optimizations for key access with null keys +# used for outer joins +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int, b int, INDEX idx(a)); +CREATE TABLE t3 (b int, INDEX idx(b)); +CREATE TABLE t4 (b int, INDEX idx(b)); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (1, 1), (3, 1); +INSERT INTO t3 VALUES + (NULL), (NULL), (NULL), (NULL), (NULL), + (NULL), (NULL), (NULL), (NULL), (NULL); +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t3; +INSERT INTO t3 SELECT * FROM t4; +INSERT INTO t3 VALUES (2), (3); + +ANALYZE table t1, t2, t3; + +SELECT COUNT(*) FROM t3; + +EXPLAIN SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + LEFT JOIN t3 ON t2.b=t3.b; +FLUSH STATUS ; +SELECT SQL_CALC_FOUND_ROWS * FROM t1 LEFT JOIN t2 ON t1.a=t2.a + LEFT JOIN t3 ON t2.b=t3.b; +SELECT FOUND_ROWS(); +SHOW STATUS LIKE "handler_read%"; + +DROP TABLE t1,t2,t3,t4; +# End of 4.1 tests diff --git a/mysql-test/t/odbc.test b/mysql-test/t/odbc.test index 9aac5948359..d4b6fc35e74 100644 --- a/mysql-test/t/odbc.test +++ b/mysql-test/t/odbc.test @@ -20,3 +20,5 @@ select * from t1 where a is null and b=2; select * from t1 where a is null; explain select * from t1 where b is null; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 26fcc7463d6..2e09bc5b3a3 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -266,3 +266,15 @@ EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; DROP VIEW v1; DROP TABLE t1; +# Test for bug #11543: ROLLUP query with a repeated column in GROUP BY +# + +CREATE TABLE t1 (a INT(10) NOT NULL, b INT(10) NOT NULL); +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 VALUES (1, 2); + +SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; + +DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 2262395d586..96c92615430 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -43,3 +43,5 @@ delete from mysql.user where user='ssl_user%'; delete from mysql.db where user='ssl_user%'; flush privileges; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 36eee6e43b7..e3b26a3e47f 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -549,3 +549,5 @@ INSERT INTO t1 VALUES (2), (1), (1), (2), (1); SELECT a FROM t1 ORDER BY a; (SELECT a FROM t1) ORDER BY a; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/order_fill_sortbuf.test b/mysql-test/t/order_fill_sortbuf.test index 37620ebe331..f13cf8cf350 100644 --- a/mysql-test/t/order_fill_sortbuf.test +++ b/mysql-test/t/order_fill_sortbuf.test @@ -22,3 +22,5 @@ enable_query_log; create table t2 select id2 from t1 order by id3; select count(*) from t2; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/outfile.test b/mysql-test/t/outfile.test index 4b12f9e4e50..a74bebe1460 100644 --- a/mysql-test/t/outfile.test +++ b/mysql-test/t/outfile.test @@ -63,3 +63,5 @@ EXPLAIN FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\r\n' FROM t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/overflow.test b/mysql-test/t/overflow.test index 17e443d51f8..c930707413b 100644 --- a/mysql-test/t/overflow.test +++ b/mysql-test/t/overflow.test @@ -2,3 +2,5 @@ connect (con1,localhost,boo,,); connection con1; -- error 1064,1102,1280 drop database AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + +# End of 4.1 tests diff --git a/mysql-test/t/packet.test b/mysql-test/t/packet.test index c7f10d75d74..04122b42b44 100644 --- a/mysql-test/t/packet.test +++ b/mysql-test/t/packet.test @@ -31,3 +31,5 @@ set global net_buffer_length=default; set net_buffer_length=default; SELECT length("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") as len; select length(repeat('a',2000)); + +# End of 4.1 tests diff --git a/mysql-test/t/preload.test b/mysql-test/t/preload.test index 7a049d06a86..1b7f3c5b9eb 100644 --- a/mysql-test/t/preload.test +++ b/mysql-test/t/preload.test @@ -98,3 +98,5 @@ load index into cache t3 key (b), t2 key (c) ; show status like "key_read%"; drop table t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index de92c67518e..b4c04e4432a 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -828,3 +828,5 @@ execute stmt; set @@tx_isolation=default; execute stmt; deallocate prepare stmt; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_10nestset.test b/mysql-test/t/ps_10nestset.test index 53e84f7a47d..46a88653da3 100644 --- a/mysql-test/t/ps_10nestset.test +++ b/mysql-test/t/ps_10nestset.test @@ -69,3 +69,5 @@ execute st_round using @arg_round, @arg_round; select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_11bugs.test b/mysql-test/t/ps_11bugs.test index 5945b140645..e214afeaaf3 100644 --- a/mysql-test/t/ps_11bugs.test +++ b/mysql-test/t/ps_11bugs.test @@ -129,3 +129,4 @@ drop table t1, t2; # end of bug#1676 +# End of 4.1 tests diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index ab133e4c347..6abfd8f28a7 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -930,3 +930,5 @@ drop table t5, t9; # Thank you for reading these rules of thumb. # # Matthias + +# End of 4.1 tests diff --git a/mysql-test/t/ps_2myisam.test b/mysql-test/t/ps_2myisam.test index 534703efc14..0a335bd02a3 100644 --- a/mysql-test/t/ps_2myisam.test +++ b/mysql-test/t/ps_2myisam.test @@ -40,3 +40,5 @@ drop table t2 ; -- source include/ps_conv.inc drop table t1, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_3innodb.test b/mysql-test/t/ps_3innodb.test index f83b61914a2..e25a8b1f469 100644 --- a/mysql-test/t/ps_3innodb.test +++ b/mysql-test/t/ps_3innodb.test @@ -22,3 +22,5 @@ let $type= 'InnoDB' ; -- source include/ps_conv.inc drop table t1, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_4heap.test b/mysql-test/t/ps_4heap.test index 3ce3bea8265..f16d4599a74 100644 --- a/mysql-test/t/ps_4heap.test +++ b/mysql-test/t/ps_4heap.test @@ -47,3 +47,5 @@ eval create table t9 -- source include/ps_conv.inc drop table t1, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_5merge.test b/mysql-test/t/ps_5merge.test index 7e94ede41d1..e6ce9bf42d3 100644 --- a/mysql-test/t/ps_5merge.test +++ b/mysql-test/t/ps_5merge.test @@ -82,3 +82,5 @@ INSERT_METHOD=LAST; drop table t1, t1_1, t1_2, t9_1, t9_2, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_6bdb.test b/mysql-test/t/ps_6bdb.test index 5db3349279e..49dd7aa924b 100644 --- a/mysql-test/t/ps_6bdb.test +++ b/mysql-test/t/ps_6bdb.test @@ -21,3 +21,5 @@ let $type= 'BDB' ; -- source include/ps_conv.inc drop table t1, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_7ndb.test b/mysql-test/t/ps_7ndb.test index b558f2f3c21..e3f65ec2c4e 100644 --- a/mysql-test/t/ps_7ndb.test +++ b/mysql-test/t/ps_7ndb.test @@ -21,3 +21,5 @@ let $type= 'NDB' ; -- source include/ps_conv.inc drop table t1, t9; + +# End of 4.1 tests diff --git a/mysql-test/t/ps_grant.test b/mysql-test/t/ps_grant.test index 0b33a2dadde..81c842de459 100644 --- a/mysql-test/t/ps_grant.test +++ b/mysql-test/t/ps_grant.test @@ -1,7 +1,6 @@ # Can't test grants with embedded server -- source include/not_embedded.inc - let $type= 'MYISAM' ; ################ GRANT/REVOKE/DROP affecting a parallel session ################ @@ -80,6 +79,7 @@ execute s_t1 ; ######## Question 2: The table t9 does not exist. ######## --error 1146 execute s_t9 ; +deallocate prepare s_t9; #### revoke the access rights to t1 @@ -112,8 +112,11 @@ show grants for second_user@localhost ; drop database mysqltest; +# End of 4.1 tests -## grant/revoke + drop user +# +# grant/revoke + drop user +# --error 1295 prepare stmt3 from ' grant all on test.t1 to drop_user@localhost identified by ''looser'' '; @@ -126,11 +129,3 @@ revoke all privileges on test.t1 from drop_user@localhost ; --error 1295 prepare stmt3 from ' drop user drop_user@localhost '; drop user drop_user@localhost; - -# This test must be the last one, otherwise it may produce extra -# rows in the processlist under high load. -# Tested here simply so it is not tested with embedded server -prepare stmt4 from ' show full processlist '; ---replace_column 1 number 6 time 3 localhost -execute stmt4; -deallocate prepare stmt4; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 3a0ac08b1ba..8bff2b4608b 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -616,6 +616,7 @@ set character_set_results=cp1251; SELECT a,'Â','â'='Â' FROM t1; show status like "Qcache_hits"; show status like "Qcache_queries_in_cache"; +SET NAMES default; DROP TABLE t1; @@ -711,9 +712,10 @@ repair table t1; show status like 'qcache_queries_in_cache'; drop table t1; +# # Bug #9549: Make sure cached queries that span more than one cache block # are handled properly in the embedded server. - +# # We just want a small query cache, so we can fragment it easily set GLOBAL query_cache_size=64*1024; # This actually gives us a usable cache size of about 48K @@ -755,6 +757,8 @@ select a from t1; flush query cache; drop table t1, t2; +set GLOBAL query_cache_size=1355776 + # # Query with warning prohibited to query cache (BUG#9414) @@ -832,4 +836,45 @@ drop procedure p1// drop table t1// delimiter ;// +# +# query in QC from normal execution and SP (BUG#6897) +# +flush query cache; +reset query cache; +flush status; +delimiter //; +create table t1 (s1 int)// +create procedure f1 () begin +select sql_cache * from t1; +select sql_cache * from t1; +end;// +delimiter ;// +call f1(); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +insert into t1 values (1); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +call f1(); +call f1(); +select sql_cache * from t1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop procedure f1; +drop table t1; set GLOBAL query_cache_size=0; + +# End of 4.1 tests diff --git a/mysql-test/t/query_cache_merge.test b/mysql-test/t/query_cache_merge.test index fef3f18df60..36b8662f088 100644 --- a/mysql-test/t/query_cache_merge.test +++ b/mysql-test/t/query_cache_merge.test @@ -36,3 +36,5 @@ show status like "Qcache_queries_in_cache"; drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257,t00; SET @@global.query_cache_size=0; + +# End of 4.1 tests diff --git a/mysql-test/t/raid.test b/mysql-test/t/raid.test index 14a55db0c34..3ca5adaaaea 100644 --- a/mysql-test/t/raid.test +++ b/mysql-test/t/raid.test @@ -220,3 +220,5 @@ ALTER TABLE t1 RENAME t2; ALTER TABLE t2 CHANGE COLUMN c c VARCHAR(251) NOT NULL; select count(*) from t2; DROP TABLE t2; + +# End of 4.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 065cef659b8..12dda022cb9 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -490,6 +490,8 @@ SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 1' OR ARG1 != ' 2'); SELECT count(*) FROM t1 WHERE CLIENT='000' AND (ARG1 != ' 2' OR ARG1 != ' 1'); drop table t1; +# End of 4.1 tests + # # Test for optimization request #10561: to use keys for # NOT IN (c1,...,cn) and NOT BETWEEN c1 AND c2 diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 6fa208f37ec..5caecef176e 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -65,3 +65,5 @@ sleep 1; show tables; drop table t2, t4; + +# End of 4.1 tests diff --git a/mysql-test/t/repair.test b/mysql-test/t/repair.test index ef7043febbc..5e39e0b6a50 100644 --- a/mysql-test/t/repair.test +++ b/mysql-test/t/repair.test @@ -33,3 +33,5 @@ system echo 1 > $MYSQL_TEST_DIR/var/master-data/test/t1.MYI ; repair table t1; repair table t1 use_frm; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/replace.test b/mysql-test/t/replace.test index 2b3775f4f67..10703eaafb8 100644 --- a/mysql-test/t/replace.test +++ b/mysql-test/t/replace.test @@ -33,3 +33,5 @@ replace into t1 values (126,"first updated"); replace into t1 values (63,default); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rollback.test b/mysql-test/t/rollback.test index 3cb1ea3024b..3b8ad901907 100644 --- a/mysql-test/t/rollback.test +++ b/mysql-test/t/rollback.test @@ -21,3 +21,5 @@ select * from t1; select @@warning_count; show warnings; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index afcaaef6811..4becef1c2b7 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -84,3 +84,5 @@ select a, MAX(b), (1, MAX(b)) = (1, 4) from t1 group by a; drop table t1; SELECT ROW(2,10) <=> ROW(3,4); SELECT ROW(NULL,10) <=> ROW(3,NULL); + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index e9a87529706..13dba142d54 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -126,3 +126,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000002.test b/mysql-test/t/rpl000002.test index 4fbb6a595a4..bafd8a30159 100644 --- a/mysql-test/t/rpl000002.test +++ b/mysql-test/t/rpl000002.test @@ -37,3 +37,5 @@ show create table t5; connection master; drop table t2,t3,t5; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000004.test b/mysql-test/t/rpl000004.test index 8fc2977faab..f2a02bd4dd6 100644 --- a/mysql-test/t/rpl000004.test +++ b/mysql-test/t/rpl000004.test @@ -21,3 +21,5 @@ connection slave; sync_with_master; create table t1(n int); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000005.test b/mysql-test/t/rpl000005.test index b94695c72e1..e81ad739402 100644 --- a/mysql-test/t/rpl000005.test +++ b/mysql-test/t/rpl000005.test @@ -20,3 +20,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000006.test b/mysql-test/t/rpl000006.test index 898ef309f50..334ed575835 100644 --- a/mysql-test/t/rpl000006.test +++ b/mysql-test/t/rpl000006.test @@ -43,3 +43,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000008.test b/mysql-test/t/rpl000008.test index ea782b99d28..fe030f90411 100644 --- a/mysql-test/t/rpl000008.test +++ b/mysql-test/t/rpl000008.test @@ -34,3 +34,5 @@ save_master_pos; connection slave; sync_with_master; drop table mysqltest_foo,mysqltest_bar,t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000009.test b/mysql-test/t/rpl000009.test index 59451bc888d..a51a64979fa 100644 --- a/mysql-test/t/rpl000009.test +++ b/mysql-test/t/rpl000009.test @@ -170,3 +170,5 @@ sync_with_master; # These has to be droped on slave as they are not replicated drop database mysqltest2; drop database mysqltest3; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000010.test b/mysql-test/t/rpl000010.test index 0725214694a..261b9148774 100644 --- a/mysql-test/t/rpl000010.test +++ b/mysql-test/t/rpl000010.test @@ -16,3 +16,4 @@ save_master_pos; connection slave; sync_with_master; +# End of 4.1 tests diff --git a/mysql-test/t/rpl000011.test b/mysql-test/t/rpl000011.test index 3b00afe10e4..32f6227f7c5 100644 --- a/mysql-test/t/rpl000011.test +++ b/mysql-test/t/rpl000011.test @@ -13,3 +13,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000012.test b/mysql-test/t/rpl000012.test index 7f440eaaa13..2c1c65e4202 100644 --- a/mysql-test/t/rpl000012.test +++ b/mysql-test/t/rpl000012.test @@ -41,3 +41,5 @@ drop table if exists t1,t2; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000013.test b/mysql-test/t/rpl000013.test index 94d5feb3925..eca4803c6bc 100644 --- a/mysql-test/t/rpl000013.test +++ b/mysql-test/t/rpl000013.test @@ -39,3 +39,5 @@ drop table if exists t1,t2; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test index da73c5f4db2..a53049386af 100644 --- a/mysql-test/t/rpl000015.test +++ b/mysql-test/t/rpl000015.test @@ -37,3 +37,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000017.test b/mysql-test/t/rpl000017.test index 3b39a6b49a6..3b4574e9547 100644 --- a/mysql-test/t/rpl000017.test +++ b/mysql-test/t/rpl000017.test @@ -17,3 +17,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl000018.test b/mysql-test/t/rpl000018.test index fd2be2399a5..bc6d887cc99 100644 --- a/mysql-test/t/rpl000018.test +++ b/mysql-test/t/rpl000018.test @@ -25,3 +25,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_EE_error.test b/mysql-test/t/rpl_EE_error.test index 90d8c36685f..683ccf1bc40 100644 --- a/mysql-test/t/rpl_EE_error.test +++ b/mysql-test/t/rpl_EE_error.test @@ -28,3 +28,5 @@ drop table t1; save_master_pos; connection slave; wait_for_slave_to_stop; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_alter.test b/mysql-test/t/rpl_alter.test index a913f01cd81..576376a0264 100644 --- a/mysql-test/t/rpl_alter.test +++ b/mysql-test/t/rpl_alter.test @@ -20,3 +20,5 @@ drop database mysqltest; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test index 007b018e9d8..96e228a17a1 100644 --- a/mysql-test/t/rpl_chain_temp_table.test +++ b/mysql-test/t/rpl_chain_temp_table.test @@ -97,3 +97,5 @@ sync_with_master; # memory they use is freed (it should) by mysqld before it terminates). # If they wouldn't be cleaned up, you would see some "still reachable" blocks in # Valgrind. + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test index 23866447c98..45a6d2c0c28 100644 --- a/mysql-test/t/rpl_change_master.test +++ b/mysql-test/t/rpl_change_master.test @@ -33,3 +33,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test index ee54bc72a65..e5ddf084461 100644 --- a/mysql-test/t/rpl_charset.test +++ b/mysql-test/t/rpl_charset.test @@ -169,3 +169,5 @@ set @p=_latin1 'test'; update t1 set pk='test' where pk=@p; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_commit_after_flush.test b/mysql-test/t/rpl_commit_after_flush.test index 62c89b3aae6..6129e5485a6 100644 --- a/mysql-test/t/rpl_commit_after_flush.test +++ b/mysql-test/t/rpl_commit_after_flush.test @@ -15,3 +15,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_create_database.test b/mysql-test/t/rpl_create_database.test index c63b0bc85ef..cfccc4567b5 100644 --- a/mysql-test/t/rpl_create_database.test +++ b/mysql-test/t/rpl_create_database.test @@ -69,3 +69,5 @@ DROP DATABASE IF EXISTS mysqltest_prometheus; DROP DATABASE IF EXISTS mysqltest_sisyfos; DROP DATABASE IF EXISTS mysqltest_bob; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_ddl.test b/mysql-test/t/rpl_ddl.test index d043d40d96e..9521ba3d4c1 100644 --- a/mysql-test/t/rpl_ddl.test +++ b/mysql-test/t/rpl_ddl.test @@ -348,3 +348,5 @@ DROP DATABASE IF EXISTS mysqltest1; DROP DATABASE IF EXISTS mysqltest2; DROP DATABASE IF EXISTS mysqltest3; --enable_warnings + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test index eb4c5c33714..d31ef3a5bef 100644 --- a/mysql-test/t/rpl_deadlock.test +++ b/mysql-test/t/rpl_deadlock.test @@ -109,3 +109,5 @@ show slave status; connection master; drop table t1,t2,t3,t4; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_delete_all.test b/mysql-test/t/rpl_delete_all.test index ad2ce29c610..db33ee3bb86 100644 --- a/mysql-test/t/rpl_delete_all.test +++ b/mysql-test/t/rpl_delete_all.test @@ -39,3 +39,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_do_grant.test b/mysql-test/t/rpl_do_grant.test index 27a22874497..54287a67657 100644 --- a/mysql-test/t/rpl_do_grant.test +++ b/mysql-test/t/rpl_do_grant.test @@ -44,3 +44,5 @@ sync_with_master; # no need to delete manually, as the DELETEs must have done some real job on # master (updated binlog) flush privileges; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_drop.test b/mysql-test/t/rpl_drop.test index ab5b608cab6..2544599208e 100644 --- a/mysql-test/t/rpl_drop.test +++ b/mysql-test/t/rpl_drop.test @@ -10,3 +10,5 @@ drop table t1, t2; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_drop_temp.test b/mysql-test/t/rpl_drop_temp.test index cf663367b78..18fc17ed064 100644 --- a/mysql-test/t/rpl_drop_temp.test +++ b/mysql-test/t/rpl_drop_temp.test @@ -14,3 +14,4 @@ show status like 'Slave_open_temp_tables'; connection default; drop database mysqltest; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_empty_master_crash.test b/mysql-test/t/rpl_empty_master_crash.test index 98a630c69ca..5f26bedc9fe 100644 --- a/mysql-test/t/rpl_empty_master_crash.test +++ b/mysql-test/t/rpl_empty_master_crash.test @@ -11,3 +11,5 @@ load table t1 from master; connection slave; --error 1188 load table t1 from master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index 5388b6af8d4..7d948e96c39 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -55,3 +55,5 @@ connection slave; # SQL slave thread should not have stopped (because table of the killed # query is in the ignore list). sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_failed_optimize.test b/mysql-test/t/rpl_failed_optimize.test index d245d1bacbb..57afaa89e83 100644 --- a/mysql-test/t/rpl_failed_optimize.test +++ b/mysql-test/t/rpl_failed_optimize.test @@ -16,3 +16,5 @@ OPTIMIZE TABLE t1; OPTIMIZE TABLE non_existing; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_failsafe.test b/mysql-test/t/rpl_failsafe.test index ae61b061153..4336d897fc0 100644 --- a/mysql-test/t/rpl_failsafe.test +++ b/mysql-test/t/rpl_failsafe.test @@ -20,3 +20,5 @@ start slave; sync_with_master; show variables like 'rpl_recovery_rank'; show status like 'Rpl_status'; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_flush_log_loop.test b/mysql-test/t/rpl_flush_log_loop.test index ccaae8ad765..ff599af89a3 100644 --- a/mysql-test/t/rpl_flush_log_loop.test +++ b/mysql-test/t/rpl_flush_log_loop.test @@ -20,3 +20,5 @@ sleep 5; --replace_result $SLAVE_MYPORT SLAVE_PORT --replace_column 1 # 8 # 9 # 23 # 33 # show slave status; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_flush_tables.test b/mysql-test/t/rpl_flush_tables.test index eb16ddcd8de..eff0a79bc45 100644 --- a/mysql-test/t/rpl_flush_tables.test +++ b/mysql-test/t/rpl_flush_tables.test @@ -35,3 +35,5 @@ sync_with_master; select * from t3; # Note that all this confusion may cause warnings 'table xx is open on rename' # in the .err files; these are not fatal and are not reported by mysql-test-run. + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_free_items.test b/mysql-test/t/rpl_free_items.test index 3228ffd9cde..043e84160b8 100644 --- a/mysql-test/t/rpl_free_items.test +++ b/mysql-test/t/rpl_free_items.test @@ -18,3 +18,5 @@ connection master; drop table t1; drop table t2; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_get_lock.test b/mysql-test/t/rpl_get_lock.test index 847e7145be6..945bd98c993 100644 --- a/mysql-test/t/rpl_get_lock.test +++ b/mysql-test/t/rpl_get_lock.test @@ -39,3 +39,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_heap.test b/mysql-test/t/rpl_heap.test index 3452f3990bf..3ee335fe58d 100644 --- a/mysql-test/t/rpl_heap.test +++ b/mysql-test/t/rpl_heap.test @@ -47,3 +47,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_ignore_grant.test b/mysql-test/t/rpl_ignore_grant.test index 9b012d08df3..2e6e2ce9a31 100644 --- a/mysql-test/t/rpl_ignore_grant.test +++ b/mysql-test/t/rpl_ignore_grant.test @@ -55,3 +55,5 @@ sync_with_master; delete from mysql.user where user=_binary'rpl_ignore_grant'; delete from mysql.db where user=_binary'rpl_ignore_grant'; flush privileges; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_init_slave.test b/mysql-test/t/rpl_init_slave.test index 3ea04117ced..cefb04a7b75 100644 --- a/mysql-test/t/rpl_init_slave.test +++ b/mysql-test/t/rpl_init_slave.test @@ -24,3 +24,5 @@ save_master_pos; connection slave; sync_with_master; stop slave; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_innodb.test b/mysql-test/t/rpl_innodb.test index b171dced26e..551657fd7e3 100644 --- a/mysql-test/t/rpl_innodb.test +++ b/mysql-test/t/rpl_innodb.test @@ -44,3 +44,5 @@ connection master; DROP TABLE t4; --enable_query_log sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index a4506e32963..704de1a423b 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -74,6 +74,4 @@ SET FOREIGN_KEY_CHECKS=0; INSERT INTO t1 VALUES (1),(1); sync_slave_with_master; - - - +# End of 4.1 tests diff --git a/mysql-test/t/rpl_insert_ignore.test b/mysql-test/t/rpl_insert_ignore.test index 58eaa287817..a6cc69b1df8 100644 --- a/mysql-test/t/rpl_insert_ignore.test +++ b/mysql-test/t/rpl_insert_ignore.test @@ -69,3 +69,5 @@ SELECT * FROM t1 ORDER BY a; connection master; drop table t1, t2; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 3d54897adda..1b5980eb92e 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -149,3 +149,5 @@ wait_for_slave_to_stop; drop table t2; connection master; drop table t2; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_loaddata_rule_m.test b/mysql-test/t/rpl_loaddata_rule_m.test index 97c984c4369..68024c340a8 100644 --- a/mysql-test/t/rpl_loaddata_rule_m.test +++ b/mysql-test/t/rpl_loaddata_rule_m.test @@ -25,3 +25,5 @@ load data infile '../../std_data/rpl_loaddata.dat' into table test.t1; --replace_column 2 # 5 # show binlog events from 98; drop database mysqltest; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_loaddata_rule_s.test b/mysql-test/t/rpl_loaddata_rule_s.test index 9802c00d35f..98fad3cc06f 100644 --- a/mysql-test/t/rpl_loaddata_rule_s.test +++ b/mysql-test/t/rpl_loaddata_rule_s.test @@ -18,3 +18,5 @@ connection slave; sync_with_master; select count(*) from t1; # check that LOAD was replicated show binlog events from 98; # should be nothing + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_loaddatalocal.test b/mysql-test/t/rpl_loaddatalocal.test index f9325b39af6..0b54de8462e 100644 --- a/mysql-test/t/rpl_loaddatalocal.test +++ b/mysql-test/t/rpl_loaddatalocal.test @@ -35,6 +35,8 @@ save_master_pos; connection slave; sync_with_master; +# End of 4.1 tests + # # Now let us test how well we replicate LOAD DATA LOCAL in situation when # we met duplicates in tables to which we are adding rows. diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 8cb99d5432e..899f812535a 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -108,3 +108,5 @@ show slave status; --error 1220 show binlog events in 'slave-bin.000005' from 4; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_log_pos.test b/mysql-test/t/rpl_log_pos.test index 2a03497846b..979b146bb22 100644 --- a/mysql-test/t/rpl_log_pos.test +++ b/mysql-test/t/rpl_log_pos.test @@ -45,3 +45,5 @@ select * from t1; connection master; drop table t1; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_many_optimize.test b/mysql-test/t/rpl_many_optimize.test index 525e23abe15..91fab0b27a8 100644 --- a/mysql-test/t/rpl_many_optimize.test +++ b/mysql-test/t/rpl_many_optimize.test @@ -18,3 +18,5 @@ enable_query_log; drop table t1; # Bug was that slave segfaulted after ~ a hundred of OPTIMIZE (or ANALYZE) sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_master_pos_wait.test b/mysql-test/t/rpl_master_pos_wait.test index 4d4d51b04ab..893c8746efc 100644 --- a/mysql-test/t/rpl_master_pos_wait.test +++ b/mysql-test/t/rpl_master_pos_wait.test @@ -14,3 +14,5 @@ connection slave1; stop slave sql_thread; connection slave; reap; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test index 963a76fb959..8b54cf5ab7f 100644 --- a/mysql-test/t/rpl_max_relay_size.test +++ b/mysql-test/t/rpl_max_relay_size.test @@ -91,3 +91,5 @@ connection master; # test that the absence of relay logs does not make a master crash flush logs; show master status; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_misc_functions.test b/mysql-test/t/rpl_misc_functions.test index 12eadbb25ed..f20d0aa83e4 100644 --- a/mysql-test/t/rpl_misc_functions.test +++ b/mysql-test/t/rpl_misc_functions.test @@ -28,3 +28,5 @@ load data local infile './var/master-data/test/rpl_misc_functions.outfile' into # compare them with the replica; the SELECT below should return no row select * from t1, t2 where (t1.id=t2.id) and not(t1.i=t2.i and t1.r1=t2.r1 and t1.r2=t2.r2 and t1.p=t2.p); stop slave; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_delete.test b/mysql-test/t/rpl_multi_delete.test index 299cb720b62..2fd7b820b1a 100644 --- a/mysql-test/t/rpl_multi_delete.test +++ b/mysql-test/t/rpl_multi_delete.test @@ -21,3 +21,5 @@ drop table t1,t2; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_delete2.test b/mysql-test/t/rpl_multi_delete2.test index c5128833843..62d95a3a90f 100644 --- a/mysql-test/t/rpl_multi_delete2.test +++ b/mysql-test/t/rpl_multi_delete2.test @@ -21,3 +21,5 @@ select * from t2; connection master; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_query.test b/mysql-test/t/rpl_multi_query.test index 2ddd61ce7ba..fa94928e13a 100644 --- a/mysql-test/t/rpl_multi_query.test +++ b/mysql-test/t/rpl_multi_query.test @@ -27,3 +27,5 @@ connection master; show binlog events from 98; drop database mysqltest; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_update.test b/mysql-test/t/rpl_multi_update.test index 88994aa66bd..dd75edb3055 100644 --- a/mysql-test/t/rpl_multi_update.test +++ b/mysql-test/t/rpl_multi_update.test @@ -22,3 +22,5 @@ UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_update2.test b/mysql-test/t/rpl_multi_update2.test index bba7700a88e..f92c5504f43 100644 --- a/mysql-test/t/rpl_multi_update2.test +++ b/mysql-test/t/rpl_multi_update2.test @@ -31,3 +31,5 @@ connection slave; sync_with_master; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test index 80b0603eb60..64e46882c16 100644 --- a/mysql-test/t/rpl_multi_update3.test +++ b/mysql-test/t/rpl_multi_update3.test @@ -157,3 +157,5 @@ SELECT * FROM t1; connection master; DROP TABLE t1, t2, t3; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_mystery22.test b/mysql-test/t/rpl_mystery22.test index d49f1a210f4..f190968a03c 100644 --- a/mysql-test/t/rpl_mystery22.test +++ b/mysql-test/t/rpl_mystery22.test @@ -37,3 +37,4 @@ connection master; drop table t1; sync_slave_with_master; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test index 779ec4e84bf..78731e4dc7d 100644 --- a/mysql-test/t/rpl_openssl.test +++ b/mysql-test/t/rpl_openssl.test @@ -60,3 +60,5 @@ sync_with_master; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 8 # 9 # 23 # 33 # show slave status; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_optimize.test b/mysql-test/t/rpl_optimize.test index 9f02b715885..6858f52abab 100644 --- a/mysql-test/t/rpl_optimize.test +++ b/mysql-test/t/rpl_optimize.test @@ -41,3 +41,5 @@ sync_with_master; # If the machine is so fast that slave syncs before OPTIMIZE # starts, this test wil demonstrate nothing but will pass. + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_ps.test b/mysql-test/t/rpl_ps.test index 79f48381a4f..adf39b1e4ab 100644 --- a/mysql-test/t/rpl_ps.test +++ b/mysql-test/t/rpl_ps.test @@ -41,3 +41,4 @@ connection slave; sync_with_master; stop slave; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_redirect.test b/mysql-test/t/rpl_redirect.test index d505351cc69..beb18348b40 100644 --- a/mysql-test/t/rpl_redirect.test +++ b/mysql-test/t/rpl_redirect.test @@ -41,3 +41,5 @@ select * from t1; drop table t1; connection master; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_relayrotate.test b/mysql-test/t/rpl_relayrotate.test index 2fde590356a..b66cf7a6e0d 100644 --- a/mysql-test/t/rpl_relayrotate.test +++ b/mysql-test/t/rpl_relayrotate.test @@ -75,3 +75,5 @@ drop table t1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_relayspace.test b/mysql-test/t/rpl_relayspace.test index bb82781b511..70315c14f34 100644 --- a/mysql-test/t/rpl_relayspace.test +++ b/mysql-test/t/rpl_relayspace.test @@ -30,3 +30,5 @@ start slave; # also the slave will probably not cooperate to shutdown # (as 2 threads are locked) select master_pos_wait('master-bin.001',200,6)=-1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test index 108dd54ce0a..ff5af71ea5b 100644 --- a/mysql-test/t/rpl_replicate_do.test +++ b/mysql-test/t/rpl_replicate_do.test @@ -36,3 +36,4 @@ sync_with_master; --replace_column 1 # 8 # 9 # 23 # 33 # show slave status; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test index 1b27e059f92..aeac1b50110 100644 --- a/mysql-test/t/rpl_reset_slave.test +++ b/mysql-test/t/rpl_reset_slave.test @@ -46,3 +46,5 @@ reset slave; start slave; sync_with_master; show status like 'slave_open_temp_tables'; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_rewrite_db.test b/mysql-test/t/rpl_rewrite_db.test index b77d57294fa..1e8e5a992d8 100644 --- a/mysql-test/t/rpl_rewrite_db.test +++ b/mysql-test/t/rpl_rewrite_db.test @@ -78,3 +78,4 @@ drop database rewrite; connection master; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index 2355e92e58b..26cb5ac8631 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -153,3 +153,4 @@ connection master; drop table if exists t1,t2,t3,t4; sync_slave_with_master; +# End of 4.1 tests diff --git a/mysql-test/t/rpl_server_id1.test b/mysql-test/t/rpl_server_id1.test index 4d504325294..3583f05284c 100644 --- a/mysql-test/t/rpl_server_id1.test +++ b/mysql-test/t/rpl_server_id1.test @@ -22,3 +22,5 @@ insert into t1 values (1); sleep 2; # enough time for the event to be replicated (it should not) show status like "slave_running"; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_server_id2.test b/mysql-test/t/rpl_server_id2.test index 7bbac358ada..0f2eb560d18 100644 --- a/mysql-test/t/rpl_server_id2.test +++ b/mysql-test/t/rpl_server_id2.test @@ -22,3 +22,5 @@ select * from t1; # check that indeed 2 were inserted # (not critical). stop slave; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_set_charset.test b/mysql-test/t/rpl_set_charset.test index 269074b1c42..c70eb2681f5 100644 --- a/mysql-test/t/rpl_set_charset.test +++ b/mysql-test/t/rpl_set_charset.test @@ -31,3 +31,5 @@ drop database mysqltest1; save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_skip_error.test b/mysql-test/t/rpl_skip_error.test index 86c89c70314..e0e569a65b7 100644 --- a/mysql-test/t/rpl_skip_error.test +++ b/mysql-test/t/rpl_skip_error.test @@ -12,3 +12,5 @@ save_master_pos; connection slave; sync_with_master; select * from t1; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index e2a8982ebaa..184ac4edea1 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -249,7 +249,7 @@ select * from t1; connection master; delete from t1; -drop trigger t1.trg; +drop trigger trg; insert into t1 values (1); select * from t1; --replace_column 2 # 5 # diff --git a/mysql-test/t/rpl_sporadic_master.test b/mysql-test/t/rpl_sporadic_master.test index b24901c62a9..26b633a1c4f 100644 --- a/mysql-test/t/rpl_sporadic_master.test +++ b/mysql-test/t/rpl_sporadic_master.test @@ -22,3 +22,5 @@ select * from t1; connection master; drop table t1,t2; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_start_stop_slave.test b/mysql-test/t/rpl_start_stop_slave.test index 903ff204194..19988cf902a 100644 --- a/mysql-test/t/rpl_start_stop_slave.test +++ b/mysql-test/t/rpl_start_stop_slave.test @@ -32,3 +32,5 @@ save_master_pos; connection slave; sync_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index e65469de7e0..fcb2391a9d8 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -130,3 +130,5 @@ create temporary table t3 (f int); sync_with_master; # The server will now close done + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_timezone.test b/mysql-test/t/rpl_timezone.test index a7547f7afc6..2e9883141d8 100644 --- a/mysql-test/t/rpl_timezone.test +++ b/mysql-test/t/rpl_timezone.test @@ -122,3 +122,5 @@ select * from t2; connection master; drop table t1, t2; sync_slave_with_master; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index c1aee2cb1db..5bc7a040b1b 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -83,3 +83,5 @@ start slave until relay_log_file='slave-relay-bin.000002', master_log_pos=561; # Warning should be given for second command start slave sql_thread; start slave until master_log_file='master-bin.000001', master_log_pos=776; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test index 711d83219a6..e8985397703 100644 --- a/mysql-test/t/rpl_user_variables.test +++ b/mysql-test/t/rpl_user_variables.test @@ -54,3 +54,5 @@ save_master_pos; connection slave; sync_with_master; stop slave; + +# End of 4.1 tests diff --git a/mysql-test/t/rpl_variables.test b/mysql-test/t/rpl_variables.test index ea40181ecd3..57ae2b9c3c4 100644 --- a/mysql-test/t/rpl_variables.test +++ b/mysql-test/t/rpl_variables.test @@ -3,6 +3,8 @@ source include/master-slave.inc; set global slave_net_timeout=100; set global sql_slave_skip_counter=100; +# End of 4.1 tests + # BUG #7800: Add various-slave related variables to SHOW VARIABLES show variables like 'slave_compressed_protocol'; --replace_column 2 SLAVE_LOAD_TMPDIR diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 69343524928..eac76749589 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2080,6 +2080,96 @@ select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid drop table t1,t2,t3; +# Test for BUG#11700 +CREATE TABLE t1 ( + acct_id int(11) NOT NULL default '0', + profile_id smallint(6) default NULL, + UNIQUE KEY t1$acct_id (acct_id), + KEY t1$profile_id (profile_id) +); +INSERT INTO t1 VALUES (132,17),(133,18); + +CREATE TABLE t2 ( + profile_id smallint(6) default NULL, + queue_id int(11) default NULL, + seq int(11) default NULL, + KEY t2$queue_id (queue_id) +); +INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); + +CREATE TABLE t3 ( + id int(11) NOT NULL default '0', + qtype int(11) default NULL, + seq int(11) default NULL, + warn_lvl int(11) default NULL, + crit_lvl int(11) default NULL, + rr1 tinyint(4) NOT NULL default '0', + rr2 int(11) default NULL, + default_queue tinyint(4) NOT NULL default '0', + KEY t3$qtype (qtype), + KEY t3$id (id) +); + +INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), + (36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); + +SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q +WHERE + (pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND + (pq.queue_id = q.id) AND (q.rr1 <> 1); + +drop table t1,t2,t3; + +# +# Bug #11482 Wrongly applied optimization was erroneously rejecting valid +# rows +create table t1 (f1 int); +insert into t1 values (1),(NULL); +create table t2 (f2 int, f3 int, f4 int); +create index idx1 on t2 (f4); +insert into t2 values (1,2,3),(2,4,6); +select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) +from t2 C where A.f4 = C.f4) or A.f3 IS NULL; +drop table t1,t2; + +# +# Bug #11521 Negative integer keys incorrectly substituted for 0 during +# range analysis. + +create table t2 (a tinyint unsigned); +create index t2i on t2(a); +insert into t2 values (0), (254), (255); +explain select * from t2 where a > -1; +select * from t2 where a > -1; +drop table t2; + +# +# Bug #11745: SELECT ... FROM DUAL with WHERE condition +# + +CREATE TABLE t1 (a int, b int, c int); +INSERT INTO t1 + SELECT 50, 3, 3 FROM DUAL + WHERE NOT EXISTS + (SELECT * FROM t1 WHERE a = 50 AND b = 3); +SELECT * FROM t1; +INSERT INTO t1 + SELECT 50, 3, 3 FROM DUAL + WHERE NOT EXISTS + (SELECT * FROM t1 WHERE a = 50 AND b = 3); +select found_rows(); +SELECT * FROM t1; +select count(*) from t1; +select found_rows(); +select count(*) from t1 limit 2,3; +select found_rows(); +select SQL_CALC_FOUND_ROWS count(*) from t1 limit 2,3; +select found_rows(); + +DROP TABLE t1; + +# End of 4.1 tests + # # Test case for bug 7098: substitution of a constant for a string field # @@ -2152,10 +2242,8 @@ INSERT INTO t1 VALUES SELECT K2C4, K4N4, F2I4 FROM t1 WHERE K2C4 = 'WART' AND (F2I4 = 2 AND K2C4 = 'WART' OR (F2I4 = 2 OR K4N4 = '0200')); - SELECT K2C4, K4N4, F2I4 FROM t1 WHERE K2C4 = 'WART' AND (K2C4 = 'WART' OR K4N4 = '0200'); - DROP TABLE t1; # @@ -2173,36 +2261,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; DROP TABLE t1, t2; - -# -# Test case for bug 7098: substitution of a constant for a string field -# - -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); - -SELECT * FROM t1 WHERE city='London'; -SELECT * FROM t1 WHERE city='london'; -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -SELECT * FROM t1 WHERE city='London' AND city='london'; -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; - -DROP TABLE t1; - -# -# Bug#7425 inconsistent sort order on unsigned columns result of substraction -# - -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -select a-b , (a-b < 0) from t1 order by 1; -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -select cast((a - b) as unsigned) from t1 order by 1; -drop table t1; - # # Bug#8670 # @@ -2290,54 +2348,3 @@ DROP TABLE t1,t2; # select x'10' + 0, X'10' + 0, b'10' + 0, B'10' + 0; -# Test for BUG#11700 -CREATE TABLE t1 ( - acct_id int(11) NOT NULL default '0', - profile_id smallint(6) default NULL, - UNIQUE KEY t1$acct_id (acct_id), - KEY t1$profile_id (profile_id) -); -INSERT INTO t1 VALUES (132,17),(133,18); - -CREATE TABLE t2 ( - profile_id smallint(6) default NULL, - queue_id int(11) default NULL, - seq int(11) default NULL, - KEY t2$queue_id (queue_id) -); -INSERT INTO t2 VALUES (17,31,4),(17,30,3),(17,36,2),(17,37,1); - -CREATE TABLE t3 ( - id int(11) NOT NULL default '0', - qtype int(11) default NULL, - seq int(11) default NULL, - warn_lvl int(11) default NULL, - crit_lvl int(11) default NULL, - rr1 tinyint(4) NOT NULL default '0', - rr2 int(11) default NULL, - default_queue tinyint(4) NOT NULL default '0', - KEY t3$qtype (qtype), - KEY t3$id (id) -); - -INSERT INTO t3 VALUES (30,1,29,NULL,NULL,0,NULL,0),(31,1,28,NULL,NULL,0,NULL,0), - (36,1,34,NULL,NULL,0,NULL,0),(37,1,35,NULL,NULL,0,121,0); - -SELECT COUNT(*) FROM t1 a STRAIGHT_JOIN t2 pq STRAIGHT_JOIN t3 q -WHERE - (pq.profile_id = a.profile_id) AND (a.acct_id = 132) AND - (pq.queue_id = q.id) AND (q.rr1 <> 1); - -drop table t1,t2,t3; - -# -# Bug #11482 4.1.12 produces different resultset for a complex query -# than in previous 4.1.x -create table t1 (f1 int); -insert into t1 values (1),(NULL); -create table t2 (f2 int, f3 int, f4 int); -create index idx1 on t2 (f4); -insert into t2 values (1,2,3),(2,4,6); -select A.f2 from t1 left join t2 A on A.f2 = f1 where A.f3=(select min(f3) -from t2 C where A.f4 = C.f4) or A.f3 IS NULL; -drop table t1,t2; diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test index 91879015b51..e4bc54a5538 100644 --- a/mysql-test/t/select_found.test +++ b/mysql-test/t/select_found.test @@ -191,3 +191,5 @@ INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5); SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2; SELECT FOUND_ROWS(); DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test index 5b2dfb00bb7..1da700c9adf 100644 --- a/mysql-test/t/select_safe.test +++ b/mysql-test/t/select_safe.test @@ -56,7 +56,6 @@ SELECT * from t1; # # Test MAX_SEEKS_FOR_KEY # -SELECT @@MAX_SEEKS_FOR_KEY; analyze table t1; insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); explain select STRAIGHT_JOIN * from t1,t1 as t2 where t1.b=t2.b; @@ -87,3 +86,5 @@ select * from (select 1 union select 2 union select 3) x; drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; + +# End of 4.1 tests diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index d591f90dd65..efe3504ad7d 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -385,3 +385,5 @@ create table t1 ( ); SHOW CREATE TABLE t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/skip_name_resolve.test b/mysql-test/t/skip_name_resolve.test index b669579acbf..02339ca14c5 100644 --- a/mysql-test/t/skip_name_resolve.test +++ b/mysql-test/t/skip_name_resolve.test @@ -6,3 +6,5 @@ GRANT ALL ON test.* TO mysqltest_1@'127.0.0.1/255.255.255.255'; SHOW GRANTS FOR mysqltest_1@'127.0.0.1/255.255.255.255'; REVOKE ALL ON test.* FROM mysqltest_1@'127.0.0.1/255.255.255.255'; DROP USER mysqltest_1@'127.0.0.1/255.255.255.255'; + +# End of 4.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index d9e6163cbc7..ecc9c3c12a2 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3378,7 +3378,7 @@ drop procedure avg| drop procedure if exists bug6129| --enable_warnings set @old_mode= @@sql_mode; -set @@sql_mode= ""; +set @@sql_mode= "ERROR_FOR_DIVISION_BY_ZERO"; create procedure bug6129() select @@sql_mode| call bug6129()| @@ -3877,6 +3877,34 @@ drop procedure bug9538| # +# BUG#8692: Cursor fetch of empty string +# +--disable_warnings +drop procedure if exists bug8692| +--enable_warnings +create table t3 (c1 varchar(5), c2 char(5), c3 enum('one','two'), c4 text, c5 blob, c6 char(5), c7 varchar(5))| +insert into t3 values ('', '', '', '', '', '', NULL)| + +create procedure bug8692() +begin + declare v1 VARCHAR(10); + declare v2 VARCHAR(10); + declare v3 VARCHAR(10); + declare v4 VARCHAR(10); + declare v5 VARCHAR(10); + declare v6 VARCHAR(10); + declare v7 VARCHAR(10); + declare c8692 cursor for select c1,c2,c3,c4,c5,c6,c7 from t3; + open c8692; + fetch c8692 into v1,v2,v3,v4,v5,v6,v7; + select v1, v2, v3, v4, v5, v6, v7; +end| + +call bug8692()| +drop procedure bug8692| +drop table t3| + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index f8ab521e665..10db520cd12 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -86,6 +86,8 @@ drop table t1 ; --error 1231 set @@SQL_MODE=NULL; +# End of 4.1 tests + # # test for # WL 1941 "NO_C_ESCAPES sql_mode" diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 31d9c8154d5..7fea51c9327 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -35,3 +35,5 @@ connection con1; reap; show status like 'Table_lock%'; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index 6ac88e4d629..ca57ca646f2 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -1103,3 +1103,43 @@ create table t1(a int, b date not null); alter table t1 modify a bigint unsigned not null; show create table t1; drop table t1; + +# +# Bug #5906: handle invalid date due to conversion +# +set @@sql_mode='traditional'; +create table t1 (d date); +--error 1292 +insert into t1 values ('2000-10-00'); +--error 1292 +insert into t1 values (1000); +insert into t1 values ('2000-10-01'); +--error 1292 +update t1 set d = 1100; +select * from t1; +drop table t1; + +# +# Bug #11964: alter table with timestamp field +# + +set @@sql_mode='traditional'; +create table t1(a int, b timestamp); +alter table t1 add primary key(a); +show create table t1; +drop table t1; +create table t1(a int, b timestamp default 20050102030405); +alter table t1 add primary key(a); +show create table t1; +drop table t1; + +# +# BIT fields +# + +set @@sql_mode='traditional'; +create table t1(a bit(2)); +--error 1406 +insert into t1 values(b'101'); +select * from t1; +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ecb3432753d..41cdf9f1c64 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1867,3 +1867,5 @@ insert into t1 values ('1'); select * from (select max(fld) from t1) as foo; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index 2d42320334a..839e94206d0 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -146,4 +146,5 @@ SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion'; -drop table t1, t2, t3, t4;
\ No newline at end of file +drop table t1, t2, t3, t4; +# End of 4.1 tests diff --git a/mysql-test/t/subselect_gis.test b/mysql-test/t/subselect_gis.test index 338051029c4..1ab139b7822 100644 --- a/mysql-test/t/subselect_gis.test +++ b/mysql-test/t/subselect_gis.test @@ -13,3 +13,5 @@ select City from t1 where (select intersects(GeomFromText(AsText(Location)),GeomFromText('Polygon((2 50, 2.5 50, 2.5 47, 2 47, 2 50))'))=0); drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index 5d796988178..3b1d2f393c2 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -159,3 +159,5 @@ EXECUTE my_stmt; EXECUTE my_stmt; deallocate prepare my_stmt; drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index f477fc378c6..b7a7e83d569 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -136,3 +136,5 @@ eval create table t1 (i int) index directory = "$MYSQL_TEST_DIR/var/master-data/ enable_query_log; show create table t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/synchronization.test b/mysql-test/t/synchronization.test index 09324b32b97..c7696195ee0 100644 --- a/mysql-test/t/synchronization.test +++ b/mysql-test/t/synchronization.test @@ -36,3 +36,5 @@ while ($1) dec $1; } DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/system_mysql_db.test b/mysql-test/t/system_mysql_db.test index acd19f47728..27c17da2731 100644 --- a/mysql-test/t/system_mysql_db.test +++ b/mysql-test/t/system_mysql_db.test @@ -16,3 +16,5 @@ use test; -- enable_query_log # keep results same with system_mysql_db_fix show tables; + +# End of 4.1 tests diff --git a/mysql-test/t/system_mysql_db_fix.test b/mysql-test/t/system_mysql_db_fix.test index f47b4cba6e6..3b19df5f756 100644 --- a/mysql-test/t/system_mysql_db_fix.test +++ b/mysql-test/t/system_mysql_db_fix.test @@ -91,3 +91,5 @@ DROP TABLE db, host, user, func, tables_priv, columns_priv, procs_priv, help_cat # check that we droped all system tables show tables; + +# End of 4.1 tests diff --git a/mysql-test/t/system_mysql_db_refs.test b/mysql-test/t/system_mysql_db_refs.test index 9e2c5a20b54..c5146e1b043 100644 --- a/mysql-test/t/system_mysql_db_refs.test +++ b/mysql-test/t/system_mysql_db_refs.test @@ -99,3 +99,5 @@ drop table test_func; drop table test_host; drop table test_user; drop table test_db; + +# End of 4.1 tests diff --git a/mysql-test/t/tablelock.test b/mysql-test/t/tablelock.test index fbc5d685096..95533903b45 100644 --- a/mysql-test/t/tablelock.test +++ b/mysql-test/t/tablelock.test @@ -47,3 +47,5 @@ CREATE TABLE t2 (a int); lock tables t1 write,t1 as b write, t2 write, t2 as c read; drop table t2,t1; unlock tables; + +# End of 4.1 tests diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index da7ce9b4722..9a7678ed712 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -112,3 +112,5 @@ insert into t1 values (3,1),(3,2); insert into t2 values (NULL, 'foo'), (NULL, 'bar'); select d, c from t1 left join t2 on b = c where a = 3 order by d; drop table t1, t2; + +# End of 4.1 tests diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test index ffc2e3a3ebf..34bbb365c70 100644 --- a/mysql-test/t/timezone.test +++ b/mysql-test/t/timezone.test @@ -58,3 +58,5 @@ select unix_timestamp('1970-01-01 01:00:00'), unix_timestamp('1970-01-01 01:00:01'), unix_timestamp('2038-01-01 00:59:59'), unix_timestamp('2038-01-01 01:00:00'); + +# End of 4.1 tests diff --git a/mysql-test/t/timezone2.test b/mysql-test/t/timezone2.test index 0b5aaed5d30..069c19341e4 100644 --- a/mysql-test/t/timezone2.test +++ b/mysql-test/t/timezone2.test @@ -48,6 +48,11 @@ insert into t1 (i, ts) values (unix_timestamp('2003-03-30 01:59:59'),'2003-03-30 01:59:59'), (unix_timestamp('2003-03-30 02:30:00'),'2003-03-30 02:30:00'), (unix_timestamp('2003-03-30 03:00:00'),'2003-03-30 03:00:00'); +# Values around and in spring time-gap +insert into t1 (i, ts) values + (unix_timestamp(20030330015959),20030330015959), + (unix_timestamp(20030330023000),20030330023000), + (unix_timestamp(20030330030000),20030330030000); # Normal value with DST insert into t1 (i, ts) values (unix_timestamp('2003-05-01 00:00:00'),'2003-05-01 00:00:00'); @@ -215,3 +220,5 @@ select convert_tz('2005-01-14 17:00:00', 'UTC', custTimeZone) from (select 'UTC' create table t1 select convert_tz(NULL, NULL, NULL); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/timezone3.test b/mysql-test/t/timezone3.test index 8910783cd85..0aedbafcec4 100644 --- a/mysql-test/t/timezone3.test +++ b/mysql-test/t/timezone3.test @@ -57,3 +57,5 @@ create table t1 (ts timestamp); insert into t1 values (19730101235900), (20040101235900); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/timezone_grant.test b/mysql-test/t/timezone_grant.test index f586ba0c5fe..f94d86eb266 100644 --- a/mysql-test/t/timezone_grant.test +++ b/mysql-test/t/timezone_grant.test @@ -61,6 +61,18 @@ select * from mysql.time_zone_name; --error 1142 select Name, convert_tz('2004-11-30 12:00:00', Name, 'UTC') from mysql.time_zone_name; +# +# Bug #9979: Use of CONVERT_TZ in multiple-table UPDATE causes bogus +# privilege error +# +drop table t1, t2; +create table t1 (a int, b datetime); +create table t2 (a int, b varchar(40)); +update t1 set b = '2005-01-01 10:00'; +update t1 set b = convert_tz(b, 'UTC', 'UTC'); +update t1 join t2 on (t1.a = t2.a) set t1.b = '2005-01-01 10:00' where t2.b = 'foo'; +update t1 join t2 on (t1.a = t2.a) set t1.b = convert_tz('2005-01-01 10:00','UTC','UTC') where t2.b = 'foo'; + # Clean-up connection default; delete from mysql.user where user like 'mysqltest\_%'; @@ -69,3 +81,4 @@ delete from mysql.tables_priv where user like 'mysqltest\_%'; flush privileges; drop table t1, t2; +# End of 4.1 tests diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 8a27636ed84..7bf8b1a4e2b 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -17,13 +17,13 @@ set @a:=0; select @a; insert into t1 values (1); select @a; -drop trigger t1.trg; +drop trigger trg; # let us test simple trigger reading some values create trigger trg before insert on t1 for each row set @a:=new.i; insert into t1 values (123); select @a; -drop trigger t1.trg; +drop trigger trg; drop table t1; @@ -40,7 +40,7 @@ end| insert into t1 (i) values (1)| insert into t1 (i,j) values (2, 3)| select * from t1| -drop trigger t1.trg| +drop trigger trg| drop table t1| delimiter ;| @@ -52,7 +52,7 @@ create trigger trg after insert on t1 for each row set @a:=""; insert into t1 values (2),(3),(4),(5); select @a; -drop trigger t1.trg; +drop trigger trg; drop table t1; # PS doesn't work with multi-row statements @@ -75,7 +75,7 @@ set @update_failed:=""| update t1 set balance=1500| select @update_failed; select * from t1| -drop trigger t1.trg| +drop trigger trg| drop table t1| delimiter ;| --enable_ps_protocol @@ -88,7 +88,7 @@ create trigger trg after update on t1 for each row set @total_change:=0; update t1 set i=3; select @total_change; -drop trigger t1.trg; +drop trigger trg; drop table t1; # Before delete trigger @@ -100,7 +100,7 @@ create trigger trg before delete on t1 for each row set @del_sum:= 0; delete from t1 where i <= 3; select @del_sum; -drop trigger t1.trg; +drop trigger trg; drop table t1; # After delete trigger. @@ -111,7 +111,7 @@ create trigger trg after delete on t1 for each row set @del:= 1; set @del:= 0; delete from t1 where i <> 0; select @del; -drop trigger t1.trg; +drop trigger trg; drop table t1; # Several triggers on one table @@ -145,9 +145,9 @@ update t1 set j= 20; select @fired; select * from t1; -drop trigger t1.trg1; -drop trigger t1.trg2; -drop trigger t1.trg3; +drop trigger trg1; +drop trigger trg2; +drop trigger trg3; drop table t1; @@ -212,7 +212,7 @@ create trigger t1_ai after insert on t1 for each row insert into t1 (id, data) values (1, "one"), (2, "two"); select * from t1; select * from t2; -drop trigger t1.t1_ai; +drop trigger t1_ai; # Trigger which uses couple of tables (and partially emulates FK constraint) delimiter |; create trigger t1_bi before insert on t1 for each row @@ -282,6 +282,7 @@ drop table t1, t2; # Test of wrong column specifiers in triggers # create table t1 (i int); +create table t3 (i int); --error 1363 create trigger trg before insert on t1 for each row set @a:= old.i; @@ -301,7 +302,7 @@ create trigger trg before update on t1 for each row set @a:=old.j; # # Let us test various trigger creation errors -# +# Also quickly test table namespace (bug#5892/6182) # --error 1146 create trigger trg before insert on t2 for each row set @a:=1; @@ -311,10 +312,14 @@ create trigger trg before insert on t1 for each row set @a:=1; create trigger trg after insert on t1 for each row set @a:=1; --error 1359 create trigger trg2 before insert on t1 for each row set @a:=1; -drop trigger t1.trg; +--error 1359 +create trigger trg before insert on t3 for each row set @a:=1; +create trigger trg2 before insert on t3 for each row set @a:=1; +drop trigger trg2; +drop trigger trg; --error 1360 -drop trigger t1.trg; +drop trigger trg; create view v1 as select * from t1; --error 1347 @@ -322,6 +327,7 @@ create trigger trg before insert on v1 for each row set @a:=1; drop view v1; drop table t1; +drop table t3; create temporary table t1 (i int); --error 1361 @@ -339,7 +345,7 @@ drop table t1; create table t1 (x1col char); create trigger tx1 before insert on t1 for each row set new.x1col = 'x'; insert into t1 values ('y'); -drop trigger t1.tx1; +drop trigger tx1; drop table t1; # @@ -355,8 +361,8 @@ create trigger trg2 after delete on t1 for each row set @del_after:= @del_after set @del_before:=0, @del_after:= 0; delete from t1; select @del_before, @del_after; -drop trigger t1.trg1; -drop trigger t1.trg2; +drop trigger trg1; +drop trigger trg2; drop table t1; # Test for bug #5859 "DROP TABLE does not drop triggers". Trigger should not @@ -378,6 +384,19 @@ create trigger trg1 before insert on t1 for each row set @a:= 1; drop database mysqltest; use test; +# Test for bug #8791 +# "Triggers: Allowed to create triggers on a subject table in a different DB". +create database mysqltest; +create table mysqltest.t1 (i int); +--error ER_TRG_IN_WRONG_SCHEMA +create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1; +use mysqltest; +--error ER_TRG_IN_WRONG_SCHEMA +create trigger test.trg1 before insert on t1 for each row set @a:= 1; +drop database mysqltest; +use test; + + # Test for bug #5860 "Multi-table UPDATE does not activate update triggers" # We will also test how delete triggers wor for multi-table DELETE. create table t1 (i int, j int default 10, k int not null, key (k)); @@ -559,7 +578,7 @@ select * from t1; # To test properly code-paths different from those that are used # in ordinary INSERT we need to drop "before insert" trigger. alter table t1 add primary key (i); -drop trigger t1.bi; +drop trigger bi; --error 1054 insert into t1 values (2, 4) on duplicate key update k= k + 10; select * from t1; @@ -589,5 +608,37 @@ drop function bug5893; --error 1305 update t1 set col2 = 4; # This should not crash server too. -drop trigger t1.t1_bu; +drop trigger t1_bu; +drop table t1; + +# +# storing and restoring parsing modes for triggers (BUG#5891) +# +set sql_mode='ansi'; +create table t1 ("t1 column" int); +create trigger t1_bi before insert on t1 for each row set new."t1 column" = 5; +set sql_mode=""; +insert into t1 values (0); +# create trigger with different sql_mode +create trigger t1_af after insert on t1 for each row set @a=10; +insert into t1 values (0); +select * from t1; +select @a; +--replace_column 6 # +show triggers; +drop table t1; +# check that rigger preserve sql_mode during execution +set sql_mode="traditional"; +create table t1 (a date); +-- error 1292 +insert into t1 values ('2004-01-00'); +set sql_mode=""; +create trigger t1_bi before insert on t1 for each row set new.a = '2004-01-00'; +set sql_mode="traditional"; +insert into t1 values ('2004-01-01'); +select * from t1; +set sql_mode=default; +show create table t1; +--replace_column 6 # +show triggers; drop table t1; diff --git a/mysql-test/t/truncate.test b/mysql-test/t/truncate.test index b7ec506ecf1..f806bd8ec17 100644 --- a/mysql-test/t/truncate.test +++ b/mysql-test/t/truncate.test @@ -50,3 +50,5 @@ delete from t1; insert into t1 (a) values (NULL),(NULL); SELECT * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index 80aabf6c5e0..1ec5c600296 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -394,6 +394,8 @@ INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,''); select max(i) from t1 where c = ''; drop table t1; +# End of 4.1 tests + # # Bug#11657: Creation of secondary index fails # diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 304ed19b971..78bdd9b8a80 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -114,3 +114,5 @@ CREATE TABLE t1 (y YEAR); INSERT INTO t1 VALUES ('abc'); SELECT * FROM t1; DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index a7eb78cb292..f60bc5adb16 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -101,3 +101,5 @@ insert into t1 values ("12-00-00"), ("00-00-00 01:00:00"); insert into t1 values ("00-00-00"), ("00-00-00 00:00:00"); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 2901592fd9e..44032fde46f 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -268,7 +268,11 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; drop table t1; +# End of 4.1 tests + +# # Test for BUG#8397: decimal type in subselects (Item_cache_decimal) +# CREATE TABLE t1 (EMPNUM CHAR(3) NOT NULL, HOURS DECIMAL(5)); diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index 6b2183df069..0d479f312cd 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -126,3 +126,5 @@ create table t1 (a set('x','y') default 'x'); --error 1067 alter table t1 alter a set default 'z'; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index a27fd4c58b4..c0f1854d5b2 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -145,3 +145,5 @@ select * from t1 where reckey=1.08E2; select * from t1 where reckey=109; select * from t1 where reckey=1.09E2; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_nchar.test b/mysql-test/t/type_nchar.test index e85609e3f0c..f2258830450 100644 --- a/mysql-test/t/type_nchar.test +++ b/mysql-test/t/type_nchar.test @@ -33,3 +33,4 @@ create table t1 (c nchar varying(10)); show create table t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index f295311fe4e..81e06c70c7d 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -986,6 +986,10 @@ create table t1 (sl decimal(0,30)); create table t1 (sl decimal(5, 5)); show create table t1; drop table t1; +# Test limits +create table t1 (sl decimal(65, 30)); +show create table t1; +drop table t1; # # Bug 11557 (DEFAULT values rounded improperly @@ -1003,3 +1007,11 @@ insert into t1 (f1) values (1); select * from t1; drop table t1; +# +# Bug 12173 (show create table fails) +# +create table t1 ( + f0 decimal (30,30) zerofill not null DEFAULT 0, + f1 decimal (0,0) zerofill not null default 0); +show create table t1; +drop table t1; diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test index a2deb367e14..c1a5ac382ec 100644 --- a/mysql-test/t/type_ranges.test +++ b/mysql-test/t/type_ranges.test @@ -165,3 +165,5 @@ drop table t3; create table t3 select t1.id as id_A, t2.id as id_B from t1 left join t2 using ( id ); select * from t3; drop table t1,t2,t3; + +# End of 4.1 tests diff --git a/mysql-test/t/type_set.test b/mysql-test/t/type_set.test index b6410a9ea3d..56df3328246 100644 --- a/mysql-test/t/type_set.test +++ b/mysql-test/t/type_set.test @@ -37,3 +37,5 @@ INSERT INTO t1 VALUES ('ae,oe,ue,ss'); SELECT c FROM t1 ORDER BY c; SELECT c FROM t1 ORDER BY concat(c); DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 2f342f8bf67..7ae3f65f7cc 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -20,3 +20,5 @@ insert into t1 values ('09:00:00'),('13:00:00'),('19:38:34'), ('13:00:00'),('09: select t, time_to_sec(t),sec_to_time(time_to_sec(t)) from t1; select sec_to_time(time_to_sec(t)) from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 01d18afc5af..f96beedbebc 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -321,3 +321,4 @@ insert into t1 (a, c) values (4, '2004-04-04 00:00:00'), select * from t1; drop table t1; +# End of 4.1 tests diff --git a/mysql-test/t/type_uint.test b/mysql-test/t/type_uint.test index b1f59242e8e..a9212183cb6 100644 --- a/mysql-test/t/type_uint.test +++ b/mysql-test/t/type_uint.test @@ -13,3 +13,5 @@ insert into t1 values (-1); insert into t1 values ('5000000000'); select * from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index c67b8447494..9744da24c02 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -20,3 +20,5 @@ create table t1 (y year); insert into t1 values (now()); select if(y = now(), 1, 0) from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 4da19622dcb..227d1cddcfa 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -793,3 +793,5 @@ insert into t1 (col1) values (2),(3),(4),(5),(6); select 99 union all select id from t1 order by 1; select id from t1 union all select 99 order by 1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 21789a550b9..dd6c36d8414 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -201,3 +201,18 @@ analyze table t1,t2; update t1, t2 set t1.a = t2.a where t2.b = t1.b; show warnings; drop table t1, t2; + +# +# Bug #11868 Update with subquery with ref built with a key from the updated +# table crashes server +# +create table t1(f1 int, f2 int); +create table t2(f3 int, f4 int); +create index idx on t2(f3); +insert into t1 values(1,0),(2,0); +insert into t2 values(1,1),(2,2); +UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); +select * from t1; +drop table t1,t2; + +# End of 4.1 tests diff --git a/mysql-test/t/user_var-binlog.test b/mysql-test/t/user_var-binlog.test index 916a7dfa47b..004154339b2 100644 --- a/mysql-test/t/user_var-binlog.test +++ b/mysql-test/t/user_var-binlog.test @@ -17,3 +17,5 @@ show binlog events from 98; --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index f8c441c7564..91372b67f5e 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -121,6 +121,8 @@ set session @honk=99; --error 1382 set one_shot @honk=99; +# End of 4.1 tests + # # Bug #6598: problem with cast(NULL as signed integer); # diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test index 9425bd7bd99..5fbd116d7b8 100644 --- a/mysql-test/t/varbinary.test +++ b/mysql-test/t/varbinary.test @@ -35,3 +35,5 @@ select 0xfg; create table t1 select 1 as x, 2 as xx; select x,xx from t1; drop table t1; + +# End of 4.1 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index c3ffdc79c16..d6dd6017a16 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -390,6 +390,8 @@ SET GLOBAL table_cache=-1; SHOW VARIABLES LIKE 'table_cache'; SET GLOBAL table_cache=DEFAULT; +# End of 4.1 tests + # # Bug#6282 Packet error with SELECT INTO # @@ -406,3 +408,11 @@ drop table t1; set @@warning_count=1; --error 1238 set @@global.error_count=1; + +# +# Bug #10351: Setting ulong variable to > MAX_ULONG fails on 32-bit platform +# +set @@max_heap_table_size= 4294967296; +select @@max_heap_table_size > 0; +set global max_heap_table_size= 4294967296; +select @@global.max_heap_table_size > 0; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a98ecfe232f..5454b3409da 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1182,7 +1182,7 @@ create view v1 as select * from t1 where s1 <> 127 with check option; insert into v1 values (0); select * from v1; select * from t1; -drop trigger t1.t1_bi; +drop trigger t1_bi; drop view v1; drop table t1; @@ -1853,3 +1853,37 @@ CALL p1(); DROP PROCEDURE p1; DROP VIEW v1; DROP TABLE t1; + +# +# Bug #11760 Typo in Item_func_add_time::print() results in NULLs returned +# subtime() in view +create table t1(f1 datetime); +insert into t1 values('2005.01.01 12:0:0'); +create view v1 as select f1, subtime(f1, '1:1:1') as sb from t1; +select * from v1; +drop view v1; +drop table t1; + +# +# Test for bug #11412: query over a multitable view with GROUP_CONCAT +# +CREATE TABLE t1 ( + aid int PRIMARY KEY, + fn varchar(20) NOT NULL, + ln varchar(20) NOT NULL +); +CREATE TABLE t2 ( + aid int NOT NULL, + pid int NOT NULL +); +INSERT INTO t1 VALUES(1,'a','b'), (2,'c','d'); +INSERT INTO t2 values (1,1), (2,1), (2,2); + +CREATE VIEW v1 AS SELECT t1.*,t2.pid FROM t1,t2 WHERE t1.aid = t2.aid; + +SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM t1,t2 + WHERE t1.aid = t2.aid GROUP BY pid; +SELECT pid,GROUP_CONCAT(CONCAT(fn,' ',ln) ORDER BY 1) FROM v1 GROUP BY pid; + +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test index 314432af83e..f6ae7cdaf30 100644 --- a/mysql-test/t/warnings.test +++ b/mysql-test/t/warnings.test @@ -151,3 +151,5 @@ select * from t1 limit 0; select * from t1 limit 1, 0; select * from t1 limit 0, 0; drop table t1; + +# End of 4.1 tests diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 4a35b9f9c39..9c58c18cf59 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -45,7 +45,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ ptr_cmp.c mf_radix.c queues.c \ tree.c list.c hash.c array.c string.c typelib.c \ my_copy.c my_append.c my_lib.c \ - my_delete.c my_rename.c my_redel.c my_tempnam.c \ + my_delete.c my_rename.c my_redel.c \ my_chsize.c my_lread.c my_lwrite.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ my_sync.c my_getopt.c my_mkdir.c \ @@ -69,6 +69,7 @@ DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \ -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ -DDEFAULT_HOME_ENV=MYSQL_HOME \ + -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX \ @DEFS@ libmysys_a_DEPENDENCIES= @THREAD_LOBJECTS@ diff --git a/mysys/charset.c b/mysys/charset.c index 4920e7806a2..701170b747b 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -383,26 +383,28 @@ static my_bool init_available_charsets(myf myflags) while we may changing the cs_info_table */ pthread_mutex_lock(&THR_LOCK_charset); - - bzero(&all_charsets,sizeof(all_charsets)); - init_compiled_charsets(myflags); - - /* Copy compiled charsets */ - for (cs=all_charsets; - cs < all_charsets+array_elements(all_charsets)-1 ; - cs++) + if (!charset_initialized) { - if (*cs) + bzero(&all_charsets,sizeof(all_charsets)); + init_compiled_charsets(myflags); + + /* Copy compiled charsets */ + for (cs=all_charsets; + cs < all_charsets+array_elements(all_charsets)-1 ; + cs++) { - if (cs[0]->ctype) - if (init_state_maps(*cs)) - *cs= NULL; + if (*cs) + { + if (cs[0]->ctype) + if (init_state_maps(*cs)) + *cs= NULL; + } } + + strmov(get_charsets_dir(fname), MY_CHARSET_INDEX); + error= my_read_charset_file(fname,myflags); + charset_initialized=1; } - - strmov(get_charsets_dir(fname), MY_CHARSET_INDEX); - error= my_read_charset_file(fname,myflags); - charset_initialized=1; pthread_mutex_unlock(&THR_LOCK_charset); } return error; @@ -586,6 +588,7 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name, ~0 The escaped string did not fit in the to buffer >=0 The length of the escaped string */ + ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, const char *from, ulong length) @@ -700,6 +703,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, ~0 The escaped string did not fit in the to buffer >=0 The length of the escaped string */ + ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, const char *from, ulong length) @@ -712,7 +716,6 @@ ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, #endif for (end= from + length; from < end; from++) { - char escape= 0; #ifdef USE_MB int tmp_length; if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end))) diff --git a/mysys/default.c b/mysys/default.c index 15c92e816a6..bde7cbf2563 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -30,8 +30,8 @@ --no-defaults ; no options are read. --defaults-file=full-path-to-default-file ; Only this file will be read. --defaults-extra-file=full-path-to-default-file ; Read this file before ~/ - --print-defaults ; Print the modified command line and exit - --instance ; also read groups with concat(group, instance) + --defaults-group-suffix ; Also read groups with concat(group, suffix) + --print-defaults ; Print the modified command line and exit ****************************************************************************/ #include "mysys_priv.h" @@ -42,8 +42,7 @@ #include <winbase.h> #endif -const char *defaults_instance=0; -static const char instance_option[] = "--instance="; +const char *defaults_group_suffix=0; char *defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ @@ -61,6 +60,9 @@ static const char *f_extensions[]= { ".cnf", 0 }; #define NEWLINE "\n" #endif +static int handle_default_option(void *in_ctx, const char *group_name, + const char *option); + /* This structure defines the context that we pass to callback function 'handle_default_option' used in search_default_file @@ -101,35 +103,81 @@ static char *remove_end_comment(char *ptr); func_ctx It's context. Usually it is the structure to store additional options. DESCRIPTION + Process the default options from argc & argv + Read through each found config file looks and calls 'func' to process + each option. + + NOTES + --defaults-group-suffix is only processed if we are called from + load_defaults(). - This function looks for config files in default directories. Then it - travesrses each of the files and calls func to process each option. RETURN 0 ok 1 given cinf_file doesn't exist + + The global variable 'defaults_group_suffix' is updated with value for + --defaults_group_suffix */ int my_search_option_files(const char *conf_file, int *argc, char ***argv, - uint *args_used, Process_option_func func, - void *func_ctx) + uint *args_used, Process_option_func func, + void *func_ctx) { const char **dirs, *forced_default_file, *forced_extra_defaults; int error= 0; DBUG_ENTER("my_search_option_files"); /* Check if we want to force the use a specific default file */ - get_defaults_files(*argc - *args_used, *argv + *args_used, - (char **)&forced_default_file, - (char **)&forced_extra_defaults); - if (forced_default_file) - forced_default_file= strchr(forced_default_file,'=')+1; - if (forced_extra_defaults) - defaults_extra_file= strchr(forced_extra_defaults,'=')+1; + *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used, + (char **) &forced_default_file, + (char **) &forced_extra_defaults, + (char **) &defaults_group_suffix); - (*args_used)+= (forced_default_file ? 1 : 0) + - (forced_extra_defaults ? 1 : 0); + if (! defaults_group_suffix) + defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV)); + + /* + We can only handle 'defaults-group-suffix' if we are called from + load_defaults() as otherwise we can't know the type of 'func_ctx' + */ + if (defaults_group_suffix && func == handle_default_option) + { + /* Handle --defaults-group-suffix= */ + uint i; + const char **extra_groups; + const uint instance_len= strlen(defaults_group_suffix); + struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx; + char *ptr; + TYPELIB *group= ctx->group; + + if (!(extra_groups= + (const char**)alloc_root(ctx->alloc, + (2*group->count+1)*sizeof(char*)))) + goto err; + + for (i= 0; i < group->count; i++) + { + uint len; + extra_groups[i]= group->type_names[i]; /** copy group */ + + len= strlen(extra_groups[i]); + if (!(ptr= alloc_root(ctx->alloc, len+instance_len+1))) + goto err; + + extra_groups[i+group->count]= ptr; + + /** Construct new group */ + memcpy(ptr, extra_groups[i], len); + memcpy(ptr+len, defaults_group_suffix, instance_len+1); + } + + group->count*= 2; + group->type_names= extra_groups; + group->type_names[group->count]= 0; + } + if (forced_default_file) { if ((error= search_default_file_with_ext(func, func_ctx, "", "", @@ -222,32 +270,54 @@ static int handle_default_option(void *in_ctx, const char *group_name, /* - Gets --defaults-file and --defaults-extra-file options from command line. + Gets options from the command line SYNOPSIS - get_defaults_files() + get_defaults_options() argc Pointer to argc of original program argv Pointer to argv of original program defaults --defaults-file option extra_defaults --defaults-extra-file option RETURN - defaults and extra_defaults will be set to appropriate items - of argv array, or to NULL if there are no such options + # Number of arguments used from *argv + defaults and extra_defaults will be set to option of the appropriate + items of argv array, or to NULL if there are no such options */ -void get_defaults_files(int argc, char **argv, - char **defaults, char **extra_defaults) +int get_defaults_options(int argc, char **argv, + char **defaults, + char **extra_defaults, + char **group_suffix) { - *defaults=0; - *extra_defaults=0; - if (argc >= 2) + int org_argc= argc, prev_argc= 0; + *defaults= *extra_defaults= *group_suffix= 0; + + while (argc >= 2 && argc != prev_argc) { - if (is_prefix(argv[1],"--defaults-file=")) - *defaults= argv[1]; - else if (is_prefix(argv[1],"--defaults-extra-file=")) - *extra_defaults= argv[1]; + /* Skip program name or previously handled argument */ + argv++; + prev_argc= argc; /* To check if we found */ + if (!*defaults && is_prefix(*argv,"--defaults-file=")) + { + *defaults= *argv + sizeof("--defaults-file=")-1; + argc--; + continue; + } + if (!*extra_defaults && is_prefix(*argv,"--defaults-extra-file=")) + { + *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1; + argc--; + continue; + } + if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix=")) + { + *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1; + argc--; + continue; + } } + return org_argc - argc; } @@ -297,6 +367,10 @@ int load_defaults(const char *conf_file, const char **groups, init_default_directories(); init_alloc_root(&alloc,512,0); + /* + Check if the user doesn't want any default option processing + --no-defaults is always the first option + */ if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults")) { /* remove the --no-defaults argument and return only the other arguments */ @@ -329,51 +403,8 @@ int load_defaults(const char *conf_file, const char **groups, ctx.args= &args; ctx.group= &group; - if (*argc >= 2 && - is_prefix(argv[0][1], instance_option)) - { - args_used++; - defaults_instance= argv[0][args_used]+sizeof(instance_option)-1; - } - else - { - defaults_instance= getenv("MYSQL_INSTANCE"); - } - - if (defaults_instance) - { - /** Handle --instance= */ - uint i, len; - const char **extra_groups; - const uint instance_len= strlen(defaults_instance); - - if (!(extra_groups= - (const char**)alloc_root(&alloc, (2*group.count+1)*sizeof(char*)))) - goto err; - - for (i= 0; i<group.count; i++) - { - extra_groups[i]= group.type_names[i]; /** copy group */ - - len= strlen(extra_groups[i]); - if (!(ptr= alloc_root(&alloc, len+instance_len+1))) - goto err; - - extra_groups[i+group.count]= ptr; - - /** Construct new group */ - memcpy(ptr, extra_groups[i], len); - ptr+= len; - memcpy(ptr, defaults_instance, instance_len+1); - } - - group.count*= 2; - group.type_names= extra_groups; - group.type_names[group.count]= 0; - } - error= my_search_option_files(conf_file, argc, argv, &args_used, - handle_default_option, (void *) &ctx); + handle_default_option, (void *) &ctx); /* Here error contains <> 0 only if we have a fully specified conf_file or a forced default file @@ -386,11 +417,14 @@ int load_defaults(const char *conf_file, const char **groups, /* copy name + found arguments + command line arguments to new array */ res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */ memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*)); - /* Skip --defaults-file and --defaults-extra-file */ + /* Skip --defaults-xxx options */ (*argc)-= args_used; (*argv)+= args_used; - /* Check if we wan't to see the new argument list */ + /* + Check if we wan't to see the new argument list + This options must always be the last of the default options + */ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults")) { found_print_defaults=1; @@ -851,14 +885,14 @@ void print_defaults(const char *conf_file, const char **groups) fputs(*groups,stdout); } - if (defaults_instance) + if (defaults_group_suffix) { groups= groups_save; for ( ; *groups ; groups++) { fputc(' ',stdout); fputs(*groups,stdout); - fputs(defaults_instance,stdout); + fputs(defaults_group_suffix,stdout); } } puts("\nThe following options may be given as the first argument:\n\ @@ -883,6 +917,7 @@ typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT); static uint my_get_system_windows_directory(char *buffer, uint size) { + uint count; GET_SYSTEM_WINDOWS_DIRECTORY func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY) GetProcAddress(GetModuleHandle("kernel32.dll"), @@ -890,22 +925,19 @@ static uint my_get_system_windows_directory(char *buffer, uint size) if (func_ptr) return func_ptr(buffer, size); - else - { - /* - Windows NT 4.0 Terminal Server Edition: - To retrieve the shared Windows directory, call GetSystemDirectory and - trim the "System32" element from the end of the returned path. - */ - UINT count= GetSystemDirectory(buffer, size); - if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0) - { - count-= 8; - buffer[count] = '\0'; - } - return count; + /* + Windows NT 4.0 Terminal Server Edition: + To retrieve the shared Windows directory, call GetSystemDirectory and + trim the "System32" element from the end of the returned path. + */ + count= GetSystemDirectory(buffer, size); + if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0) + { + count-= 8; + buffer[count] = '\0'; } + return count; } #endif @@ -918,7 +950,7 @@ static uint my_get_system_windows_directory(char *buffer, uint size) 2. GetWindowsDirectory() 3. GetSystemWindowsDirectory() 4. getenv(DEFAULT_HOME_ENV) - 5. Direcotry above where the executable is located + 5. Directory above where the executable is located 6. "" On Novell NetWare, this is: @@ -977,26 +1009,28 @@ static void init_default_directories() Look for the second-to-last \ in the filename, but hang on to a pointer after the last \ in case we're in the root of a drive. - */ + */ for ( ; end > config_dir; end--) { if (*end == FN_LIBCHAR) { if (last) + { + if (end != config_dir) + { + /* Keep the last '\' as this works both with D:\ and a directory */ + end[1]= 0; + } + else + { + /* No parent directory (strange). Use current dir + '\' */ + last[1]= 0; + } break; + } last= end; } } - - if (last) - { - if (end != config_dir && end[-1] == FN_DEVCHAR) /* Ended up with D:\ */ - end[1]= 0; /* Keep one \ */ - else if (end != config_dir) - end[0]= 0; - else - last[1]= 0; - } *ptr++= (char *)&config_dir; } #endif diff --git a/mysys/default_modify.c b/mysys/default_modify.c index ea384f9f27a..de03d783c68 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -20,8 +20,7 @@ #include <my_dir.h> #define BUFF_SIZE 1024 -/* should be big enough to handle at least one line */ -#define RESERVE 1024 +#define RESERVE 1024 /* Extend buffer with this extent */ #ifdef __WIN__ #define NEWLINE "\r\n" @@ -70,7 +69,7 @@ int modify_defaults_file(const char *file_location, const char *option, char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer; uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size; my_bool in_section= FALSE, opt_applied= 0; - uint reserve_extended= 1, old_opt_len= 0; + uint reserve_extended; uint new_opt_len; int reserve_occupied= 0; DBUG_ENTER("modify_defaults_file"); @@ -88,25 +87,21 @@ int modify_defaults_file(const char *file_location, const char *option, new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN; /* calculate the size of the buffer we need */ - buffer_size= sizeof(char) * (file_stat.st_size + - /* option name len */ - opt_len + - /* reserve for '=' char */ - 1 + - /* option value len */ - optval_len + - /* reserve space for newline */ - NEWLINE_LEN + - /* The ending zero */ - 1 + - /* reserve some additional space */ - RESERVE); + reserve_extended= (opt_len + + 1 + /* For '=' char */ + optval_len + /* Option value len */ + NEWLINE_LEN + /* Space for newline */ + RESERVE); /* Some additional space */ + + buffer_size= (file_stat.st_size + + 1); /* The ending zero */ /* Reserve space to read the contents of the file and some more for the option we want to add. */ - if (!(file_buffer= (char*) my_malloc(buffer_size, MYF(MY_WME)))) + if (!(file_buffer= (char*) my_malloc(buffer_size + reserve_extended, + MYF(MY_WME)))) goto malloc_err; sect_len= (uint) strlen(section_name); @@ -130,31 +125,20 @@ int modify_defaults_file(const char *file_location, const char *option, my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) || *(src_ptr + opt_len) == '\0')) { - /* - we should change all options. If opt_applied is set, we are running - into reserved memory area. Hence we should check for overruns. - */ - if (opt_applied) + char *old_src_ptr= src_ptr; + src_ptr= strend(src_ptr+ opt_len); /* Find the end of the line */ + + /* could be negative */ + reserve_occupied+= (int) new_opt_len - (int) (src_ptr - old_src_ptr); + if (reserve_occupied >= (int) reserve_extended) { - src_ptr+= opt_len; /* If we correct an option, we know it's name */ - old_opt_len= opt_len; - - while (*src_ptr++) /* Find the end of the line */ - old_opt_len++; - - /* could be negative */ - reserve_occupied+= (int) new_opt_len - (int) old_opt_len; - if ((int) reserve_occupied > (int) (RESERVE*reserve_extended)) - { - if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size + - RESERVE*reserve_extended, - MYF(MY_WME|MY_FREE_ON_ERROR)))) - goto malloc_err; - reserve_extended++; - } + reserve_extended= (uint) reserve_occupied + RESERVE; + if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size + + reserve_extended, + MYF(MY_WME|MY_FREE_ON_ERROR)))) + goto malloc_err; } - else - opt_applied= 1; + opt_applied= 1; dst_ptr= add_option(dst_ptr, option_value, option, remove_option); } else @@ -164,6 +148,7 @@ int modify_defaults_file(const char *file_location, const char *option, { dst_ptr= add_option(dst_ptr, option_value, option, remove_option); opt_applied= 1; /* set the flag to do write() later */ + reserve_occupied= new_opt_len+ opt_len + 1 + NEWLINE_LEN; } for (; nr_newlines; nr_newlines--) diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index ba958b234d2..4a917fc8287 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -152,6 +152,7 @@ my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit) bitmap_lock(map); res= bitmap_fast_test_and_set(map, bitmap_bit); bitmap_unlock(map); + return res; } uint bitmap_set_next(MY_BITMAP *map) @@ -338,6 +339,37 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2) } +/* + Set/clear all bits above a bit. + + SYNOPSIS + bitmap_set_above() + map RETURN The bitmap to change. + from_byte The bitmap buffer byte offset to start with. + use_bit The bit value (1/0) to use for all upper bits. + + NOTE + You can only set/clear full bytes. + The function is meant for the situation that you copy a smaller bitmap + to a bigger bitmap. Bitmap lengths are always multiple of eigth (the + size of a byte). Using 'from_byte' saves multiplication and division + by eight during parameter passing. + + RETURN + void +*/ + +void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit) +{ + uchar use_byte= use_bit ? 0xff : 0; + uchar *to= map->bitmap + from_byte; + uchar *end= map->bitmap + map->bitmap_size; + + while (to < end) + *to++= use_byte; +} + + void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2) { uchar *to=map->bitmap, *from=map2->bitmap, *end; diff --git a/mysys/my_tempnam.c b/mysys/my_tempnam.c deleted file mode 100644 index 9f765298fb6..00000000000 --- a/mysys/my_tempnam.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - This function is only used by some old ISAM code. - When we remove ISAM support from MySQL, we should also delete this file - - One should instead use the functions in mf_tempfile.c -*/ - -#include "mysys_priv.h" -#include <m_string.h> - -/* HPUX 11.0 doesn't allow us to change the environ pointer */ -#ifdef HPUX11 -#undef HAVE_TEMPNAM -#endif - -#include "my_static.h" -#include "mysys_err.h" - -#define TMP_EXT ".tmp" /* Extension of tempfile */ -#if ! defined(P_tmpdir) -#define P_tmpdir "" -#endif - -#ifdef HAVE_TEMPNAM -#if !defined( MSDOS) && !defined(OS2) && !defined(__NETWARE__) -extern char **environ; -#endif -#endif - -/* Make a uniq temp file name by using dir and adding something after - pfx to make name uniq. Name is made by adding a uniq 8 length-string and - TMP_EXT after pfx. - Returns pointer to malloced area for filename. Should be freed by - free(). - The name should be uniq, but it isn't checked if it file allready exists. - Uses tempnam() if function exist on system. - This function fixes that if dir is given it's used. For example - MSDOS tempnam() uses always TMP environment-variable if it exists. -*/ - /* ARGSUSED */ - -my_string my_tempnam(const char *dir, const char *pfx, - myf MyFlags __attribute__((unused))) -{ -#ifdef _MSC_VER - char temp[FN_REFLEN],*end,*res,**old_env,*temp_env[1]; - old_env=environ; - if (dir) - { - end=strend(dir)-1; - if (!dir[0]) - { /* Change empty string to current dir */ - temp[0]= FN_CURLIB; - temp[1]= 0; - dir=temp; - } - else if (*end == FN_DEVCHAR) - { /* Get current dir for drive */ - _fullpath(temp,dir,FN_REFLEN); - dir=temp; - } - else if (*end == FN_LIBCHAR && dir < end && end[-1] != FN_DEVCHAR) - { - strmake(temp,dir,(uint) (end-dir)); /* Copy and remove last '\' */ - dir=temp; - } - environ=temp_env; /* Force use of dir (dir not checked) */ - temp_env[0]=0; - } - res=tempnam((char*) dir,(my_string) pfx); - environ=old_env; - return res; -#else -#ifdef __ZTC__ - if (!dir) - { /* If empty test first if TMP can be used */ - dir=getenv("TMP"); - } - return tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */ -#else -#ifdef HAVE_TEMPNAM - char temp[2],*res,**old_env,*temp_env[1]; - - if (dir && !dir[0]) - { /* Change empty string to current dir */ - temp[0]= FN_CURLIB; - temp[1]= 0; - dir=temp; - } -#ifdef OS2 - /* changing environ variable doesn't work with VACPP */ - char buffer[256], *end; - buffer[sizeof[buffer)-1]= 0; - end= strxnmov(buffer, sizeof(buffer)-1, (char*) "TMP=", dir, NullS); - /* remove ending backslash */ - if (end[-1] == '\\') - end[-1]= 0; - putenv(buffer); -#elif !defined(__NETWARE__) - old_env=(char**)environ; - if (dir) - { /* Don't use TMPDIR if dir is given */ - /* - The following strange cast is required because the IBM compiler on AIX - doesn't allow us to cast the value of environ. - The cast of environ is needed as some systems doesn't allow us to - update environ with a char ** pointer. (const mismatch) - */ - (*(char***) &environ)=(char**) temp_env; - temp_env[0]=0; - } -#endif - res=tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */ -#if !defined(OS2) && !defined(__NETWARE__) - (*(char***) &environ)=(char**) old_env; -#endif - if (!res) - DBUG_PRINT("error",("Got error: %d from tempnam",errno)); - return res; -#else - register long uniq; - register int length; - my_string pos,end_pos; - DBUG_ENTER("my_tempnam"); - /* Make a uniq nummber */ - pthread_mutex_lock(&THR_LOCK_open); - uniq= ((long) getpid() << 20) + (long) _my_tempnam_used++ ; - pthread_mutex_unlock(&THR_LOCK_open); - if (!dir && !(dir=getenv("TMPDIR"))) /* Use this if possibly */ - dir=P_tmpdir; /* Use system default */ - length=strlen(dir)+strlen(pfx)+1; - - DBUG_PRINT("test",("mallocing %d byte",length+8+sizeof(TMP_EXT)+1)); - if (!(pos=(char*) malloc(length+8+sizeof(TMP_EXT)+1))) - { - if (MyFlags & MY_FAE+MY_WME) - my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), - length+8+sizeof(TMP_EXT)+1); - DBUG_RETURN(NullS); - } - end_pos=strmov(pos,dir); - if (end_pos != pos && end_pos[-1] != FN_LIBCHAR) - *end_pos++=FN_LIBCHAR; - end_pos=strmov(end_pos,pfx); - - for (length=0 ; length < 8 && uniq ; length++) - { - *end_pos++= _dig_vec_upper[(int) (uniq & 31)]; - uniq >>= 5; - } - VOID(strmov(end_pos,TMP_EXT)); - DBUG_PRINT("exit",("tempnam: '%s'",pos)); - DBUG_RETURN(pos); -#endif /* HAVE_TEMPNAM */ -#endif /* __ZTC__ */ -#endif /* _MSC_VER */ -} /* my_tempnam */ diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 85a2b34b851..1a47a061b97 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -84,6 +84,7 @@ multiple read locks. my_bool thr_lock_inited=0; ulong locks_immediate = 0L, locks_waited = 0L; +ulong table_lock_wait_timeout; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; /* The following constants are only for debug output */ @@ -109,25 +110,32 @@ my_bool init_thr_lock() return 0; } +static inline my_bool +thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs) +{ + return rhs == lhs; +} + + #ifdef EXTRA_DEBUG #define MAX_FOUND_ERRORS 10 /* Report 10 first errors */ static uint found_errors=0; static int check_lock(struct st_lock_list *list, const char* lock_type, - const char *where, my_bool same_thread, bool no_cond) + const char *where, my_bool same_owner, bool no_cond) { THR_LOCK_DATA *data,**prev; uint count=0; - pthread_t first_thread; - LINT_INIT(first_thread); + THR_LOCK_OWNER *first_owner; + LINT_INIT(first_owner); prev= &list->data; if (list->data) { enum thr_lock_type last_lock_type=list->data->type; - if (same_thread && list->data) - first_thread=list->data->thread; + if (same_owner && list->data) + first_owner= list->data->owner; for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next) { if (data->type != last_lock_type) @@ -139,7 +147,8 @@ static int check_lock(struct st_lock_list *list, const char* lock_type, count, lock_type, where); return 1; } - if (same_thread && ! pthread_equal(data->thread,first_thread) && + if (same_owner && + !thr_lock_owner_equal(data->owner, first_owner) && last_lock_type != TL_WRITE_ALLOW_WRITE) { fprintf(stderr, @@ -255,8 +264,8 @@ static void check_locks(THR_LOCK *lock, const char *where, } if (lock->read.data) { - if (!pthread_equal(lock->write.data->thread, - lock->read.data->thread) && + if (!thr_lock_owner_equal(lock->write.data->owner, + lock->read.data->owner) && ((lock->write.data->type > TL_WRITE_DELAYED && lock->write.data->type != TL_WRITE_ONLY) || ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT || @@ -330,24 +339,32 @@ void thr_lock_delete(THR_LOCK *lock) DBUG_VOID_RETURN; } + +void thr_lock_info_init(THR_LOCK_INFO *info) +{ + info->thread= pthread_self(); + info->thread_id= my_thread_id(); /* for debugging */ + info->n_cursors= 0; +} + /* Initialize a lock instance */ void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param) { data->lock=lock; data->type=TL_UNLOCK; - data->thread=pthread_self(); - data->thread_id=my_thread_id(); /* for debugging */ + data->owner= 0; /* no owner yet */ data->status_param=param; data->cond=0; } -static inline my_bool have_old_read_lock(THR_LOCK_DATA *data,pthread_t thread) +static inline my_bool +have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner) { for ( ; data ; data=data->next) { - if ((pthread_equal(data->thread,thread))) + if (thr_lock_owner_equal(data->owner, owner)) return 1; /* Already locked by thread */ } return 0; @@ -365,12 +382,15 @@ static inline my_bool have_specific_lock(THR_LOCK_DATA *data, } -static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, - my_bool in_wait_list) +static enum enum_thr_lock_result +wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, + my_bool in_wait_list) { - pthread_cond_t *cond=get_cond(); - struct st_my_thread_var *thread_var=my_thread_var; - int result; + struct st_my_thread_var *thread_var= my_thread_var; + pthread_cond_t *cond= &thread_var->suspend; + struct timespec wait_timeout; + enum enum_thr_lock_result result= THR_LOCK_ABORTED; + my_bool can_deadlock= test(data->owner->info->n_cursors); if (!in_wait_list) { @@ -382,31 +402,52 @@ static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, /* Set up control struct to allow others to abort locks */ thread_var->current_mutex= &data->lock->mutex; thread_var->current_cond= cond; + data->cond= cond; - data->cond=cond; + if (can_deadlock) + set_timespec(wait_timeout, table_lock_wait_timeout); while (!thread_var->abort || in_wait_list) { - pthread_cond_wait(cond,&data->lock->mutex); - if (data->cond != cond) + int rc= can_deadlock ? pthread_cond_timedwait(cond, &data->lock->mutex, + &wait_timeout) : + pthread_cond_wait(cond, &data->lock->mutex); + /* + We must break the wait if one of the following occurs: + - the connection has been aborted (!thread_var->abort), but + this is not a delayed insert thread (in_wait_list). For a delayed + insert thread the proper action at shutdown is, apparently, to + acquire the lock and complete the insert. + - the lock has been granted (data->cond is set to NULL by the granter), + or the waiting has been aborted (additionally data->type is set to + TL_UNLOCK). + - the wait has timed out (rc == ETIMEDOUT) + Order of checks below is important to not report about timeout + if the predicate is true. + */ + if (data->cond == 0) break; + if (rc == ETIMEDOUT) + { + result= THR_LOCK_WAIT_TIMEOUT; + break; + } } if (data->cond || data->type == TL_UNLOCK) { - if (data->cond) /* aborted */ + if (data->cond) /* aborted or timed out */ { if (((*data->prev)=data->next)) /* remove from wait-list */ data->next->prev= data->prev; else wait->last=data->prev; + data->type= TL_UNLOCK; /* No lock */ } - data->type=TL_UNLOCK; /* No lock */ - result=1; /* Didn't get lock */ check_locks(data->lock,"failed wait_for_lock",0); } else { - result=0; + result= THR_LOCK_SUCCESS; statistic_increment(locks_waited, &THR_LOCK_lock); if (data->lock->get_status) (*data->lock->get_status)(data->status_param, 0); @@ -423,20 +464,24 @@ static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, } -int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) +enum enum_thr_lock_result +thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, + enum thr_lock_type lock_type) { THR_LOCK *lock=data->lock; - int result=0; + enum enum_thr_lock_result result= THR_LOCK_SUCCESS; + struct st_lock_list *wait_queue; + THR_LOCK_DATA *lock_owner; DBUG_ENTER("thr_lock"); data->next=0; data->cond=0; /* safety */ data->type=lock_type; - data->thread=pthread_self(); /* Must be reset ! */ - data->thread_id=my_thread_id(); /* Must be reset ! */ + data->owner= owner; /* Must be reset ! */ VOID(pthread_mutex_lock(&lock->mutex)); DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx type: %d", - data,data->thread_id,lock,(int) lock_type)); + data, data->owner->info->thread_id, + lock, (int) lock_type)); check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ? "enter read_lock" : "enter write_lock",0); if ((int) lock_type <= (int) TL_READ_NO_INSERT) @@ -454,8 +499,8 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) */ DBUG_PRINT("lock",("write locked by thread: %ld", - lock->write.data->thread_id)); - if (pthread_equal(data->thread,lock->write.data->thread) || + lock->write.data->owner->info->thread_id)); + if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type <= TL_WRITE_DELAYED && (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) || (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT && @@ -476,14 +521,14 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) { /* We are not allowed to get a READ lock in this case */ data->type=TL_UNLOCK; - result=1; /* Can't wait for this one */ + result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } } else if (!lock->write_wait.data || lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY || lock_type == TL_READ_HIGH_PRIORITY || - have_old_read_lock(lock->read.data,data->thread)) + have_old_read_lock(lock->read.data, data->owner)) { /* No important write-locks */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; @@ -496,8 +541,12 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } - /* Can't get lock yet; Wait for it */ - DBUG_RETURN(wait_for_lock(&lock->read_wait,data,0)); + /* + We're here if there is an active write lock or no write + lock but a high priority write waiting in the write_wait queue. + In the latter case we should yield the lock to the writer. + */ + wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ { @@ -506,7 +555,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY) { data->type=TL_UNLOCK; - result=1; /* Can't wait for this one */ + result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } /* @@ -540,7 +589,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) { /* We are not allowed to get a lock in this case */ data->type=TL_UNLOCK; - result=1; /* Can't wait for this one */ + result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } @@ -549,7 +598,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in the same thread, but this will never happen within MySQL. */ - if (pthread_equal(data->thread,lock->write.data->thread) || + if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock_type == TL_WRITE_ALLOW_WRITE && !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) @@ -572,7 +621,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) goto end; } DBUG_PRINT("lock",("write locked by thread: %ld", - lock->write.data->thread_id)); + lock->write.data->owner->info->thread_id)); } else { @@ -608,10 +657,24 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) } } DBUG_PRINT("lock",("write locked by thread: %ld, type: %ld", - lock->read.data->thread_id,data->type)); + lock->read.data->owner->info->thread_id, data->type)); } - DBUG_RETURN(wait_for_lock(&lock->write_wait,data,0)); + wait_queue= &lock->write_wait; + } + /* + Try to detect a trivial deadlock when using cursors: attempt to + lock a table that is already locked by an open cursor within the + same connection. lock_owner can be zero if we succumbed to a high + priority writer in the write_wait queue. + */ + lock_owner= lock->read.data ? lock->read.data : lock->write.data; + if (lock_owner && lock_owner->owner->info == owner->info) + { + result= THR_LOCK_DEADLOCK; + goto end; } + /* Can't get lock yet; Wait for it */ + DBUG_RETURN(wait_for_lock(wait_queue, data, 0)); end: pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(result); @@ -656,7 +719,7 @@ static inline void free_all_read_locks(THR_LOCK *lock, lock->read_no_write_count++; } DBUG_PRINT("lock",("giving read lock to thread: %ld", - data->thread_id)); + data->owner->info->thread_id)); data->cond=0; /* Mark thread free */ VOID(pthread_cond_signal(cond)); } while ((data=data->next)); @@ -674,7 +737,7 @@ void thr_unlock(THR_LOCK_DATA *data) enum thr_lock_type lock_type=data->type; DBUG_ENTER("thr_unlock"); DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx", - data,data->thread_id,lock)); + data, data->owner->info->thread_id, lock)); pthread_mutex_lock(&lock->mutex); check_locks(lock,"start of release lock",0); @@ -734,7 +797,7 @@ void thr_unlock(THR_LOCK_DATA *data) (*lock->check_status)(data->status_param)) data->type=TL_WRITE; /* Upgrade lock */ DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld", - data->type,data->thread_id)); + data->type, data->owner->info->thread_id)); { pthread_cond_t *cond=data->cond; data->cond=0; /* Mark thread free */ @@ -842,7 +905,8 @@ static void sort_locks(THR_LOCK_DATA **data,uint count) } -int thr_multi_lock(THR_LOCK_DATA **data,uint count) +enum enum_thr_lock_result +thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) { THR_LOCK_DATA **pos,**end; DBUG_ENTER("thr_multi_lock"); @@ -852,10 +916,11 @@ int thr_multi_lock(THR_LOCK_DATA **data,uint count) /* lock everything */ for (pos=data,end=data+count; pos < end ; pos++) { - if (thr_lock(*pos,(*pos)->type)) + enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type); + if (result != THR_LOCK_SUCCESS) { /* Aborted */ thr_multi_unlock(data,(uint) (pos-data)); - DBUG_RETURN(1); + DBUG_RETURN(result); } #ifdef MAIN printf("Thread: %s Got lock: 0x%lx type: %d\n",my_thread_name(), @@ -909,7 +974,7 @@ int thr_multi_lock(THR_LOCK_DATA **data,uint count) } while (pos != data); } #endif - DBUG_RETURN(0); + DBUG_RETURN(THR_LOCK_SUCCESS); } /* free all locks */ @@ -932,7 +997,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count) else { DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: %ld lock: 0x%lx", - *pos,(*pos)->thread_id,(*pos)->lock)); + *pos, (*pos)->owner->info->thread_id, (*pos)->lock)); } } DBUG_VOID_RETURN; @@ -952,6 +1017,7 @@ void thr_abort_locks(THR_LOCK *lock) for (data=lock->read_wait.data; data ; data=data->next) { data->type=TL_UNLOCK; /* Mark killed */ + /* It's safe to signal the cond first: we're still holding the mutex. */ pthread_cond_signal(data->cond); data->cond=0; /* Removed from list */ } @@ -977,18 +1043,21 @@ void thr_abort_locks(THR_LOCK *lock) This is used to abort all locks for a specific thread */ -void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread) +my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread) { THR_LOCK_DATA *data; + my_bool found= FALSE; DBUG_ENTER("thr_abort_locks_for_thread"); pthread_mutex_lock(&lock->mutex); for (data= lock->read_wait.data; data ; data= data->next) { - if (pthread_equal(thread, data->thread)) + if (pthread_equal(thread, data->owner->info->thread)) { DBUG_PRINT("info",("Aborting read-wait lock")); data->type= TL_UNLOCK; /* Mark killed */ + /* It's safe to signal the cond first: we're still holding the mutex. */ + found= TRUE; pthread_cond_signal(data->cond); data->cond= 0; /* Removed from list */ @@ -1000,10 +1069,11 @@ void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread) } for (data= lock->write_wait.data; data ; data= data->next) { - if (pthread_equal(thread, data->thread)) + if (pthread_equal(thread, data->owner->info->thread)) { DBUG_PRINT("info",("Aborting write-wait lock")); data->type= TL_UNLOCK; + found= TRUE; pthread_cond_signal(data->cond); data->cond= 0; @@ -1014,7 +1084,7 @@ void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread) } } pthread_mutex_unlock(&lock->mutex); - DBUG_VOID_RETURN; + DBUG_RETURN(found); } @@ -1117,7 +1187,8 @@ static void thr_print_lock(const char* name,struct st_lock_list *list) prev= &list->data; for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next) { - printf("0x%lx (%lu:%d); ",(ulong) data,data->thread_id,(int) data->type); + printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id, + (int) data->type); if (data->prev != prev) printf("\nWarning: prev didn't point at previous lock\n"); prev= &data->next; @@ -1250,11 +1321,16 @@ static void *test_thread(void *arg) { int i,j,param=*((int*) arg); THR_LOCK_DATA data[MAX_LOCK_COUNT]; + THR_LOCK_OWNER owner; + THR_LOCK_INFO lock_info; THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT]; my_thread_init(); printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout); + + thr_lock_info_init(&lock_info); + thr_lock_owner_init(&owner, &lock_info); for (i=0; i < lock_counts[param] ; i++) thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL); for (j=1 ; j < 10 ; j++) /* try locking 10 times */ @@ -1264,7 +1340,7 @@ static void *test_thread(void *arg) multi_locks[i]= &data[i]; data[i].type= tests[param][i].lock_type; } - thr_multi_lock(multi_locks,lock_counts[param]); + thr_multi_lock(multi_locks, lock_counts[param], &owner); pthread_mutex_lock(&LOCK_thread_count); { int tmp=rand() & 7; /* Do something from 0-2 sec */ diff --git a/ndb/include/kernel/NodeInfo.hpp b/ndb/include/kernel/NodeInfo.hpp index 5377f001949..622185323a3 100644 --- a/ndb/include/kernel/NodeInfo.hpp +++ b/ndb/include/kernel/NodeInfo.hpp @@ -41,6 +41,7 @@ public: Uint32 m_type; ///< Node type Uint32 m_connectCount; ///< No of times connected bool m_connected; ///< Node is connected + Uint32 m_heartbeat_cnt; ///< Missed heartbeats friend NdbOut & operator<<(NdbOut&, const NodeInfo&); }; @@ -52,6 +53,7 @@ NodeInfo::NodeInfo(){ m_signalVersion = 0; m_type = INVALID; m_connectCount = 0; + m_heartbeat_cnt= 0; } inline diff --git a/ndb/include/kernel/signaldata/AlterTable.hpp b/ndb/include/kernel/signaldata/AlterTable.hpp index 30f8727551d..173a9acf9ed 100644 --- a/ndb/include/kernel/signaldata/AlterTable.hpp +++ b/ndb/include/kernel/signaldata/AlterTable.hpp @@ -128,7 +128,8 @@ public: RecordTooBig = 738, InvalidPrimaryKeySize = 739, NullablePrimaryKey = 740, - UnsupportedChange = 741 + UnsupportedChange = 741, + BackupInProgress = 762 }; private: diff --git a/ndb/include/kernel/signaldata/DictTabInfo.hpp b/ndb/include/kernel/signaldata/DictTabInfo.hpp index 09b00cf8993..bc4817f0cf3 100644 --- a/ndb/include/kernel/signaldata/DictTabInfo.hpp +++ b/ndb/include/kernel/signaldata/DictTabInfo.hpp @@ -215,6 +215,7 @@ public: StateBuilding = 2, StateDropping = 3, StateOnline = 4, + StateBackup = 5, StateBroken = 9 }; diff --git a/ndb/include/kernel/signaldata/DropTable.hpp b/ndb/include/kernel/signaldata/DropTable.hpp index 7a5b96e4cd1..cae6aff8754 100644 --- a/ndb/include/kernel/signaldata/DropTable.hpp +++ b/ndb/include/kernel/signaldata/DropTable.hpp @@ -57,7 +57,8 @@ public: NoSuchTable = 709, InvalidTableVersion = 241, DropInProgress = 283, - NoDropTableRecordAvailable = 1229 + NoDropTableRecordAvailable = 1229, + BackupInProgress = 761 }; }; diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 018e554de7c..924d65c2847 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -139,6 +139,7 @@ * @{ */ +#include <stdio.h> #include <ndb_types.h> #include "ndb_logevent.h" #include "mgmapi_config_parameters.h" @@ -441,6 +442,12 @@ extern "C" { int ndb_mgm_get_latest_error_line(const NdbMgmHandle handle); #endif + /** + * Set error stream + */ + void ndb_mgm_set_error_stream(NdbMgmHandle, FILE *); + + /** @} *********************************************************************/ /** * @name Functions: Create/Destroy Management Server Handles diff --git a/ndb/include/mgmapi/mgmapi_config_parameters.h b/ndb/include/mgmapi/mgmapi_config_parameters.h index 33134899d1e..8f95e159b38 100644 --- a/ndb/include/mgmapi/mgmapi_config_parameters.h +++ b/ndb/include/mgmapi/mgmapi_config_parameters.h @@ -50,8 +50,11 @@ #define CFG_DB_FILESYSTEM_PATH 125 #define CFG_DB_NO_REDOLOG_FILES 126 -#define CFG_DB_DISC_BANDWIDTH 127 -#define CFG_DB_SR_DISC_BANDWITH 128 + +#define CFG_DB_LCP_DISC_PAGES_TUP 127 +#define CFG_DB_LCP_DISC_PAGES_TUP_SR 128 +#define CFG_DB_LCP_DISC_PAGES_ACC 137 +#define CFG_DB_LCP_DISC_PAGES_ACC_SR 138 #define CFG_DB_TRANSACTION_CHECK_INTERVAL 129 #define CFG_DB_TRANSACTION_INACTIVE_TIMEOUT 130 diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 86130be4c4b..6ae8aa16977 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -117,6 +117,7 @@ public: StateBuilding = 2, ///< Building, not yet usable StateDropping = 3, ///< Offlining or dropping, not usable StateOnline = 4, ///< Online, usable + StateBackup = 5, ///< Online, being backuped, usable StateBroken = 9 ///< Broken, should be dropped and re-created }; diff --git a/ndb/include/transporter/TransporterCallback.hpp b/ndb/include/transporter/TransporterCallback.hpp index 9f910f31728..f2432edd394 100644 --- a/ndb/include/transporter/TransporterCallback.hpp +++ b/ndb/include/transporter/TransporterCallback.hpp @@ -341,5 +341,8 @@ enum TransporterError { */ void reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode); + +void +transporter_recv_from(void* callbackObj, NodeId node); #endif diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index 60649665d4a..86bfa385c04 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -918,6 +918,7 @@ TransporterRegistry::performReceive() NodeId remoteNodeId; Uint32 * readPtr; Uint32 sz = theOSEReceiver->getReceiveData(&remoteNodeId, &readPtr); + transporter_recv_from(callbackObj, remoteNodeId); Uint32 szUsed = unpack(readPtr, sz, remoteNodeId, @@ -953,6 +954,7 @@ TransporterRegistry::performReceive() { Uint32 * ptr; Uint32 sz = t->getReceiveData(&ptr); + transporter_recv_from(callbackObj, nodeId); Uint32 szUsed = unpack(ptr, sz, nodeId, ioStates[nodeId]); t->updateReceiveDataPtr(szUsed); } @@ -976,6 +978,7 @@ TransporterRegistry::performReceive() { Uint32 * readPtr, * eodPtr; t->getReceivePtr(&readPtr, &eodPtr); + transporter_recv_from(callbackObj, nodeId); Uint32 *newPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]); t->updateReceivePtr(newPtr); } @@ -993,6 +996,7 @@ TransporterRegistry::performReceive() { Uint32 * readPtr, * eodPtr; t->getReceivePtr(&readPtr, &eodPtr); + transporter_recv_from(callbackObj, nodeId); Uint32 *newPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]); t->updateReceivePtr(newPtr); } diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index fedddb58c0d..1a72537a77e 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -4,9 +4,9 @@ Next NDBFS 2000 Next DBACC 3002 Next DBTUP 4013 Next DBLQH 5042 -Next DBDICT 6006 +Next DBDICT 6007 Next DBDIH 7174 -Next DBTC 8035 +Next DBTC 8037 Next CMVMI 9000 Next BACKUP 10022 Next DBUTIL 11002 @@ -408,10 +408,12 @@ Drop Table/Index: 4001: Crash on REL_TABMEMREQ in TUP 4002: Crash on DROP_TABFILEREQ in TUP 4003: Fail next trigger create in TUP +4004: Fail next trigger drop in TUP 8033: Fail next trigger create in TC 8034: Fail next index create in TC - - +8035: Fail next trigger drop in TC +8036: Fail next index drop in TC +6006: Crash participant in create index System Restart: --------------- diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 327fcc33aff..34545d4c7ff 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -921,7 +921,6 @@ Backup::execUTIL_SEQUENCE_REF(Signal* signal) jamEntry(); UtilSequenceRef * utilRef = (UtilSequenceRef*)signal->getDataPtr(); ptr.i = utilRef->senderData; - ndbrequire(ptr.i == RNIL); c_backupPool.getPtr(ptr); ndbrequire(ptr.p->masterData.gsn == GSN_UTIL_SEQUENCE_REQ); sendBackupRef(signal, ptr, BackupRef::SequenceFailure); @@ -2418,10 +2417,16 @@ Backup::execLIST_TABLES_CONF(Signal* signal) jam(); Uint32 tableId = ListTablesConf::getTableId(conf->tableData[i]); Uint32 tableType = ListTablesConf::getTableType(conf->tableData[i]); + Uint32 state= ListTablesConf::getTableState(conf->tableData[i]); if (!DictTabInfo::isTable(tableType) && !DictTabInfo::isIndex(tableType)){ jam(); continue; }//if + if (state != DictTabInfo::StateOnline) + { + jam(); + continue; + }//if TablePtr tabPtr; ptr.p->tables.seize(tabPtr); if(tabPtr.i == RNIL) { @@ -2791,10 +2796,19 @@ Backup::execGET_TABINFO_CONF(Signal* signal) TablePtr tmp = tabPtr; ptr.p->tables.next(tabPtr); - if(DictTabInfo::isIndex(tmp.p->tableType)){ + if(DictTabInfo::isIndex(tmp.p->tableType)) + { + jam(); ptr.p->tables.release(tmp); } - + else + { + jam(); + signal->theData[0] = tmp.p->tableId; + signal->theData[1] = 1; // lock + EXECUTE_DIRECT(DBDICT, GSN_BACKUP_FRAGMENT_REQ, signal, 2); + } + if(tabPtr.i == RNIL) { jam(); @@ -2844,8 +2858,6 @@ Backup::parseTableDescription(Signal* signal, BackupRecordPtr ptr, Uint32 len) /** * Initialize table object */ - tabPtr.p->frag_mask = RNIL; - tabPtr.p->schemaVersion = tmpTab.TableVersion; tabPtr.p->noOfAttributes = tmpTab.NoOfAttributes; tabPtr.p->noOfNull = 0; @@ -2938,7 +2950,6 @@ Backup::execDI_FCOUNTCONF(Signal* signal) ndbrequire(findTable(ptr, tabPtr, tableId)); ndbrequire(tabPtr.p->fragments.seize(fragCount) != false); - tabPtr.p->frag_mask = calculate_frag_mask(fragCount); for(Uint32 i = 0; i<fragCount; i++) { jam(); FragmentPtr fragPtr; @@ -3575,7 +3586,7 @@ Backup::backupFragmentRef(Signal * signal, BackupFilePtr filePtr) ref->backupId = ptr.p->backupId; ref->backupPtr = ptr.i; ref->nodeId = getOwnNodeId(); - ref->errorCode = ptr.p->errorCode; + ref->errorCode = filePtr.p->errorCode; sendSignal(ptr.p->masterRef, GSN_BACKUP_FRAGMENT_REF, signal, BackupFragmentRef::SignalLength, JBB); } @@ -3755,15 +3766,6 @@ Backup::checkFile(Signal* signal, BackupFilePtr filePtr) * Slave functionallity: Perform logging * ****************************************************************************/ -Uint32 -Backup::calculate_frag_mask(Uint32 count) -{ - Uint32 mask = 1; - while (mask < count) mask <<= 1; - mask -= 1; - return mask; -} - void Backup::execBACKUP_TRIG_REQ(Signal* signal) { @@ -3780,14 +3782,6 @@ Backup::execBACKUP_TRIG_REQ(Signal* signal) jamEntry(); c_triggerPool.getPtr(trigPtr, trigger_id); c_tablePool.getPtr(tabPtr, trigPtr.p->tab_ptr_i); - frag_id = frag_id & tabPtr.p->frag_mask; - /* - At the moment the fragment identity known by TUP is the - actual fragment id but with possibly an extra bit set. - This is due to that ACC splits the fragment. Thus fragment id 5 can - here be either 5 or 13. Thus masking with 2 ** n - 1 where number of - fragments <= 2 ** n will always provide a correct fragment id. - */ tabPtr.p->fragments.getPtr(fragPtr, frag_id); if (fragPtr.p->node != getOwnNodeId()) { jam(); @@ -3836,6 +3830,8 @@ Backup::execTRIG_ATTRINFO(Signal* signal) { !buf.getWritePtr(&dst, trigPtr.p->maxRecordSize)) { jam(); + Uint32 save[TrigAttrInfo::StaticLength]; + memcpy(save, signal->getDataPtr(), 4*TrigAttrInfo::StaticLength); BackupRecordPtr ptr; c_backupPool.getPtr(ptr, trigPtr.p->backupPtr); trigPtr.p->errorCode = AbortBackupOrd::LogBufferFull; @@ -3846,6 +3842,8 @@ Backup::execTRIG_ATTRINFO(Signal* signal) { ord->senderData= ptr.i; sendSignal(ptr.p->masterRef, GSN_ABORT_BACKUP_ORD, signal, AbortBackupOrd::SignalLength, JBB); + + memcpy(signal->getDataPtrSend(), save, 4*TrigAttrInfo::StaticLength); return; }//if @@ -3995,6 +3993,17 @@ Backup::execSTOP_BACKUP_REQ(Signal* signal) gcp->StopGCP = htonl(stopGCP - 1); filePtr.p->operation.dataBuffer.updateWritePtr(gcpSz); } + + { + TablePtr tabPtr; + for(ptr.p->tables.first(tabPtr); tabPtr.i != RNIL; + ptr.p->tables.next(tabPtr)) + { + signal->theData[0] = tabPtr.p->tableId; + signal->theData[1] = 0; // unlock + EXECUTE_DIRECT(DBDICT, GSN_BACKUP_FRAGMENT_REQ, signal, 2); + } + } closeFiles(signal, ptr); } @@ -4338,6 +4347,11 @@ Backup::cleanup(Signal* signal, BackupRecordPtr ptr) }//if tabPtr.p->triggerIds[j] = ILLEGAL_TRIGGER_ID; }//for + { + signal->theData[0] = tabPtr.p->tableId; + signal->theData[1] = 0; // unlock + EXECUTE_DIRECT(DBDICT, GSN_BACKUP_FRAGMENT_REQ, signal, 2); + } }//for BackupFilePtr filePtr; @@ -4354,9 +4368,6 @@ Backup::cleanup(Signal* signal, BackupRecordPtr ptr) ptr.p->files.release(); ptr.p->tables.release(); ptr.p->triggers.release(); - - ptr.p->tables.release(); - ptr.p->triggers.release(); ptr.p->pages.release(); ptr.p->backupId = ~0; diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index 7bcea5655b4..ab2bec7dad7 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -195,7 +195,6 @@ public: Uint32 tableId; Uint32 schemaVersion; - Uint32 frag_mask; Uint32 tableType; Uint32 noOfNull; Uint32 noOfAttributes; @@ -526,8 +525,6 @@ public: ArrayPool<Node> c_nodePool; ArrayPool<TriggerRecord> c_triggerPool; - Uint32 calculate_frag_mask(Uint32); - void checkFile(Signal*, BackupFilePtr); void checkScan(Signal*, BackupFilePtr); void fragmentCompleted(Signal*, BackupFilePtr); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index 24f9715c8b4..aefd2612151 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -731,10 +731,12 @@ void Dbacc::execREAD_CONFIG_REQ(Signal* signal) ndbrestart1Lab(signal); clblPagesPerTick = 50; - //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTick); + ndb_mgm_get_int_parameter(p, CFG_DB_LCP_DISC_PAGES_ACC_SR, + &clblPagesPerTick); clblPagesPerTickAfterSr = 50; - //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTickAfterSr); + ndb_mgm_get_int_parameter(p, CFG_DB_LCP_DISC_PAGES_ACC, + &clblPagesPerTickAfterSr); tdata0 = 0; initialiseRecordsLab(signal, ref, senderData); @@ -4845,7 +4847,24 @@ Uint32 Dbacc::executeNextOperation(Signal* signal) sendSignal(operationRecPtr.p->userblockref, GSN_ACCKEYREF, signal, 2, JBB); return operationRecPtr.p->elementIsDisappeared; }//if - }//if + } + else if(operationRecPtr.p->operation == ZWRITE) + { + jam(); + operationRecPtr.p->operation = ZUPDATE; + if (operationRecPtr.p->prevParallelQue != RNIL) { + OperationrecPtr prevOpPtr; + jam(); + prevOpPtr.i = operationRecPtr.p->prevParallelQue; + ptrCheckGuard(prevOpPtr, coprecsize, operationrec); + if (prevOpPtr.p->operation == ZDELETE) + { + jam(); + operationRecPtr.p->operation = ZINSERT; + } + } + } + if (operationRecPtr.p->operation == ZSCAN_OP && ! operationRecPtr.p->isAccLockReq) { jam(); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index d51f9537154..db4842a8789 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -1331,6 +1331,8 @@ Dbdict::Dbdict(const class Configuration & conf): addRecSignal(GSN_DROP_TAB_REQ, &Dbdict::execDROP_TAB_REQ); addRecSignal(GSN_DROP_TAB_REF, &Dbdict::execDROP_TAB_REF); addRecSignal(GSN_DROP_TAB_CONF, &Dbdict::execDROP_TAB_CONF); + + addRecSignal(GSN_BACKUP_FRAGMENT_REQ, &Dbdict::execBACKUP_FRAGMENT_REQ); }//Dbdict::Dbdict() Dbdict::~Dbdict() @@ -1486,7 +1488,6 @@ void Dbdict::initialiseTableRecord(TableRecordPtr tablePtr) tablePtr.p->tableVersion = (Uint32)-1; tablePtr.p->tabState = TableRecord::NOT_DEFINED; tablePtr.p->tabReturnState = TableRecord::TRS_IDLE; - tablePtr.p->myConnect = RNIL; tablePtr.p->fragmentType = DictTabInfo::AllNodesSmallTable; memset(tablePtr.p->tableName, 0, sizeof(tablePtr.p->tableName)); tablePtr.p->gciTableCreated = 0; @@ -2961,6 +2962,27 @@ Dbdict::execCREATE_TABLE_REQ(Signal* signal){ } void +Dbdict::execBACKUP_FRAGMENT_REQ(Signal* signal) +{ + jamEntry(); + Uint32 tableId = signal->theData[0]; + Uint32 lock = signal->theData[1]; + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, tableId, true); + + if(lock) + { + ndbrequire(tablePtr.p->tabState == TableRecord::DEFINED); + tablePtr.p->tabState = TableRecord::BACKUP_ONGOING; + } + else if(tablePtr.p->tabState == TableRecord::BACKUP_ONGOING) + { + tablePtr.p->tabState = TableRecord::DEFINED; + } +} + +void Dbdict::execALTER_TABLE_REQ(Signal* signal) { // Received by master @@ -3011,6 +3033,10 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) ok = true; jam(); break; + case TableRecord::BACKUP_ONGOING: + jam(); + alterTableRef(signal, req, AlterTableRef::BackupInProgress); + return; case TableRecord::PREPARE_DROPPING: case TableRecord::DROPPING: jam(); @@ -3030,7 +3056,6 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) CreateTableRecordPtr alterTabPtr; // Reuse create table records c_opCreateTable.seize(alterTabPtr); - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; if(alterTabPtr.isNull()){ jam(); @@ -3038,7 +3063,7 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) return; } - regAlterTabPtr->m_changeMask = changeMask; + alterTabPtr.p->m_changeMask = changeMask; parseRecord.requestType = DictTabInfo::AlterTableFromAPI; parseRecord.errorCode = 0; @@ -3058,20 +3083,18 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) } releaseSections(signal); - regAlterTabPtr->key = ++c_opRecordSequence; + alterTabPtr.p->key = ++c_opRecordSequence; c_opCreateTable.add(alterTabPtr); - ndbrequire(c_opCreateTable.find(alterTabPtr, regAlterTabPtr->key)); - regAlterTabPtr->m_errorCode = 0; - regAlterTabPtr->m_senderRef = senderRef; - regAlterTabPtr->m_senderData = senderData; - regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i; - regAlterTabPtr->m_alterTableFailed = false; - regAlterTabPtr->m_coordinatorRef = reference(); - regAlterTabPtr->m_fragmentsPtrI = RNIL; - regAlterTabPtr->m_dihAddFragPtr = RNIL; - - // Alter table on all nodes - c_blockState = BS_BUSY; + ndbrequire(c_opCreateTable.find(alterTabPtr, alterTabPtr.p->key)); + alterTabPtr.p->m_errorCode = 0; + alterTabPtr.p->m_senderRef = senderRef; + alterTabPtr.p->m_senderData = senderData; + alterTabPtr.p->m_tablePtrI = parseRecord.tablePtr.i; + alterTabPtr.p->m_alterTableFailed = false; + alterTabPtr.p->m_coordinatorRef = reference(); + alterTabPtr.p->m_fragmentsPtrI = RNIL; + alterTabPtr.p->m_dihAddFragPtr = RNIL; + alterTabPtr.p->m_alterTableId = tablePtr.p->tableId; // Send prepare request to all alive nodes SimplePropertiesSectionWriter w(getSectionSegmentPool()); @@ -3079,27 +3102,78 @@ Dbdict::execALTER_TABLE_REQ(Signal* signal) SegmentedSectionPtr tabInfoPtr; w.getPtr(tabInfoPtr); + + alterTabPtr.p->m_tabInfoPtrI = tabInfoPtr.i; + + // Alter table on all nodes + c_blockState = BS_BUSY; + + Mutex mutex(signal, c_mutexMgr, alterTabPtr.p->m_startLcpMutex); + Callback c = { safe_cast(&Dbdict::alterTable_backup_mutex_locked), + alterTabPtr.p->key }; + + ndbrequire(mutex.lock(c)); +} + +void +Dbdict::alterTable_backup_mutex_locked(Signal* signal, + Uint32 callbackData, + Uint32 retValue) +{ + jamEntry(); + + ndbrequire(retValue == 0); + + CreateTableRecordPtr alterTabPtr; + ndbrequire(c_opCreateTable.find(alterTabPtr, callbackData)); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, alterTabPtr.p->m_alterTableId, true); + + Mutex mutex(signal, c_mutexMgr, alterTabPtr.p->m_startLcpMutex); + mutex.unlock(); // ignore response + + SegmentedSectionPtr tabInfoPtr; + getSection(tabInfoPtr, alterTabPtr.p->m_tabInfoPtrI); signal->setSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO); + alterTabPtr.p->m_tabInfoPtrI = RNIL; + + if(tablePtr.p->tabState == TableRecord::BACKUP_ONGOING) + { + jam(); + AlterTableReq* req = (AlterTableReq*)signal->getDataPtr(); + req->senderData = alterTabPtr.p->m_senderData; + req->senderRef = alterTabPtr.p->m_senderRef; + alterTableRef(signal, req, AlterTableRef::BackupInProgress); + + c_tableRecordPool.getPtr(tablePtr, alterTabPtr.p->m_tablePtrI); + releaseTableObject(tablePtr.i, false); + + c_opCreateTable.release(alterTabPtr); + c_blockState = BS_IDLE; + return; + } + NodeReceiverGroup rg(DBDICT, c_aliveNodes); - regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; - SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); - safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + alterTabPtr.p->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + SafeCounter safeCounter(c_counterMgr, + alterTabPtr.p->m_coordinatorData.m_counter); + safeCounter.init<AlterTabRef>(rg, alterTabPtr.p->key); AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); lreq->senderRef = reference(); - lreq->senderData = regAlterTabPtr->key; - lreq->clientRef = regAlterTabPtr->m_senderRef; - lreq->clientData = regAlterTabPtr->m_senderData; - lreq->changeMask = changeMask; - lreq->tableId = tableId; - lreq->tableVersion = tableVersion + 1; + lreq->senderData = alterTabPtr.p->key; + lreq->clientRef = alterTabPtr.p->m_senderRef; + lreq->clientData = alterTabPtr.p->m_senderData; + lreq->changeMask = alterTabPtr.p->m_changeMask; + lreq->tableId = tablePtr.p->tableId; + lreq->tableVersion = tablePtr.p->tableVersion + 1; lreq->gci = tablePtr.p->gciTableCreated; lreq->requestType = AlterTabReq::AlterTablePrepare; sendSignal(rg, GSN_ALTER_TAB_REQ, signal, AlterTabReq::SignalLength, JBB); - } void Dbdict::alterTableRef(Signal * signal, @@ -3174,9 +3248,8 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) alterTabRef(signal, req, AlterTableRef::Busy); return; } - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; - regAlterTabPtr->m_alterTableId = tableId; - regAlterTabPtr->m_coordinatorRef = senderRef; + alterTabPtr.p->m_alterTableId = tableId; + alterTabPtr.p->m_coordinatorRef = senderRef; // Get table definition TableRecordPtr tablePtr; @@ -3210,6 +3283,10 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) jam(); alterTabRef(signal, req, AlterTableRef::DropInProgress); return; + case TableRecord::BACKUP_ONGOING: + jam(); + alterTabRef(signal, req, AlterTableRef::BackupInProgress); + return; } ndbrequire(ok); @@ -3240,23 +3317,23 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) aParseRecord); return; } - regAlterTabPtr->key = senderData; + alterTabPtr.p->key = senderData; c_opCreateTable.add(alterTabPtr); - regAlterTabPtr->m_errorCode = 0; - regAlterTabPtr->m_senderRef = senderRef; - regAlterTabPtr->m_senderData = senderData; - regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i; - regAlterTabPtr->m_fragmentsPtrI = RNIL; - regAlterTabPtr->m_dihAddFragPtr = RNIL; + alterTabPtr.p->m_errorCode = 0; + alterTabPtr.p->m_senderRef = senderRef; + alterTabPtr.p->m_senderData = senderData; + alterTabPtr.p->m_tablePtrI = parseRecord.tablePtr.i; + alterTabPtr.p->m_fragmentsPtrI = RNIL; + alterTabPtr.p->m_dihAddFragPtr = RNIL; newTablePtr = parseRecord.tablePtr; newTablePtr.p->tableVersion = tableVersion; } else { // (req->senderRef == reference()) jam(); - c_tableRecordPool.getPtr(newTablePtr, regAlterTabPtr->m_tablePtrI); + c_tableRecordPool.getPtr(newTablePtr, alterTabPtr.p->m_tablePtrI); newTablePtr.p->tableVersion = tableVersion; } - if (handleAlterTab(req, regAlterTabPtr, tablePtr, newTablePtr) == -1) { + if (handleAlterTab(req, alterTabPtr.p, tablePtr, newTablePtr) == -1) { jam(); c_opCreateTable.release(alterTabPtr); alterTabRef(signal, req, AlterTableRef::UnsupportedChange); @@ -3281,7 +3358,7 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) // Write schema for altered table to disk SegmentedSectionPtr tabInfoPtr; signal->getSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO); - regAlterTabPtr->m_tabInfoPtrI = tabInfoPtr.i; + alterTabPtr.p->m_tabInfoPtrI = tabInfoPtr.i; signal->header.m_noOfSections = 0; @@ -3309,7 +3386,7 @@ Dbdict::execALTER_TAB_REQ(Signal * signal) case(AlterTabReq::AlterTableRevert): { jam(); // Revert failed alter table - revertAlterTable(signal, changeMask, tableId, regAlterTabPtr); + revertAlterTable(signal, changeMask, tableId, alterTabPtr.p); // Acknowledge the reverted alter table AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); conf->senderRef = reference(); @@ -3373,9 +3450,8 @@ void Dbdict::execALTER_TAB_REF(Signal * signal){ (AlterTabReq::RequestType) ref->requestType; CreateTableRecordPtr alterTabPtr; ndbrequire(c_opCreateTable.find(alterTabPtr, senderData)); - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; - Uint32 changeMask = regAlterTabPtr->m_changeMask; - SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + Uint32 changeMask = alterTabPtr.p->m_changeMask; + SafeCounter safeCounter(c_counterMgr, alterTabPtr.p->m_coordinatorData.m_counter); safeCounter.clearWaitingFor(refToNode(senderRef)); switch (requestType) { case(AlterTabReq::AlterTablePrepare): { @@ -3383,7 +3459,7 @@ void Dbdict::execALTER_TAB_REF(Signal * signal){ jam(); // Send revert request to all alive nodes TableRecordPtr tablePtr; - c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId); + c_tableRecordPool.getPtr(tablePtr, alterTabPtr.p->m_alterTableId); Uint32 tableId = tablePtr.p->tableId; Uint32 tableVersion = tablePtr.p->tableVersion; Uint32 gci = tablePtr.p->gciTableCreated; @@ -3394,14 +3470,14 @@ void Dbdict::execALTER_TAB_REF(Signal * signal){ signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); NodeReceiverGroup rg(DBDICT, c_aliveNodes); - regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; - safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + alterTabPtr.p->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, alterTabPtr.p->key); AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); lreq->senderRef = reference(); - lreq->senderData = regAlterTabPtr->key; - lreq->clientRef = regAlterTabPtr->m_senderRef; - lreq->clientData = regAlterTabPtr->m_senderData; + lreq->senderData = alterTabPtr.p->key; + lreq->clientRef = alterTabPtr.p->m_senderRef; + lreq->clientData = alterTabPtr.p->m_senderData; lreq->changeMask = changeMask; lreq->tableId = tableId; lreq->tableVersion = tableVersion; @@ -3413,7 +3489,7 @@ void Dbdict::execALTER_TAB_REF(Signal * signal){ } else { jam(); - regAlterTabPtr->m_alterTableFailed = true; + alterTabPtr.p->m_alterTableFailed = true; } break; } @@ -3437,8 +3513,8 @@ void Dbdict::execALTER_TAB_REF(Signal * signal){ } else { jam(); - regAlterTabPtr->m_alterTableFailed = true; - regAlterTabPtr->m_alterTableRef = *apiRef; + alterTabPtr.p->m_alterTableFailed = true; + alterTabPtr.p->m_alterTableRef = *apiRef; } break; } @@ -3460,7 +3536,6 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ (AlterTabReq::RequestType) conf->requestType; CreateTableRecordPtr alterTabPtr; ndbrequire(c_opCreateTable.find(alterTabPtr, senderData)); - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; switch (requestType) { case(AlterTabReq::AlterTablePrepare): { @@ -3504,23 +3579,23 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ conf->tableVersion = tableVersion; conf->gci = gci; conf->requestType = requestType; - sendSignal(regAlterTabPtr->m_coordinatorRef, GSN_ALTER_TAB_CONF, signal, + sendSignal(alterTabPtr.p->m_coordinatorRef, GSN_ALTER_TAB_CONF, signal, AlterTabConf::SignalLength, JBB); return; } default :break; } // Coordinator only - SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + SafeCounter safeCounter(c_counterMgr, alterTabPtr.p->m_coordinatorData.m_counter); safeCounter.clearWaitingFor(refToNode(senderRef)); if (safeCounter.done()) { jam(); // We have received all local confirmations - if (regAlterTabPtr->m_alterTableFailed) { + if (alterTabPtr.p->m_alterTableFailed) { jam(); // Send revert request to all alive nodes TableRecordPtr tablePtr; - c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId); + c_tableRecordPool.getPtr(tablePtr, alterTabPtr.p->m_alterTableId); Uint32 tableId = tablePtr.p->tableId; Uint32 tableVersion = tablePtr.p->tableVersion; Uint32 gci = tablePtr.p->gciTableCreated; @@ -3531,14 +3606,14 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); NodeReceiverGroup rg(DBDICT, c_aliveNodes); - regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; - safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + alterTabPtr.p->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, alterTabPtr.p->key); AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); lreq->senderRef = reference(); - lreq->senderData = regAlterTabPtr->key; - lreq->clientRef = regAlterTabPtr->m_senderRef; - lreq->clientData = regAlterTabPtr->m_senderData; + lreq->senderData = alterTabPtr.p->key; + lreq->clientRef = alterTabPtr.p->m_senderRef; + lreq->clientData = alterTabPtr.p->m_senderData; lreq->changeMask = changeMask; lreq->tableId = tableId; lreq->tableVersion = tableVersion; @@ -3560,14 +3635,14 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO); NodeReceiverGroup rg(DBDICT, c_aliveNodes); - regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; - safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key); + alterTabPtr.p->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ; + safeCounter.init<AlterTabRef>(rg, alterTabPtr.p->key); AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend(); lreq->senderRef = reference(); - lreq->senderData = regAlterTabPtr->key; - lreq->clientRef = regAlterTabPtr->m_senderRef; - lreq->clientData = regAlterTabPtr->m_senderData; + lreq->senderData = alterTabPtr.p->key; + lreq->clientRef = alterTabPtr.p->m_senderRef; + lreq->clientData = alterTabPtr.p->m_senderData; lreq->changeMask = changeMask; lreq->tableId = tableId; lreq->tableVersion = tableVersion; @@ -3587,18 +3662,18 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ case(AlterTabReq::AlterTableRevert): jam(); case(AlterTabReq::AlterTableCommit): { - SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter); + SafeCounter safeCounter(c_counterMgr, alterTabPtr.p->m_coordinatorData.m_counter); safeCounter.clearWaitingFor(refToNode(senderRef)); if (safeCounter.done()) { jam(); // We have received all local confirmations releaseSections(signal); - if (regAlterTabPtr->m_alterTableFailed) { + if (alterTabPtr.p->m_alterTableFailed) { jam(); AlterTableRef * apiRef = (AlterTableRef*)signal->getDataPtrSend(); - *apiRef = regAlterTabPtr->m_alterTableRef; - sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_REF, signal, + *apiRef = alterTabPtr.p->m_alterTableRef; + sendSignal(alterTabPtr.p->m_senderRef, GSN_ALTER_TABLE_REF, signal, AlterTableRef::SignalLength, JBB); } else { @@ -3607,18 +3682,18 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ AlterTableConf * const apiConf = (AlterTableConf*)signal->getDataPtrSend(); apiConf->senderRef = reference(); - apiConf->senderData = regAlterTabPtr->m_senderData; + apiConf->senderData = alterTabPtr.p->m_senderData; apiConf->tableId = tableId; apiConf->tableVersion = tableVersion; //@todo check api failed - sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_CONF, signal, + sendSignal(alterTabPtr.p->m_senderRef, GSN_ALTER_TABLE_CONF, signal, AlterTableConf::SignalLength, JBB); } // Release resources TableRecordPtr tabPtr; - c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI); + c_tableRecordPool.getPtr(tabPtr, alterTabPtr.p->m_tablePtrI); releaseTableObject(tabPtr.i, false); c_opCreateTable.release(alterTabPtr); c_blockState = BS_IDLE; @@ -3649,7 +3724,7 @@ void Dbdict::printTables() } int Dbdict::handleAlterTab(AlterTabReq * req, - CreateTableRecord * regAlterTabPtr, + CreateTableRecord * alterTabPtrP, TableRecordPtr origTablePtr, TableRecordPtr newTablePtr) { @@ -3664,7 +3739,7 @@ int Dbdict::handleAlterTab(AlterTabReq * req, ndbrequire(c_tableRecordHash.find(tmp, *origTablePtr.p)); #endif c_tableRecordHash.remove(origTablePtr); - strcpy(regAlterTabPtr->previousTableName, origTablePtr.p->tableName); + strcpy(alterTabPtrP->previousTableName, origTablePtr.p->tableName); strcpy(origTablePtr.p->tableName, newTablePtr.p->tableName); // Set new schema version origTablePtr.p->tableVersion = newTablePtr.p->tableVersion; @@ -3683,7 +3758,7 @@ int Dbdict::handleAlterTab(AlterTabReq * req, void Dbdict::revertAlterTable(Signal * signal, Uint32 changeMask, Uint32 tableId, - CreateTableRecord * regAlterTabPtr) + CreateTableRecord * alterTabPtrP) { if (AlterTableReq::getNameFlag(changeMask)) { jam(); @@ -3698,7 +3773,7 @@ void Dbdict::revertAlterTable(Signal * signal, #endif c_tableRecordHash.remove(tablePtr); // Restore name - strcpy(tablePtr.p->tableName, regAlterTabPtr->previousTableName); + strcpy(tablePtr.p->tableName, alterTabPtrP->previousTableName); // Revert schema version tablePtr.p->tableVersion = tablePtr.p->tableVersion - 1; // Put it back @@ -3722,16 +3797,15 @@ Dbdict::alterTab_writeSchemaConf(Signal* signal, Uint32 key = callbackData; CreateTableRecordPtr alterTabPtr; ndbrequire(c_opCreateTable.find(alterTabPtr, key)); - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; - Uint32 tableId = regAlterTabPtr->m_alterTableId; + Uint32 tableId = alterTabPtr.p->m_alterTableId; Callback callback; - callback.m_callbackData = regAlterTabPtr->key; + callback.m_callbackData = alterTabPtr.p->key; callback.m_callbackFunction = safe_cast(&Dbdict::alterTab_writeTableConf); SegmentedSectionPtr tabInfoPtr; - getSection(tabInfoPtr, regAlterTabPtr->m_tabInfoPtrI); + getSection(tabInfoPtr, alterTabPtr.p->m_tabInfoPtrI); writeTableFile(signal, tableId, tabInfoPtr, &callback); @@ -3747,10 +3821,9 @@ Dbdict::alterTab_writeTableConf(Signal* signal, jam(); CreateTableRecordPtr alterTabPtr; ndbrequire(c_opCreateTable.find(alterTabPtr, callbackData)); - CreateTableRecord * regAlterTabPtr = alterTabPtr.p; - Uint32 coordinatorRef = regAlterTabPtr->m_coordinatorRef; + Uint32 coordinatorRef = alterTabPtr.p->m_coordinatorRef; TableRecordPtr tabPtr; - c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_alterTableId); + c_tableRecordPool.getPtr(tabPtr, alterTabPtr.p->m_alterTableId); // Alter table commit request handled successfully AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend(); @@ -3765,7 +3838,7 @@ Dbdict::alterTab_writeTableConf(Signal* signal, if(coordinatorRef != reference()) { jam(); // Release resources - c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI); + c_tableRecordPool.getPtr(tabPtr, alterTabPtr.p->m_tablePtrI); releaseTableObject(tabPtr.i, false); c_opCreateTable.release(alterTabPtr); c_blockState = BS_IDLE; @@ -5220,6 +5293,10 @@ Dbdict::execDROP_TABLE_REQ(Signal* signal){ jam(); dropTableRef(signal, req, DropTableRef::DropInProgress); return; + case TableRecord::BACKUP_ONGOING: + jam(); + dropTableRef(signal, req, DropTableRef::BackupInProgress); + return; } ndbrequire(ok); @@ -5246,15 +5323,53 @@ Dbdict::execDROP_TABLE_REQ(Signal* signal){ dropTabPtr.p->key = ++c_opRecordSequence; c_opDropTable.add(dropTabPtr); - tablePtr.p->tabState = TableRecord::PREPARE_DROPPING; - dropTabPtr.p->m_request = * req; dropTabPtr.p->m_errorCode = 0; dropTabPtr.p->m_requestType = DropTabReq::OnlineDropTab; dropTabPtr.p->m_coordinatorRef = reference(); dropTabPtr.p->m_coordinatorData.m_gsn = GSN_PREP_DROP_TAB_REQ; dropTabPtr.p->m_coordinatorData.m_block = 0; - prepDropTab_nextStep(signal, dropTabPtr); + + Mutex mutex(signal, c_mutexMgr, dropTabPtr.p->m_define_backup_mutex); + Callback c = { safe_cast(&Dbdict::dropTable_backup_mutex_locked), + dropTabPtr.p->key}; + + ndbrequire(mutex.lock(c)); + +} + +void +Dbdict::dropTable_backup_mutex_locked(Signal* signal, + Uint32 callbackData, + Uint32 retValue){ + jamEntry(); + + ndbrequire(retValue == 0); + + DropTableRecordPtr dropTabPtr; + ndbrequire(c_opDropTable.find(dropTabPtr, callbackData)); + + TableRecordPtr tablePtr; + c_tableRecordPool.getPtr(tablePtr, dropTabPtr.p->m_request.tableId, true); + + Mutex mutex(signal, c_mutexMgr, dropTabPtr.p->m_define_backup_mutex); + mutex.unlock(); // ignore response + + if(tablePtr.p->tabState == TableRecord::BACKUP_ONGOING) + { + jam(); + dropTableRef(signal, &dropTabPtr.p->m_request, + DropTableRef::BackupInProgress); + + c_blockState = BS_IDLE; + c_opDropTable.release(dropTabPtr); + } + else + { + jam(); + tablePtr.p->tabState = TableRecord::PREPARE_DROPPING; + prepDropTab_nextStep(signal, dropTabPtr); + } } void @@ -5974,7 +6089,8 @@ void Dbdict::execGET_TABINFOREQ(Signal* signal) return; }//if - if (tablePtr.p->tabState != TableRecord::DEFINED) { + if (! (tablePtr.p->tabState == TableRecord::DEFINED || + tablePtr.p->tabState == TableRecord::BACKUP_ONGOING)) { jam(); sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined); return; @@ -6110,6 +6226,9 @@ Dbdict::execLIST_TABLES_REQ(Signal* signal) case TableRecord::DEFINED: conf->setTableState(pos, DictTabInfo::StateOnline); break; + case TableRecord::BACKUP_ONGOING: + conf->setTableState(pos, DictTabInfo::StateBackup); + break; default: conf->setTableState(pos, DictTabInfo::StateBroken); break; @@ -6468,6 +6587,9 @@ void Dbdict::createIndex_slavePrepare(Signal* signal, OpCreateIndexPtr opPtr) { jam(); + if (ERROR_INSERTED(6006) && ! opPtr.p->m_isMaster) { + ndbrequire(false); + } } void @@ -6490,7 +6612,8 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr) } TableRecordPtr tablePtr; c_tableRecordPool.getPtr(tablePtr, req->getTableId()); - if (tablePtr.p->tabState != TableRecord::DEFINED) { + if (tablePtr.p->tabState != TableRecord::DEFINED && + tablePtr.p->tabState != TableRecord::BACKUP_ONGOING) { jam(); opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable; opPtr.p->m_errorLine = __LINE__; @@ -6781,14 +6904,16 @@ Dbdict::createIndex_sendReply(Signal* signal, OpCreateIndexPtr opPtr, CreateIndxRef* rep = (CreateIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_CREATE_INDX_CONF; Uint32 length = CreateIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == CreateIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -6857,11 +6982,8 @@ Dbdict::execDROP_INDX_REQ(Signal* signal) goto error; } - if (tmp.p->indexState == TableRecord::IS_DROPPING){ - jam(); - err = DropIndxRef::IndexNotFound; - goto error; - } + if (tmp.p->indexState != TableRecord::IS_ONLINE) + req->addRequestFlag(RequestFlag::RF_FORCE); tmp.p->indexState = TableRecord::IS_DROPPING; @@ -7124,14 +7246,16 @@ Dbdict::dropIndex_sendReply(Signal* signal, OpDropIndexPtr opPtr, DropIndxRef* rep = (DropIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_DROP_INDX_CONF; Uint32 length = DropIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == DropIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -9648,7 +9772,7 @@ Dbdict::alterIndex_fromCreateTc(Signal* signal, OpAlterIndexPtr opPtr) { jam(); // mark created in local TC - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); indexPtr.p->indexLocal |= TableRecord::IL_CREATED_TC; @@ -9664,9 +9788,10 @@ Dbdict::alterIndex_toDropTc(Signal* signal, OpAlterIndexPtr opPtr) jam(); TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); - // broken index + // broken index allowed if force if (! (indexPtr.p->indexLocal & TableRecord::IL_CREATED_TC)) { jam(); + ndbassert(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterIndex_sendReply(signal, opPtr, false); return; } @@ -9688,8 +9813,8 @@ Dbdict::alterIndex_fromDropTc(Signal* signal, OpAlterIndexPtr opPtr) { jam(); ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC); - if (! opPtr.p->hasError()) { - // mark dropped in local TC + // mark dropped locally + if (! opPtr.p->hasLastError()) { TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); indexPtr.p->indexLocal &= ~TableRecord::IL_CREATED_TC; @@ -9827,51 +9952,46 @@ Dbdict::alterIndex_toDropTrigger(Signal* signal, OpAlterIndexPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); req->setRequestType(DropTrigReq::RT_ALTER_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); req->setTableId(opPtr.p->m_request.getTableId()); req->setIndexId(opPtr.p->m_request.getIndexId()); req->setTriggerInfo(0); // not used opPtr.p->m_triggerCounter = 0; - // insert - if (indexPtr.p->insertTriggerId != RNIL) { + if (indexPtr.p->isHashIndex()) { + // insert req->setTriggerId(indexPtr.p->insertTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; - } - // update - if (indexPtr.p->updateTriggerId != RNIL) { + // update req->setTriggerId(indexPtr.p->updateTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; - } - // delete - if (indexPtr.p->deleteTriggerId != RNIL) { + // delete req->setTriggerId(indexPtr.p->deleteTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; + // build + if (indexPtr.p->buildTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->buildTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + return; } - // custom - if (indexPtr.p->customTriggerId != RNIL) { + if (indexPtr.p->isOrderedIndex()) { + // custom + req->addRequestFlag(RequestFlag::RF_NOTCTRIGGER); req->setTriggerId(indexPtr.p->customTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; + return; } - // build - if (indexPtr.p->buildTriggerId != RNIL) { - req->setTriggerId(indexPtr.p->buildTriggerId); - sendSignal(reference(), GSN_DROP_TRIG_REQ, - signal, DropTrigReq::SignalLength, JBB); - opPtr.p->m_triggerCounter++; - } - if (opPtr.p->m_triggerCounter == 0) { - // drop in each TC - jam(); - opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC; - alterIndex_sendSlaveReq(signal, opPtr); - } + ndbrequire(false); } void @@ -9989,14 +10109,16 @@ Dbdict::alterIndex_sendReply(Signal* signal, OpAlterIndexPtr opPtr, AlterIndxRef* rep = (AlterIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_ALTER_INDX_CONF; Uint32 length = AlterIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == AlterIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -10409,8 +10531,10 @@ Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + jam(); req->setRequestType(AlterIndxReq::RT_TC); } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); req->setRequestType(AlterIndxReq::RT_TUX); } else { ndbrequire(false); @@ -10421,8 +10545,10 @@ Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr) req->setOnline(true); BlockReference blockRef = 0; if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); blockRef = calcTuxBlockRef(getOwnNodeId()); } else { ndbrequire(false); @@ -10449,15 +10575,14 @@ Dbdict::buildIndex_sendSlaveReq(Signal* signal, OpBuildIndexPtr opPtr) req->setConnectionPtr(opPtr.p->key); req->setRequestType(opPtr.p->m_requestType); req->addRequestFlag(opPtr.p->m_requestFlag); - if(opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) - { + if(opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + jam(); opPtr.p->m_signalCounter.clearWaitingFor(); opPtr.p->m_signalCounter.setWaitingFor(getOwnNodeId()); sendSignal(reference(), GSN_BUILDINDXREQ, signal, BuildIndxReq::SignalLength, JBB); - } - else - { + } else { + jam(); opPtr.p->m_signalCounter = c_aliveNodes; NodeReceiverGroup rg(DBDICT, c_aliveNodes); sendSignal(rg, GSN_BUILDINDXREQ, @@ -10472,14 +10597,16 @@ Dbdict::buildIndex_sendReply(Signal* signal, OpBuildIndexPtr opPtr, BuildIndxRef* rep = (BuildIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_BUILDINDXCONF; Uint32 length = BuildIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -10795,7 +10922,8 @@ Dbdict::createTrigger_slavePrepare(Signal* signal, OpCreateTriggerPtr opPtr) } TableRecordPtr tablePtr; c_tableRecordPool.getPtr(tablePtr, tableId); - if (tablePtr.p->tabState != TableRecord::DEFINED) { + if (tablePtr.p->tabState != TableRecord::DEFINED && + tablePtr.p->tabState != TableRecord::BACKUP_ONGOING) { jam(); opPtr.p->m_errorCode = CreateTrigRef::InvalidTable; opPtr.p->m_errorLine = __LINE__; @@ -10965,14 +11093,16 @@ Dbdict::createTrigger_sendReply(Signal* signal, OpCreateTriggerPtr opPtr, CreateTrigRef* rep = (CreateTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_CREATE_TRIG_CONF; Uint32 length = CreateTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == CreateTrigReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -11060,8 +11190,10 @@ Dbdict::execDROP_TRIG_REQ(Signal* signal) OpDropTrigger opBad; opPtr.p = &opBad; opPtr.p->save(req); - opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound; - opPtr.p->m_errorLine = __LINE__; + if (! (req->getRequestFlag() & RequestFlag::RF_FORCE)) { + opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound; + opPtr.p->m_errorLine = __LINE__; + } dropTrigger_sendReply(signal, opPtr, true); return; } @@ -11228,6 +11360,7 @@ Dbdict::dropTrigger_toAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); req->setRequestType(AlterTrigReq::RT_DROP_TRIGGER); + req->addRequestFlag(opPtr.p->m_requestFlag); req->setTableId(opPtr.p->m_request.getTableId()); req->setTriggerId(opPtr.p->m_request.getTriggerId()); req->setTriggerInfo(0); // not used @@ -11323,14 +11456,16 @@ Dbdict::dropTrigger_sendReply(Signal* signal, OpDropTriggerPtr opPtr, DropTrigRef* rep = (DropTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_DROP_TRIG_CONF; Uint32 length = DropTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == DropTrigReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -11554,28 +11689,37 @@ Dbdict::alterTrigger_recvReply(Signal* signal, const AlterTrigConf* conf, if (! (opPtr.p->m_request.getRequestFlag() & RequestFlag::RF_NOTCTRIGGER)) { if (requestType == AlterTrigReq::RT_DICT_PREPARE) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } if (requestType == AlterTrigReq::RT_DICT_TC) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } if (requestType == AlterTrigReq::RT_DICT_LQH) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } @@ -11616,6 +11760,11 @@ Dbdict::alterTrigger_slavePrepare(Signal* signal, OpAlterTriggerPtr opPtr) opPtr.p->m_errorLine = __LINE__; return; } + + if (triggerPtr.p->triggerType == TriggerType::SUBSCRIPTION) + { + opPtr.p->m_request.addRequestFlag(RequestFlag::RF_NOTCTRIGGER); + } } void @@ -11630,8 +11779,10 @@ Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); req->setRequestType(CreateTrigReq::RT_TC); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); req->setRequestType(CreateTrigReq::RT_LQH); } else { ndbassert(false); @@ -11648,8 +11799,10 @@ Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setReceiverRef(opPtr.p->m_request.getReceiverRef()); BlockReference blockRef = 0; if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); blockRef = calcLqhBlockRef(getOwnNodeId()); } else { ndbassert(false); @@ -11663,13 +11816,15 @@ void Dbdict::alterTrigger_fromCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) { jam(); - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { // mark created locally TriggerRecordPtr triggerPtr; c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_TC; } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_LQH; } else { ndbrequire(false); @@ -11689,17 +11844,21 @@ Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { - // broken trigger + jam(); + // broken trigger allowed if force if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_TC)) { jam(); + ndbassert(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterTrigger_sendReply(signal, opPtr, false); return; } req->setRequestType(DropTrigReq::RT_TC); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { - // broken trigger + jam(); + // broken trigger allowed if force if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_LQH)) { jam(); + ndbassert(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterTrigger_sendReply(signal, opPtr, false); return; } @@ -11717,8 +11876,10 @@ Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes); BlockReference blockRef = 0; if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); blockRef = calcLqhBlockRef(getOwnNodeId()); } else { ndbassert(false); @@ -11731,13 +11892,15 @@ void Dbdict::alterTrigger_fromDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) { jam(); - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { // mark dropped locally TriggerRecordPtr triggerPtr; c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_TC; } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_LQH; } else { ndbrequire(false); @@ -11794,8 +11957,9 @@ Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr, AlterTrigRef* rep = (AlterTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_ALTER_TRIG_CONF; Uint32 length = AlterTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); @@ -11806,6 +11970,7 @@ Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr, jam(); } } else { + sendRef = opPtr.p->hasError(); jam(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); @@ -12019,7 +12184,9 @@ Dbdict::getMetaTablePtr(TableRecordPtr& tablePtr, Uint32 tableId, Uint32 tableVe } // online flag is not maintained by DICT tablePtr.p->online = - tablePtr.p->isTable() && tablePtr.p->tabState == TableRecord::DEFINED || + tablePtr.p->isTable() && + (tablePtr.p->tabState == TableRecord::DEFINED || + tablePtr.p->tabState == TableRecord::BACKUP_ONGOING) || tablePtr.p->isIndex() && tablePtr.p->indexState == TableRecord::IS_ONLINE; return 0; } diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 68bb9b628d4..95efb2ec3fd 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -150,8 +150,6 @@ public: /** Pointer to last attribute in table */ Uint32 lastAttribute; - /* Temporary record used during add/drop table */ - Uint32 myConnect; #ifdef HAVE_TABLE_REORG /* Second table used by this table (for table reorg) */ Uint32 secondTable; @@ -175,7 +173,8 @@ public: CHECKED = 3, DEFINED = 4, PREPARE_DROPPING = 5, - DROPPING = 6 + DROPPING = 6, + BACKUP_ONGOING = 7 }; TabState tabState; @@ -511,6 +510,8 @@ private: void execBUILDINDXCONF(Signal* signal); void execBUILDINDXREF(Signal* signal); + void execBACKUP_FRAGMENT_REQ(Signal*); + // Util signals used by Event code void execUTIL_PREPARE_CONF(Signal* signal); void execUTIL_PREPARE_REF (Signal* signal); @@ -925,6 +926,8 @@ private: Uint32 m_errorCode; void setErrorCode(Uint32 c){ if(m_errorCode == 0) m_errorCode = c;} + + MutexHandle2<BACKUP_DEFINE_MUTEX> m_define_backup_mutex; /** * When sending stuff around @@ -953,7 +956,8 @@ private: enum { RF_LOCAL = 1 << 0, // create on local node only RF_NOBUILD = 1 << 1, // no need to build index - RF_NOTCTRIGGER = 1 << 2 // alter trigger: no trigger in TC + RF_NOTCTRIGGER = 1 << 2, // alter trigger: no trigger in TC + RF_FORCE = 1 << 4 // force drop }; }; @@ -973,6 +977,7 @@ private: CreateIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + CreateIndxRef::ErrorCode m_lastError; CreateIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -984,6 +989,7 @@ private: m_coordinatorRef = 0; m_requestType = CreateIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = CreateIndxRef::NoError; m_errorCode = CreateIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -993,34 +999,49 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != CreateIndxRef::NoError; + } bool hasError() { return m_errorCode != CreateIndxRef::NoError; } void setError(const CreateIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTableRef* ref) { - if (ref != 0 && ! hasError()) { + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { switch (ref->getErrorCode()) { case CreateTableRef::TableAlreadyExist: - m_errorCode = CreateIndxRef::IndexExists; + m_lastError = CreateIndxRef::IndexExists; break; default: - m_errorCode = (CreateIndxRef::ErrorCode)ref->getErrorCode(); + m_lastError = (CreateIndxRef::ErrorCode)ref->getErrorCode(); break; } - m_errorLine = ref->getErrorLine(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (CreateIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { + m_lastError = (CreateIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1039,6 +1060,7 @@ private: DropIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + DropIndxRef::ErrorCode m_lastError; DropIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1050,6 +1072,7 @@ private: m_coordinatorRef = 0; m_requestType = DropIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = DropIndxRef::NoError; m_errorCode = DropIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1059,44 +1082,59 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != DropIndxRef::NoError; + } bool hasError() { return m_errorCode != DropIndxRef::NoError; } void setError(const DropIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = ref->getErrorCode(); + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (DropIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + m_lastError = (DropIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTableRef* ref) { - if (ref != 0 && ! hasError()) { - switch(ref->errorCode) { - case(DropTableRef::Busy): - m_errorCode = DropIndxRef::Busy; + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + switch (ref->errorCode) { + case DropTableRef::Busy: + m_lastError = DropIndxRef::Busy; break; - case(DropTableRef::NoSuchTable): - m_errorCode = DropIndxRef::IndexNotFound; + case DropTableRef::NoSuchTable: + m_lastError = DropIndxRef::IndexNotFound; break; - case(DropTableRef::DropInProgress): - m_errorCode = DropIndxRef::Busy; + case DropTableRef::DropInProgress: + m_lastError = DropIndxRef::Busy; break; - case(DropTableRef::NoDropTableRecordAvailable): - m_errorCode = DropIndxRef::Busy; + case DropTableRef::NoDropTableRecordAvailable: + m_lastError = DropIndxRef::Busy; break; default: - m_errorCode = (DropIndxRef::ErrorCode)ref->errorCode; + m_lastError = (DropIndxRef::ErrorCode)ref->errorCode; break; } - //m_errorLine = ref->getErrorLine(); - //m_errorNode = ref->getErrorNode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } }; @@ -1117,6 +1155,7 @@ private: AlterIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + AlterIndxRef::ErrorCode m_lastError; AlterIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1129,6 +1168,7 @@ private: m_coordinatorRef = 0; m_requestType = AlterIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = AlterIndxRef::NoError; m_errorCode = AlterIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1139,47 +1179,76 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != AlterIndxRef::NoError; + } bool hasError() { return m_errorCode != AlterIndxRef::NoError; } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const BuildIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1201,6 +1270,7 @@ private: Uint32 m_requestFlag; Uint32 m_constrTriggerId; // error info + BuildIndxRef::ErrorCode m_lastError; BuildIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1212,7 +1282,7 @@ private: m_coordinatorRef = 0; m_requestType = BuildIndxReq::RT_UNDEFINED; m_requestFlag = 0; -// Uint32 m_constrTriggerId = RNIL; + m_lastError = BuildIndxRef::NoError; m_errorCode = BuildIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1222,33 +1292,54 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != BuildIndxRef::NoError; + } bool hasError() { return m_errorCode != BuildIndxRef::NoError; } void setError(const BuildIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1381,6 +1472,7 @@ private: CreateTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + CreateTrigRef::ErrorCode m_lastError; CreateTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1392,6 +1484,7 @@ private: m_coordinatorRef = 0; m_requestType = CreateTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = CreateTrigRef::NoError; m_errorCode = CreateTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1401,21 +1494,32 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != CreateTrigRef::NoError; + } bool hasError() { return m_errorCode != CreateTrigRef::NoError; } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateTrigRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (CreateTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateTrigRef::NoError; + if (ref != 0) { + m_lastError = (CreateTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1434,6 +1538,7 @@ private: DropTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + DropTrigRef::ErrorCode m_lastError; DropTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1445,6 +1550,7 @@ private: m_coordinatorRef = 0; m_requestType = DropTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = DropTrigRef::NoError; m_errorCode = DropTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1454,21 +1560,32 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != DropTrigRef::NoError; + } bool hasError() { return m_errorCode != DropTrigRef::NoError; } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropTrigRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (DropTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropTrigRef::NoError; + if (ref != 0) { + m_lastError = (DropTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1489,6 +1606,7 @@ private: AlterTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + AlterTrigRef::ErrorCode m_lastError; AlterTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1500,6 +1618,7 @@ private: m_coordinatorRef = 0; m_requestType = AlterTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = AlterTrigRef::NoError; m_errorCode = AlterTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1509,28 +1628,43 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != AlterTrigRef::NoError; + } bool hasError() { return m_errorCode != AlterTrigRef::NoError; } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1942,6 +2076,7 @@ private: bool getIsFailed(Uint32 nodeId) const; + void dropTable_backup_mutex_locked(Signal* signal, Uint32, Uint32); void dropTableRef(Signal * signal, DropTableReq *, DropTableRef::ErrorCode); void printTables(); // For debugging only int handleAlterTab(AlterTabReq * req, @@ -1952,6 +2087,7 @@ private: Uint32 changeMask, Uint32 tableId, CreateTableRecord * regAlterTabPtr); + void alterTable_backup_mutex_locked(Signal* signal, Uint32, Uint32); void alterTableRef(Signal * signal, AlterTableReq *, AlterTableRef::ErrorCode, ParseDictTabInfoRecord* parseRecord = NULL); diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 2a661104347..723792d2e26 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -10290,7 +10290,87 @@ void Dbdih::tableCloseLab(Signal* signal, FileRecordPtr filePtr) * GCP stop detected, * send SYSTEM_ERROR to all other alive nodes */ -void Dbdih::crashSystemAtGcpStop(Signal* signal){ +void Dbdih::crashSystemAtGcpStop(Signal* signal) +{ + switch(cgcpStatus){ + case GCP_NODE_FINISHED: + { + /** + * We're waiting for a GCP save conf + */ + ndbrequire(!c_GCP_SAVEREQ_Counter.done()); + NodeReceiverGroup rg(DBLQH, c_GCP_SAVEREQ_Counter); + signal->theData[0] = 2305; + sendSignal(rg, GSN_DUMP_STATE_ORD, signal, 1, JBB); + + infoEvent("Detected GCP stop...sending kill to %s", + c_GCP_SAVEREQ_Counter.getText()); + ndbout_c("Detected GCP stop...sending kill to %s", + c_GCP_SAVEREQ_Counter.getText()); + return; + } + case GCP_SAVE_LQH_FINISHED: + ndbout_c("m_copyReason: %d m_waiting: %d", + c_copyGCIMaster.m_copyReason, + c_copyGCIMaster.m_waiting); + break; + } + + ndbout_c("c_copyGCISlave: sender{Data, Ref} %d %x reason: %d nextWord: %d", + c_copyGCISlave.m_senderData, + c_copyGCISlave.m_senderRef, + c_copyGCISlave.m_copyReason, + c_copyGCISlave.m_expectedNextWord); + + FileRecordPtr file0Ptr; + file0Ptr.i = crestartInfoFile[0]; + ptrCheckGuard(file0Ptr, cfileFileSize, fileRecord); + FileRecordPtr file1Ptr; + file1Ptr.i = crestartInfoFile[1]; + ptrCheckGuard(file1Ptr, cfileFileSize, fileRecord); + + ndbout_c("file[0] status: %d type: %d reqStatus: %d file1: %d %d %d", + file0Ptr.p->fileStatus, file0Ptr.p->fileType, file0Ptr.p->reqStatus, + file1Ptr.p->fileStatus, file1Ptr.p->fileType, file1Ptr.p->reqStatus + ); + + signal->theData[0] = 404; + signal->theData[1] = file0Ptr.p->fileRef; + EXECUTE_DIRECT(NDBFS, GSN_DUMP_STATE_ORD, signal, 2); + + signal->theData[0] = 404; + signal->theData[1] = file1Ptr.p->fileRef; + EXECUTE_DIRECT(NDBFS, GSN_DUMP_STATE_ORD, signal, 2); + + ndbout_c("c_COPY_GCIREQ_Counter = %s", + c_COPY_GCIREQ_Counter.getText()); + ndbout_c("c_COPY_TABREQ_Counter = %s", + c_COPY_TABREQ_Counter.getText()); + ndbout_c("c_CREATE_FRAGREQ_Counter = %s", + c_CREATE_FRAGREQ_Counter.getText()); + ndbout_c("c_DIH_SWITCH_REPLICA_REQ_Counter = %s", + c_DIH_SWITCH_REPLICA_REQ_Counter.getText()); + ndbout_c("c_EMPTY_LCP_REQ_Counter = %s",c_EMPTY_LCP_REQ_Counter.getText()); + ndbout_c("c_END_TOREQ_Counter = %s", c_END_TOREQ_Counter.getText()); + ndbout_c("c_GCP_COMMIT_Counter = %s", c_GCP_COMMIT_Counter.getText()); + ndbout_c("c_GCP_PREPARE_Counter = %s", c_GCP_PREPARE_Counter.getText()); + ndbout_c("c_GCP_SAVEREQ_Counter = %s", c_GCP_SAVEREQ_Counter.getText()); + ndbout_c("c_INCL_NODEREQ_Counter = %s", c_INCL_NODEREQ_Counter.getText()); + ndbout_c("c_MASTER_GCPREQ_Counter = %s", + c_MASTER_GCPREQ_Counter.getText()); + ndbout_c("c_MASTER_LCPREQ_Counter = %s", + c_MASTER_LCPREQ_Counter.getText()); + ndbout_c("c_START_INFOREQ_Counter = %s", + c_START_INFOREQ_Counter.getText()); + ndbout_c("c_START_RECREQ_Counter = %s", c_START_RECREQ_Counter.getText()); + ndbout_c("c_START_TOREQ_Counter = %s", c_START_TOREQ_Counter.getText()); + ndbout_c("c_STOP_ME_REQ_Counter = %s", c_STOP_ME_REQ_Counter.getText()); + ndbout_c("c_TC_CLOPSIZEREQ_Counter = %s", + c_TC_CLOPSIZEREQ_Counter.getText()); + ndbout_c("c_TCGETOPSIZEREQ_Counter = %s", + c_TCGETOPSIZEREQ_Counter.getText()); + ndbout_c("c_UPDATE_TOREQ_Counter = %s", c_UPDATE_TOREQ_Counter.getText()); + NodeRecordPtr nodePtr; for (nodePtr.i = 1; nodePtr.i < MAX_NDB_NODES; nodePtr.i++) { jam(); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 725ea04c148..a15d54c0b28 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -169,6 +169,8 @@ void Dblqh::execTUP_COM_UNBLOCK(Signal* signal) /* ------------------------------------------------------------------------- */ void Dblqh::systemError(Signal* signal) { + signal->theData[0] = 2304; + execDUMP_STATE_ORD(signal); progError(0, 0); }//Dblqh::systemError() @@ -12598,6 +12600,22 @@ void Dblqh::lastWriteInFileLab(Signal* signal) void Dblqh::writePageZeroLab(Signal* signal) { + if (false && logPartPtr.p->logPartState == LogPartRecord::FILE_CHANGE_PROBLEM) + { + if (logPartPtr.p->firstLogQueue == RNIL) + { + jam(); + logPartPtr.p->logPartState = LogPartRecord::IDLE; + ndbout_c("resetting logPartState to IDLE"); + } + else + { + jam(); + logPartPtr.p->logPartState = LogPartRecord::ACTIVE; + ndbout_c("resetting logPartState to ACTIVE"); + } + } + logFilePtr.p->fileChangeState = LogFileRecord::NOT_ONGOING; /*---------------------------------------------------------------------------*/ /* IT COULD HAVE ARRIVED PAGE WRITES TO THE CURRENT FILE WHILE WE WERE */ @@ -15661,6 +15679,7 @@ void Dblqh::warningHandlerLab(Signal* signal) void Dblqh::systemErrorLab(Signal* signal) { + systemError(signal); progError(0, 0); /*************************************************************************>*/ /* WE WANT TO INVOKE AN IMMEDIATE ERROR HERE SO WE GET THAT BY */ @@ -18526,8 +18545,65 @@ Dblqh::execDUMP_STATE_ORD(Signal* signal) return; } + Uint32 arg= dumpState->args[0]; + if(arg == 2304 || arg == 2305) + { + jam(); + Uint32 i; + GcpRecordPtr gcp; gcp.i = RNIL; + for(i = 0; i<4; i++) + { + logPartPtr.i = i; + ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); + ndbout_c("LP %d state: %d WW_Gci: %d gcprec: %d flq: %d currfile: %d tailFileNo: %d logTailMbyte: %d", + i, + logPartPtr.p->logPartState, + logPartPtr.p->waitWriteGciLog, + logPartPtr.p->gcprec, + logPartPtr.p->firstLogQueue, + logPartPtr.p->currentLogfile, + logPartPtr.p->logTailFileNo, + logPartPtr.p->logTailMbyte); + + if(gcp.i == RNIL && logPartPtr.p->gcprec != RNIL) + gcp.i = logPartPtr.p->gcprec; + LogFileRecordPtr logFilePtr; + Uint32 first= logFilePtr.i= logPartPtr.p->firstLogfile; + do + { + ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); + ndbout_c(" file %d(%d) FileChangeState: %d logFileStatus: %d currentMbyte: %d currentFilepage", + logFilePtr.p->fileNo, + logFilePtr.i, + logFilePtr.p->fileChangeState, + logFilePtr.p->logFileStatus, + logFilePtr.p->currentMbyte, + logFilePtr.p->currentFilepage); + logFilePtr.i = logFilePtr.p->nextLogFile; + } while(logFilePtr.i != first); + } + + if(gcp.i != RNIL) + { + ptrCheckGuard(gcp, cgcprecFileSize, gcpRecord); + for(i = 0; i<4; i++) + { + ndbout_c(" GCP %d file: %d state: %d sync: %d page: %d word: %d", + i, gcp.p->gcpFilePtr[i], gcp.p->gcpLogPartState[i], + gcp.p->gcpSyncReady[i], + gcp.p->gcpPageNo[i], + gcp.p->gcpWordNo[i]); + } + } + if(arg== 2305) + { + progError(__LINE__, ERR_SYSTEM_ERROR, + "Shutting down node due to failed handling of GCP_SAVEREQ"); + + } + } }//Dblqh::execDUMP_STATE_ORD() void Dblqh::execSET_VAR_REQ(Signal* signal) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index e4cce29ba30..07a85b705fb 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -11043,6 +11043,7 @@ void Dbtc::execCREATE_TRIG_REQ(Signal* signal) if (ERROR_INSERTED(8033) || !c_theDefinedTriggers.seizeId(triggerPtr, createTrigReq->getTriggerId())) { + jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate trigger record CreateTrigRef * const createTrigRef = @@ -11077,8 +11078,10 @@ void Dbtc::execDROP_TRIG_REQ(Signal* signal) DropTrigReq * const dropTrigReq = (DropTrigReq *)&signal->theData[0]; BlockReference sender = signal->senderBlockRef(); - if ((c_theDefinedTriggers.getPtr(dropTrigReq->getTriggerId())) == NULL) { + if (ERROR_INSERTED(8035) || + (c_theDefinedTriggers.getPtr(dropTrigReq->getTriggerId())) == NULL) { jam(); + CLEAR_ERROR_INSERT_VALUE; // Failed to find find trigger record DropTrigRef * const dropTrigRef = (DropTrigRef *)&signal->theData[0]; @@ -11110,6 +11113,7 @@ void Dbtc::execCREATE_INDX_REQ(Signal* signal) if (ERROR_INSERTED(8034) || !c_theIndexes.seizeId(indexPtr, createIndxReq->getIndexId())) { + jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate index record CreateIndxRef * const createIndxRef = @@ -11321,8 +11325,10 @@ void Dbtc::execDROP_INDX_REQ(Signal* signal) TcIndexData* indexData; BlockReference sender = signal->senderBlockRef(); - if ((indexData = c_theIndexes.getPtr(dropIndxReq->getIndexId())) == NULL) { + if (ERROR_INSERTED(8036) || + (indexData = c_theIndexes.getPtr(dropIndxReq->getIndexId())) == NULL) { jam(); + CLEAR_ERROR_INSERT_VALUE; // Failed to find index record DropIndxRef * const dropIndxRef = (DropIndxRef *)signal->getDataPtrSend(); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp index 03f02dd0b92..f02a804aa83 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp @@ -672,10 +672,12 @@ void Dbtup::execREAD_CONFIG_REQ(Signal* signal) initialiseRecordsLab(signal, 0, ref, senderData); clblPagesPerTick = 50; - //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTick); + ndb_mgm_get_int_parameter(p, CFG_DB_LCP_DISC_PAGES_TUP_SR, + &clblPagesPerTick); clblPagesPerTickAfterSr = 50; - //ndb_mgm_get_int_parameter(p, CFG_DB_, &clblPagesPerTickAfterSr); + ndb_mgm_get_int_parameter(p, CFG_DB_LCP_DISC_PAGES_TUP, + &clblPagesPerTickAfterSr); }//Dbtup::execSIZEALT_REP() diff --git a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp index 2b65a8402c2..6652464dc0f 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp @@ -305,6 +305,10 @@ Dbtup::primaryKey(Tablerec* const regTabPtr, Uint32 attrId) Uint32 Dbtup::dropTrigger(Tablerec* table, const DropTrigReq* req) { + if (ERROR_INSERTED(4004)) { + CLEAR_ERROR_INSERT_VALUE; + return 9999; + } Uint32 triggerId = req->getTriggerId(); TriggerType::Value ttype = req->getTriggerType(); @@ -603,7 +607,7 @@ void Dbtup::executeTrigger(Signal* signal, for everybody else. */ signal->theData[0] = trigPtr->triggerId; - signal->theData[1] = regOperPtr->fragId; + signal->theData[1] = regOperPtr->fragId >> 1; // send "real" frag id EXECUTE_DIRECT(BACKUP, GSN_BACKUP_TRIG_REQ, signal, 2); ljamEntry(); if (signal->theData[0] == 0) { diff --git a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp index f76440a462a..45073b63a5d 100644 --- a/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +++ b/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp @@ -96,6 +96,7 @@ AsyncFile::AsyncFile() : theReportTo(0), theMemoryChannelPtr(NULL) { + m_current_request= m_last_request= 0; } void @@ -177,6 +178,7 @@ AsyncFile::run() endReq(); return; }//if + m_current_request= request; switch (request->action) { case Request:: open: openReq(request); @@ -226,7 +228,11 @@ AsyncFile::run() abort(); break; }//switch - theReportTo->writeChannel(request); + m_last_request= request; + m_current_request= 0; + + // No need to signal as ndbfs only uses tryRead + theReportTo->writeChannelNoSignal(request); }//while }//AsyncFile::run() @@ -1031,3 +1037,60 @@ void printErrorAndFlags(Uint32 used_flags) { } #endif + +NdbOut& +operator<<(NdbOut& out, const Request& req) +{ + out << "[ Request: file: " << hex << req.file + << " userRef: " << hex << req.theUserReference + << " userData: " << dec << req.theUserPointer + << " theFilePointer: " << req.theFilePointer + << " action: "; + switch(req.action){ + case Request::open: + out << "open"; + break; + case Request::close: + out << "close"; + break; + case Request::closeRemove: + out << "closeRemove"; + break; + case Request::read: // Allways leave readv directly after + out << "read"; + break; + case Request::readv: + out << "readv"; + break; + case Request::write:// Allways leave writev directly after + out << "write"; + break; + case Request::writev: + out << "writev"; + break; + case Request::writeSync:// Allways leave writevSync directly after + out << "writeSync"; + break; + // writeSync because SimblockAsyncFileSystem depends on it + case Request::writevSync: + out << "writevSync"; + break; + case Request::sync: + out << "sync"; + break; + case Request::end: + out << "end"; + break; + case Request::append: + out << "append"; + break; + case Request::rmrf: + out << "rmrf"; + break; + default: + out << (Uint32)req.action; + break; + } + out << " ]"; + return out; +} diff --git a/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp b/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp index 2176c93c5d5..997bf40fe2a 100644 --- a/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp +++ b/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp @@ -160,6 +160,7 @@ public: Uint32 theTrace; }; +NdbOut& operator <<(NdbOut&, const Request&); inline void @@ -173,6 +174,7 @@ Request::set(BlockReference userReference, class AsyncFile { + friend class Ndbfs; public: AsyncFile(); ~AsyncFile(); @@ -188,6 +190,7 @@ public: bool isOpen(); Filename theFileName; + Request *m_current_request, *m_last_request; private: void openReq(Request *request); diff --git a/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp b/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp index 349cccdbcb4..460ad3f614a 100644 --- a/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp +++ b/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp @@ -68,7 +68,7 @@ class CircularIndex { public: inline CircularIndex( int start= 0,int size=256 ); - operator int (); + operator int () const; CircularIndex& operator ++ (); friend int full( const CircularIndex& write, const CircularIndex& read ); friend int empty( const CircularIndex& write, const CircularIndex& read ); @@ -77,7 +77,7 @@ private: int theIndex; }; -inline CircularIndex::operator int () +inline CircularIndex::operator int () const { return theIndex; } diff --git a/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp b/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp index 03911d195ec..9037bbad765 100644 --- a/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp +++ b/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp @@ -84,7 +84,8 @@ public: MemoryChannel( int size= 256); virtual ~MemoryChannel( ); - virtual void writeChannel( T *t); + void writeChannel( T *t); + void writeChannelNoSignal( T *t); T* readChannel(); T* tryReadChannel(); @@ -96,8 +97,20 @@ private: NdbMutex* theMutexPtr; NdbCondition* theConditionPtr; + template<class U> + friend NdbOut& operator<<(NdbOut& out, const MemoryChannel<U> & chn); }; +template <class T> +NdbOut& operator<<(NdbOut& out, const MemoryChannel<T> & chn) +{ + NdbMutex_Lock(chn.theMutexPtr); + out << "[ theSize: " << chn.theSize + << " theReadIndex: " << (int)chn.theReadIndex + << " theWriteIndex: " << (int)chn.theWriteIndex << " ]"; + NdbMutex_Unlock(chn.theMutexPtr); + return out; +} template <class T> MemoryChannel<T>::MemoryChannel( int size): theSize(size), @@ -127,6 +140,15 @@ template <class T> void MemoryChannel<T>::writeChannel( T *t) NdbCondition_Signal(theConditionPtr); } +template <class T> void MemoryChannel<T>::writeChannelNoSignal( T *t) +{ + + NdbMutex_Lock(theMutexPtr); + if(full(theWriteIndex, theReadIndex) || theChannel == NULL) abort(); + theChannel[theWriteIndex]= t; + ++theWriteIndex; + NdbMutex_Unlock(theMutexPtr); +} template <class T> T* MemoryChannel<T>::readChannel() { @@ -149,8 +171,6 @@ template <class T> T* MemoryChannel<T>::tryReadChannel() { T* tmp= 0; NdbMutex_Lock(theMutexPtr); - NdbCondition_WaitTimeout(theConditionPtr, - theMutexPtr, 0); if ( !empty(theWriteIndex, theReadIndex) ) { tmp= theChannel[theReadIndex]; diff --git a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp index 6f848d7fe16..d6b19c8f872 100644 --- a/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp +++ b/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp @@ -1006,6 +1006,30 @@ Ndbfs::execDUMP_STATE_ORD(Signal* signal) } return; } + + if(signal->theData[0] == 404) + { + ndbrequire(signal->getLength() == 2); + Uint32 file= signal->theData[1]; + AsyncFile* openFile = theOpenFiles.find(file); + ndbrequire(openFile); + ndbout_c("File: %s %p", openFile->theFileName.c_str(), openFile); + Request* curr = openFile->m_current_request; + Request* last = openFile->m_last_request; + if(curr) + ndbout << "Current request: " << *curr << endl; + if(last) + ndbout << "Last request: " << *last << endl; + + ndbout << "theReportTo " << *openFile->theReportTo << endl; + ndbout << "theMemoryChannelPtr" << *openFile->theMemoryChannelPtr << endl; + + ndbout << "All files: " << endl; + for (unsigned i = 0; i < theFiles.size(); i++){ + AsyncFile* file = theFiles[i]; + ndbout_c("%2d (0x%x): %s", i,file, file->isOpen()?"OPEN":"CLOSED"); + } + } }//Ndbfs::execDUMP_STATE_ORD() @@ -1016,3 +1040,4 @@ template class Vector<AsyncFile*>; template class Vector<OpenFiles::OpenFileItem>; template class MemoryChannel<Request>; template class Pool<Request>; +template NdbOut& operator<<(NdbOut&, const MemoryChannel<Request>&); diff --git a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp index e134609df0a..2f4fcd21460 100644 --- a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp +++ b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp @@ -118,8 +118,7 @@ public: struct NodeRec { UintR ndynamicId; Phase phase; - UintR alarmCount; - + QmgrState sendPrepFailReqStatus; QmgrState sendCommitFailReqStatus; QmgrState sendPresToStatus; diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp index 621ec70fbe1..d062f5afb7e 100644 --- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp +++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp @@ -66,7 +66,7 @@ void Qmgr::execCM_HEARTBEAT(Signal* signal) jamEntry(); hbNodePtr.i = signal->theData[0]; ptrCheckGuard(hbNodePtr, MAX_NDB_NODES, nodeRec); - hbNodePtr.p->alarmCount = 0; + setNodeInfo(hbNodePtr.i).m_heartbeat_cnt= 0; return; }//Qmgr::execCM_HEARTBEAT() @@ -1040,7 +1040,7 @@ void Qmgr::execCM_ADD(Signal* signal) jam(); ndbrequire(addNodePtr.p->phase == ZSTARTING); addNodePtr.p->phase = ZRUNNING; - addNodePtr.p->alarmCount = 0; + setNodeInfo(addNodePtr.i).m_heartbeat_cnt= 0; c_clusterNodes.set(addNodePtr.i); findNeighbours(signal); @@ -1078,7 +1078,7 @@ Qmgr::joinedCluster(Signal* signal, NodeRecPtr nodePtr){ * NODES IN THE CLUSTER. */ nodePtr.p->phase = ZRUNNING; - nodePtr.p->alarmCount = 0; + setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0; findNeighbours(signal); c_clusterNodes.set(nodePtr.i); c_start.reset(); @@ -1299,7 +1299,7 @@ void Qmgr::findNeighbours(Signal* signal) *---------------------------------------------------------------------*/ fnNodePtr.i = cneighbourl; ptrCheckGuard(fnNodePtr, MAX_NDB_NODES, nodeRec); - fnNodePtr.p->alarmCount = 0; + setNodeInfo(fnNodePtr.i).m_heartbeat_cnt= 0; }//if }//if @@ -1347,8 +1347,8 @@ void Qmgr::initData(Signal* signal) } else { nodePtr.p->phase = ZAPI_INACTIVE; } - - nodePtr.p->alarmCount = 0; + + setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0; nodePtr.p->sendPrepFailReqStatus = Q_NOT_ACTIVE; nodePtr.p->sendCommitFailReqStatus = Q_NOT_ACTIVE; nodePtr.p->sendPresToStatus = Q_NOT_ACTIVE; @@ -1550,18 +1550,18 @@ void Qmgr::checkHeartbeat(Signal* signal) }//if ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRec); - nodePtr.p->alarmCount ++; + setNodeInfo(nodePtr.i).m_heartbeat_cnt++; ndbrequire(nodePtr.p->phase == ZRUNNING); ndbrequire(getNodeInfo(nodePtr.i).m_type == NodeInfo::DB); - if(nodePtr.p->alarmCount > 2){ + if(getNodeInfo(nodePtr.i).m_heartbeat_cnt > 2){ signal->theData[0] = NDB_LE_MissedHeartbeat; signal->theData[1] = nodePtr.i; - signal->theData[2] = nodePtr.p->alarmCount - 1; + signal->theData[2] = getNodeInfo(nodePtr.i).m_heartbeat_cnt - 1; sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB); } - if (nodePtr.p->alarmCount > 4) { + if (getNodeInfo(nodePtr.i).m_heartbeat_cnt > 4) { jam(); /**---------------------------------------------------------------------- * OUR LEFT NEIGHBOUR HAVE KEPT QUIET FOR THREE CONSECUTIVE HEARTBEAT @@ -1593,16 +1593,16 @@ void Qmgr::apiHbHandlingLab(Signal* signal) if (TnodePtr.p->phase == ZAPI_ACTIVE){ jam(); - TnodePtr.p->alarmCount ++; + setNodeInfo(TnodePtr.i).m_heartbeat_cnt++; - if(TnodePtr.p->alarmCount > 2){ + if(getNodeInfo(TnodePtr.i).m_heartbeat_cnt > 2){ signal->theData[0] = NDB_LE_MissedHeartbeat; signal->theData[1] = nodeId; - signal->theData[2] = TnodePtr.p->alarmCount - 1; + signal->theData[2] = getNodeInfo(TnodePtr.i).m_heartbeat_cnt - 1; sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB); } - if (TnodePtr.p->alarmCount > 4) { + if (getNodeInfo(TnodePtr.i).m_heartbeat_cnt > 4) { jam(); /*------------------------------------------------------------------*/ /* THE API NODE HAS NOT SENT ANY HEARTBEAT FOR THREE SECONDS. @@ -1634,16 +1634,17 @@ void Qmgr::checkStartInterface(Signal* signal) ptrAss(nodePtr, nodeRec); if (nodePtr.p->phase == ZFAIL_CLOSING) { jam(); - nodePtr.p->alarmCount = nodePtr.p->alarmCount + 1; + setNodeInfo(nodePtr.i).m_heartbeat_cnt++; if (c_connectedNodes.get(nodePtr.i)){ jam(); /*-------------------------------------------------------------------*/ // We need to ensure that the connection is not restored until it has // been disconnected for at least three seconds. /*-------------------------------------------------------------------*/ - nodePtr.p->alarmCount = 0; + setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0; }//if - if ((nodePtr.p->alarmCount > 3) && (nodePtr.p->failState == NORMAL)) { + if ((getNodeInfo(nodePtr.i).m_heartbeat_cnt > 3) + && (nodePtr.p->failState == NORMAL)) { /**------------------------------------------------------------------ * WE HAVE DISCONNECTED THREE SECONDS AGO. WE ARE NOW READY TO * CONNECT AGAIN AND ACCEPT NEW REGISTRATIONS FROM THIS NODE. @@ -1659,18 +1660,18 @@ void Qmgr::checkStartInterface(Signal* signal) nodePtr.p->phase = ZINIT; }//if - nodePtr.p->alarmCount = 0; + setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0; signal->theData[0] = 0; signal->theData[1] = nodePtr.i; sendSignal(CMVMI_REF, GSN_OPEN_COMREQ, signal, 2, JBA); } else { - if(((nodePtr.p->alarmCount + 1) % 60) == 0){ + if(((getNodeInfo(nodePtr.i).m_heartbeat_cnt + 1) % 60) == 0){ char buf[100]; BaseString::snprintf(buf, sizeof(buf), "Failure handling of node %d has not completed in %d min." " - state = %d", nodePtr.i, - (nodePtr.p->alarmCount + 1)/60, + (getNodeInfo(nodePtr.i).m_heartbeat_cnt + 1)/60, nodePtr.p->failState); warningEvent(buf); } @@ -1718,7 +1719,7 @@ void Qmgr::sendApiFailReq(Signal* signal, Uint16 failedNodeNo) * WE ONLY NEED TO SET PARAMETERS TO ENABLE A NEW CONNECTION IN A FEW * SECONDS. *-------------------------------------------------------------------------*/ - failedNodePtr.p->alarmCount = 0; + setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0; CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0]; @@ -1871,7 +1872,7 @@ void Qmgr::node_failed(Signal* signal, Uint16 aFailedNode) /*---------------------------------------------------------------------*/ failedNodePtr.p->failState = NORMAL; failedNodePtr.p->phase = ZFAIL_CLOSING; - failedNodePtr.p->alarmCount = 0; + setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0; CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0]; @@ -1965,8 +1966,8 @@ void Qmgr::execAPI_REGREQ(Signal* signal) } setNodeInfo(apiNodePtr.i).m_version = version; - - apiNodePtr.p->alarmCount = 0; + + setNodeInfo(apiNodePtr.i).m_heartbeat_cnt= 0; ApiRegConf * const apiRegConf = (ApiRegConf *)&signal->theData[0]; apiRegConf->qmgrRef = reference(); @@ -2484,7 +2485,7 @@ void Qmgr::execCOMMIT_FAILREQ(Signal* signal) ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRec); nodePtr.p->phase = ZFAIL_CLOSING; nodePtr.p->failState = WAITING_FOR_NDB_FAILCONF; - nodePtr.p->alarmCount = 0; + setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0; c_clusterNodes.clear(nodePtr.i); }//for /*----------------------------------------------------------------------*/ @@ -2742,7 +2743,7 @@ void Qmgr::failReport(Signal* signal, failedNodePtr.p->sendPrepFailReqStatus = Q_NOT_ACTIVE; failedNodePtr.p->sendCommitFailReqStatus = Q_NOT_ACTIVE; failedNodePtr.p->sendPresToStatus = Q_NOT_ACTIVE; - failedNodePtr.p->alarmCount = 0; + setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0; if (aSendFailRep == ZTRUE) { jam(); if (failedNodePtr.i != getOwnNodeId()) { diff --git a/ndb/src/kernel/vm/Makefile.am b/ndb/src/kernel/vm/Makefile.am index d9e57ce9dd6..0dce9285ae3 100644 --- a/ndb/src/kernel/vm/Makefile.am +++ b/ndb/src/kernel/vm/Makefile.am @@ -18,8 +18,7 @@ libkernel_a_SOURCES = \ SimplePropertiesSection.cpp \ SectionReader.cpp \ MetaData.cpp \ - Mutex.cpp SafeCounter.cpp \ - SuperPool.cpp + Mutex.cpp SafeCounter.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi diff --git a/ndb/src/kernel/vm/TransporterCallback.cpp b/ndb/src/kernel/vm/TransporterCallback.cpp index 0f292143c21..e5322edaecc 100644 --- a/ndb/src/kernel/vm/TransporterCallback.cpp +++ b/ndb/src/kernel/vm/TransporterCallback.cpp @@ -33,6 +33,7 @@ #include <NdbOut.hpp> #include "DataBuffer.hpp" + /** * The instance */ @@ -452,3 +453,8 @@ SignalLoggerManager::printSegmentedSection(FILE * output, putc('\n', output); } +void +transporter_recv_from(void * callbackObj, NodeId nodeId){ + globalData.m_nodeInfo[nodeId].m_heartbeat_cnt= 0; + return; +} diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 5808e2ed534..1cfc46ae078 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -101,6 +101,7 @@ struct ndb_mgm_handle { #ifdef MGMAPI_LOG FILE* logfile; #endif + FILE *errstream; }; #define SET_ERROR(h, e, s) setError(h, e, __LINE__, s) @@ -154,6 +155,7 @@ ndb_mgm_create_handle() h->read_timeout = 50000; h->write_timeout = 100; h->cfg_i = -1; + h->errstream = stdout; strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE); @@ -219,6 +221,13 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle) DBUG_VOID_RETURN; } +extern "C" +void +ndb_mgm_set_error_stream(NdbMgmHandle handle, FILE * file) +{ + handle->errstream = file; +} + /***************************************************************************** * Error handling *****************************************************************************/ @@ -329,11 +338,9 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply, /** * Print some info about why the parser returns NULL */ - ndbout << "Error in mgm protocol parser. " - << "cmd: '" << cmd - << "' status=" << (Uint32)ctx.m_status - << ", curr=" << ctx.m_currentToken - << endl; + fprintf(handle->errstream, + "Error in mgm protocol parser. cmd: >%s< status: %d curr: %d\n", + cmd, (Uint32)ctx.m_status, ctx.m_currentToken); DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s", ctx.m_status, ctx.m_currentToken)); } @@ -409,8 +416,8 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, #endif if (verbose > 0) { char buf[1024]; - ndbout_c("Unable to connect with connect string: %s", - cfg.makeConnectString(buf,sizeof(buf))); + fprintf(handle->errstream, "Unable to connect with connect string: %s\n", + cfg.makeConnectString(buf,sizeof(buf))); verbose= -1; } if (no_retries == 0) { @@ -419,32 +426,35 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, "Unable to connect with connect string: %s", cfg.makeConnectString(buf,sizeof(buf))); if (verbose == -2) - ndbout << ", failed." << endl; + fprintf(handle->errstream, ", failed.\n"); DBUG_RETURN(-1); } if (verbose == -1) { - ndbout << "Retrying every " << retry_delay_in_seconds << " seconds"; + fprintf(handle->errstream, "Retrying every %d seconds", + retry_delay_in_seconds); if (no_retries > 0) - ndbout << ". Attempts left:"; + fprintf(handle->errstream, ". Attempts left:"); else - ndbout << ", until connected.";; - ndbout << flush; + fprintf(handle->errstream, ", until connected."); + fflush(handle->errstream); verbose= -2; } if (no_retries > 0) { if (verbose == -2) { - ndbout << " " << no_retries; - ndbout << flush; + fprintf(handle->errstream, " %d", no_retries); + fflush(handle->errstream); } no_retries--; } NdbSleep_SecSleep(retry_delay_in_seconds); } if (verbose == -2) - ndbout << endl; - + { + fprintf(handle->errstream, "\n"); + fflush(handle->errstream); + } handle->cfg_i = i; - + handle->socket = sockfd; handle->connected = 1; @@ -496,7 +506,9 @@ ndb_mgm_match_node_type(const char * type) for(int i = 0; i<no_of_type_values; i++) if(strcmp(type, type_values[i].str) == 0) return type_values[i].value; - + else if(strcmp(type, type_values[i].alias) == 0) + return type_values[i].value; + return NDB_MGM_NODE_TYPE_UNKNOWN; } @@ -1705,28 +1717,28 @@ ndb_mgm_get_configuration(NdbMgmHandle handle, unsigned int version) { do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n\n", buf); break; } buf = "<Unspecified>"; if(!prop->get("Content-Type", &buf) || strcmp(buf, "ndbconfig/octet-stream") != 0){ - ndbout_c("Unhandled response type: %s", buf); + fprintf(handle->errstream, "Unhandled response type: %s\n", buf); break; } buf = "<Unspecified>"; if(!prop->get("Content-Transfer-Encoding", &buf) || strcmp(buf, "base64") != 0){ - ndbout_c("Unhandled encoding: %s", buf); + fprintf(handle->errstream, "Unhandled encoding: %s\n", buf); break; } buf = "<Content-Length Unspecified>"; Uint32 len = 0; if(!prop->get("Content-Length", &len)){ - ndbout_c("Invalid response: %s\n", buf); + fprintf(handle->errstream, "Invalid response: %s\n\n", buf); break; } @@ -1751,14 +1763,14 @@ ndb_mgm_get_configuration(NdbMgmHandle handle, unsigned int version) { const int res = base64_decode(buf64, len-1, tmp); delete[] buf64; if(res != 0){ - ndbout_c("Failed to decode buffer"); + fprintf(handle->errstream, "Failed to decode buffer\n"); break; } ConfigValuesFactory cvf; const int res2 = cvf.unpack(tmp); if(!res2){ - ndbout_c("Failed to unpack buffer"); + fprintf(handle->errstream, "Failed to unpack buffer\n"); break; } @@ -1868,7 +1880,7 @@ ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, int nodetype) } Uint32 _nodeid; if(!prop->get("nodeid", &_nodeid) != 0){ - ndbout_c("ERROR Message: <nodeid Unspecified>\n"); + fprintf(handle->errstream, "ERROR Message: <nodeid Unspecified>\n"); break; } nodeid= _nodeid; @@ -1944,7 +1956,7 @@ ndb_mgm_set_int_parameter(NdbMgmHandle handle, do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } res= 0; @@ -1987,7 +1999,7 @@ ndb_mgm_set_int64_parameter(NdbMgmHandle handle, do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } res= 0; @@ -2030,7 +2042,7 @@ ndb_mgm_set_string_parameter(NdbMgmHandle handle, do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } res= 0; @@ -2067,7 +2079,7 @@ ndb_mgm_purge_stale_sessions(NdbMgmHandle handle, char **purged){ do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } if (purged) { @@ -2149,7 +2161,7 @@ ndb_mgm_set_connection_int_parameter(NdbMgmHandle handle, do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } res= 0; @@ -2191,14 +2203,14 @@ ndb_mgm_get_connection_int_parameter(NdbMgmHandle handle, do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ - ndbout_c("ERROR Message: %s\n", buf); + fprintf(handle->errstream, "ERROR Message: %s\n", buf); break; } res= 0; } while(0); if(!prop->get("value",(Uint32*)value)){ - ndbout_c("Unable to get value"); + fprintf(handle->errstream, "Unable to get value\n"); res = -4; } @@ -2250,7 +2262,7 @@ ndb_mgm_get_mgmd_nodeid(NdbMgmHandle handle) CHECK_REPLY(prop, 0); if(!prop->get("nodeid",&nodeid)){ - ndbout_c("Unable to get value"); + fprintf(handle->errstream, "Unable to get value\n"); return 0; } diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index b1fe0735612..3df878065a7 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -62,8 +62,6 @@ ConfigInfo::m_sectionNames[]={ DB_TOKEN, MGM_TOKEN, API_TOKEN, - "REP", - "EXTERNAL REP", "TCP", "SCI", @@ -100,6 +98,7 @@ static bool saveInConfigValues(InitConfigFileParser::Context & ctx, const char * static bool fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data); static bool fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data); static bool fixShmUniqueId(InitConfigFileParser::Context & ctx, const char * data); +static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const char * data); const ConfigInfo::SectionRule ConfigInfo::m_SectionRules[] = { @@ -110,8 +109,6 @@ ConfigInfo::m_SectionRules[] = { { DB_TOKEN, transformNode, 0 }, { API_TOKEN, transformNode, 0 }, { MGM_TOKEN, transformNode, 0 }, - { "REP", transformNode, 0 }, - { "EXTERNAL REP", transformExtNode, 0 }, { MGM_TOKEN, fixShmUniqueId, 0 }, @@ -128,8 +125,6 @@ ConfigInfo::m_SectionRules[] = { { DB_TOKEN, fixNodeHostname, 0 }, { API_TOKEN, fixNodeHostname, 0 }, { MGM_TOKEN, fixNodeHostname, 0 }, - { "REP", fixNodeHostname, 0 }, - //{ "EXTERNAL REP", fixNodeHostname, 0 }, { "TCP", fixNodeId, "NodeId1" }, { "TCP", fixNodeId, "NodeId2" }, @@ -168,6 +163,10 @@ ConfigInfo::m_SectionRules[] = { { "*", fixDepricated, 0 }, { "*", applyDefaultValues, "system" }, + { DB_TOKEN, checkLocalhostHostnameMix, 0 }, + { API_TOKEN, checkLocalhostHostnameMix, 0 }, + { MGM_TOKEN, checkLocalhostHostnameMix, 0 }, + { DB_TOKEN, fixFileSystemPath, 0 }, { DB_TOKEN, fixBackupDataDir, 0 }, @@ -193,7 +192,6 @@ ConfigInfo::m_SectionRules[] = { { DB_TOKEN, saveInConfigValues, 0 }, { API_TOKEN, saveInConfigValues, 0 }, { MGM_TOKEN, saveInConfigValues, 0 }, - { "REP", saveInConfigValues, 0 }, { "TCP", saveInConfigValues, 0 }, { "SHM", saveInConfigValues, 0 }, @@ -345,17 +343,6 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { 0, 0 }, { - CFG_SYS_REPLICATION_ROLE, - "ReplicationRole", - "SYSTEM", - "Role in Global Replication (None, Primary, or Standby)", - ConfigInfo::CI_USED, - false, - ConfigInfo::CI_STRING, - UNDEFINED, - 0, 0 }, - - { CFG_SYS_PRIMARY_MGM_NODE, "PrimaryMGMNode", "SYSTEM", @@ -402,7 +389,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INTERNAL, false, ConfigInfo::CI_STRING, - UNDEFINED, + "localhost", 0, 0 }, { @@ -928,7 +915,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { STR_VALUE(MAX_INT_RNIL) }, { - KEY_INTERNAL, + CFG_DB_LCP_DISC_PAGES_TUP_SR, "NoOfDiskPagesToDiskDuringRestartTUP", DB_TOKEN, "?", @@ -940,7 +927,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { STR_VALUE(MAX_INT_RNIL) }, { - KEY_INTERNAL, + CFG_DB_LCP_DISC_PAGES_TUP, "NoOfDiskPagesToDiskAfterRestartTUP", DB_TOKEN, "?", @@ -952,7 +939,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { STR_VALUE(MAX_INT_RNIL) }, { - KEY_INTERNAL, + CFG_DB_LCP_DISC_PAGES_ACC_SR, "NoOfDiskPagesToDiskDuringRestartACC", DB_TOKEN, "?", @@ -964,7 +951,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { STR_VALUE(MAX_INT_RNIL) }, { - KEY_INTERNAL, + CFG_DB_LCP_DISC_PAGES_ACC, "NoOfDiskPagesToDiskAfterRestartACC", DB_TOKEN, "?", @@ -1219,78 +1206,6 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { STR_VALUE(MAX_INT_RNIL) }, /*************************************************************************** - * REP - ***************************************************************************/ - { - CFG_SECTION_NODE, - "REP", - "REP", - "Node section", - ConfigInfo::CI_USED, - false, - ConfigInfo::CI_SECTION, - (const char *)NODE_TYPE_REP, - 0, 0 - }, - - { - CFG_NODE_HOST, - "HostName", - "REP", - "Name of computer for this node", - ConfigInfo::CI_INTERNAL, - false, - ConfigInfo::CI_STRING, - UNDEFINED, - 0, 0 }, - - { - CFG_NODE_SYSTEM, - "System", - "REP", - "Name of system for this node", - ConfigInfo::CI_INTERNAL, - false, - ConfigInfo::CI_STRING, - UNDEFINED, - 0, 0 }, - - { - CFG_NODE_ID, - "Id", - "REP", - "Number identifying replication node (REP)", - ConfigInfo::CI_USED, - false, - ConfigInfo::CI_INT, - MANDATORY, - "1", - STR_VALUE(MAX_NODES) }, - - { - KEY_INTERNAL, - "ExecuteOnComputer", - "REP", - "String referencing an earlier defined COMPUTER", - ConfigInfo::CI_USED, - false, - ConfigInfo::CI_STRING, - MANDATORY, - 0, 0 }, - - { - CFG_REP_HEARTBEAT_INTERVAL, - "HeartbeatIntervalRepRep", - "REP", - "Time between REP-REP heartbeats. Connection closed after 3 missed HBs", - ConfigInfo::CI_USED, - true, - ConfigInfo::CI_INT, - "3000", - "100", - STR_VALUE(MAX_INT_RNIL) }, - - /*************************************************************************** * API ***************************************************************************/ { @@ -1313,7 +1228,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INTERNAL, false, ConfigInfo::CI_STRING, - UNDEFINED, + "", 0, 0 }, { @@ -1433,7 +1348,7 @@ const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = { ConfigInfo::CI_INTERNAL, false, ConfigInfo::CI_STRING, - UNDEFINED, + "", 0, 0 }, { @@ -2464,7 +2379,15 @@ ConfigInfo::isSection(const char * section) const { } const char* -ConfigInfo::getAlias(const char * section) const { +ConfigInfo::nameToAlias(const char * name) { + for (int i = 0; m_sectionNameAliases[i].name != 0; i++) + if(!strcasecmp(name, m_sectionNameAliases[i].name)) + return m_sectionNameAliases[i].alias; + return 0; +} + +const char* +ConfigInfo::getAlias(const char * section) { for (int i = 0; m_sectionNameAliases[i].name != 0; i++) if(!strcasecmp(section, m_sectionNameAliases[i].alias)) return m_sectionNameAliases[i].name; @@ -2623,7 +2546,7 @@ transformNode(InitConfigFileParser::Context & ctx, const char * data){ return true; } -static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx) +static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const char * data) { DBUG_ENTER("checkLocalhostHostnameMix"); const char * hostname= 0; @@ -2643,7 +2566,7 @@ static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx) } if (localhost_used) { - ctx.reportError("Mixing of localhost with other hostname(%s) is illegal", + ctx.reportError("Mixing of localhost (default for [NDBD]HostName) with other hostname(%s) is illegal", hostname); DBUG_RETURN(false); } @@ -2652,21 +2575,17 @@ static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx) } bool -fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data){ - +fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data) +{ const char * hostname; + DBUG_ENTER("fixNodeHostname"); + if (ctx.m_currentSection->get("HostName", &hostname)) - return checkLocalhostHostnameMix(ctx); + DBUG_RETURN(checkLocalhostHostnameMix(ctx,0)); const char * compId; - if(!ctx.m_currentSection->get("ExecuteOnComputer", &compId)){ - const char * type; - if(ctx.m_currentSection->get("Type", &type) && strcmp(type,DB_TOKEN) == 0) - require(ctx.m_currentSection->put("HostName", "localhost")); - else - require(ctx.m_currentSection->put("HostName", "")); - return checkLocalhostHostnameMix(ctx); - } + if(!ctx.m_currentSection->get("ExecuteOnComputer", &compId)) + DBUG_RETURN(true); const Properties * computer; char tmp[255]; @@ -2675,18 +2594,18 @@ fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data){ ctx.reportError("Computer \"%s\" not declared" "- [%s] starting at line: %d", compId, ctx.fname, ctx.m_sectionLineno); - return false; + DBUG_RETURN(false); } if(!computer->get("HostName", &hostname)){ ctx.reportError("HostName missing in [COMPUTER] (Id: %d) " " - [%s] starting at line: %d", compId, ctx.fname, ctx.m_sectionLineno); - return false; + DBUG_RETURN(false); } require(ctx.m_currentSection->put("HostName", hostname)); - return checkLocalhostHostnameMix(ctx); + DBUG_RETURN(checkLocalhostHostnameMix(ctx,0)); } bool @@ -2870,7 +2789,7 @@ transformComputer(InitConfigFileParser::Context & ctx, const char * data){ return true; } - return checkLocalhostHostnameMix(ctx); + return checkLocalhostHostnameMix(ctx,0); } /** @@ -2878,7 +2797,9 @@ transformComputer(InitConfigFileParser::Context & ctx, const char * data){ */ void applyDefaultValues(InitConfigFileParser::Context & ctx, - const Properties * defaults){ + const Properties * defaults) +{ + DBUG_ENTER("applyDefaultValues"); if(defaults != NULL){ Properties::Iterator it(defaults); @@ -2891,26 +2812,58 @@ applyDefaultValues(InitConfigFileParser::Context & ctx, Uint32 val = 0; ::require(defaults->get(name, &val)); ctx.m_currentSection->put(name, val); + DBUG_PRINT("info",("%s=%d #default",name,val)); break; } case ConfigInfo::CI_INT64:{ Uint64 val = 0; ::require(defaults->get(name, &val)); ctx.m_currentSection->put64(name, val); + DBUG_PRINT("info",("%s=%lld #default",name,val)); break; } case ConfigInfo::CI_STRING:{ const char * val; ::require(defaults->get(name, &val)); ctx.m_currentSection->put(name, val); + DBUG_PRINT("info",("%s=%s #default",name,val)); break; } case ConfigInfo::CI_SECTION: break; } } +#ifndef DBUG_OFF + else + { + switch (ctx.m_info->getType(ctx.m_currentInfo, name)){ + case ConfigInfo::CI_INT: + case ConfigInfo::CI_BOOL:{ + Uint32 val = 0; + ::require(ctx.m_currentSection->get(name, &val)); + DBUG_PRINT("info",("%s=%d",name,val)); + break; + } + case ConfigInfo::CI_INT64:{ + Uint64 val = 0; + ::require(ctx.m_currentSection->get(name, &val)); + DBUG_PRINT("info",("%s=%lld",name,val)); + break; + } + case ConfigInfo::CI_STRING:{ + const char * val; + ::require(ctx.m_currentSection->get(name, &val)); + DBUG_PRINT("info",("%s=%s",name,val)); + break; + } + case ConfigInfo::CI_SECTION: + break; + } + } +#endif } } + DBUG_VOID_RETURN; } bool @@ -3482,6 +3435,8 @@ fixDepricated(InitConfigFileParser::Context & ctx, const char * data){ return true; } +extern int g_print_full_config; + static bool saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){ const Properties * sec; @@ -3503,6 +3458,12 @@ saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){ break; } + if (g_print_full_config) + { + const char *alias= ConfigInfo::nameToAlias(ctx.fname); + printf("[%s]\n", alias ? alias : ctx.fname); + } + Uint32 no = 0; ctx.m_userProperties.get("$Section", id, &no); ctx.m_userProperties.put("$Section", id, no+1, true); @@ -3530,18 +3491,24 @@ saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){ Uint32 val; require(ctx.m_currentSection->get(n, &val)); ok = ctx.m_configValues.put(id, val); + if (g_print_full_config) + printf("%s=%u\n", n, val); break; } case PropertiesType_Uint64:{ Uint64 val; require(ctx.m_currentSection->get(n, &val)); ok = ctx.m_configValues.put64(id, val); + if (g_print_full_config) + printf("%s=%llu\n", n, val); break; } case PropertiesType_char:{ const char * val; require(ctx.m_currentSection->get(n, &val)); ok = ctx.m_configValues.put(id, val); + if (g_print_full_config) + printf("%s=%s\n", n, val); break; } default: diff --git a/ndb/src/mgmsrv/ConfigInfo.hpp b/ndb/src/mgmsrv/ConfigInfo.hpp index dff8b34bf4a..788619db7fe 100644 --- a/ndb/src/mgmsrv/ConfigInfo.hpp +++ b/ndb/src/mgmsrv/ConfigInfo.hpp @@ -105,7 +105,8 @@ public: * @note Result is not defined if section/name are wrong! */ bool verify(const Properties* secti, const char* fname, Uint64 value) const; - const char* getAlias(const char*) const; + static const char* nameToAlias(const char*); + static const char* getAlias(const char*); bool isSection(const char*) const; const char* getDescription(const Properties * sec, const char* fname) const; @@ -126,14 +127,14 @@ private: Properties m_info; Properties m_systemDefaults; - static const ParamInfo m_ParamInfo[]; - static const int m_NoOfParams; - static const AliasPair m_sectionNameAliases[]; static const char* m_sectionNames[]; static const int m_noOfSectionNames; public: + static const ParamInfo m_ParamInfo[]; + static const int m_NoOfParams; + static const SectionRule m_SectionRules[]; static const ConfigRule m_ConfigRules[]; static const int m_NoOfRules; diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 07b369d4ebc..ec20101493e 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -121,6 +121,7 @@ struct MgmGlobals { }; int g_no_nodeid_checks= 0; +int g_print_full_config; static MgmGlobals *glob= 0; /****************************************************************************** @@ -147,6 +148,9 @@ static struct my_option my_long_options[] = { "config-file", 'f', "Specify cluster configuration file", (gptr*) &opt_config_filename, (gptr*) &opt_config_filename, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "print-full-config", 'P', "Print full config and exit", + (gptr*) &g_print_full_config, (gptr*) &g_print_full_config, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "daemon", 'd', "Run ndb_mgmd in daemon mode (default)", (gptr*) &opt_daemon, (gptr*) &opt_daemon, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, @@ -208,7 +212,8 @@ int main(int argc, char** argv) exit(ho_error); if (opt_interactive || - opt_non_interactive) { + opt_non_interactive || + g_print_full_config) { opt_daemon= 0; } @@ -220,6 +225,9 @@ int main(int argc, char** argv) opt_config_filename, opt_connect_str); + if (g_print_full_config) + goto the_end; + if (glob->mgmObject->init()) goto error_end; @@ -358,6 +366,7 @@ int main(int argc, char** argv) glob->mgmObject->get_config_retriever()->disconnect(); glob->socketServer->stopSessions(true); g_eventLogger.info("Shutdown complete"); + the_end: delete glob; ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); return 0; diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp index ef9367ef10e..42b7c5b115d 100644 --- a/ndb/src/ndbapi/ClusterMgr.cpp +++ b/ndb/src/ndbapi/ClusterMgr.cpp @@ -214,7 +214,7 @@ ClusterMgr::threadMain( ){ * It is now time to send a new Heartbeat */ if (theNode.hbCounter >= theNode.hbFrequency) { - theNode.hbSent++; + theNode.m_info.m_heartbeat_cnt++; theNode.hbCounter = 0; } @@ -231,7 +231,7 @@ ClusterMgr::threadMain( ){ theFacade.sendSignalUnCond(&signal, nodeId); }//if - if (theNode.hbSent == 4 && theNode.hbFrequency > 0){ + if (theNode.m_info.m_heartbeat_cnt == 4 && theNode.hbFrequency > 0){ reportNodeFailed(i); }//if } @@ -337,7 +337,7 @@ ClusterMgr::execAPI_REGCONF(const Uint32 * theData){ node.compatible = ndbCompatible_api_ndb(NDB_VERSION, node.m_info.m_version); } - + node.m_state = apiRegConf->nodeState; if (node.compatible && (node.m_state.startLevel == NodeState::SL_STARTED || node.m_state.startLevel == NodeState::SL_SINGLEUSER)){ @@ -345,7 +345,7 @@ ClusterMgr::execAPI_REGCONF(const Uint32 * theData){ } else { set_node_alive(node, false); }//if - node.hbSent = 0; + node.m_info.m_heartbeat_cnt = 0; node.hbCounter = 0; if (node.m_info.m_type != NodeInfo::REP) { node.hbFrequency = (apiRegConf->apiHeartbeatFrequency * 10) - 50; @@ -414,7 +414,7 @@ ClusterMgr::reportConnected(NodeId nodeId){ Node & theNode = theNodes[nodeId]; theNode.connected = true; - theNode.hbSent = 0; + theNode.m_info.m_heartbeat_cnt = 0; theNode.hbCounter = 0; /** diff --git a/ndb/src/ndbapi/ClusterMgr.hpp b/ndb/src/ndbapi/ClusterMgr.hpp index d75b820e9cb..da8f16d6789 100644 --- a/ndb/src/ndbapi/ClusterMgr.hpp +++ b/ndb/src/ndbapi/ClusterMgr.hpp @@ -73,12 +73,12 @@ public: */ Uint32 hbFrequency; // Heartbeat frequence Uint32 hbCounter; // # milliseconds passed since last hb sent - Uint32 hbSent; // # heartbeats sent (without answer) }; const Node & getNodeInfo(NodeId) const; Uint32 getNoOfConnectedNodes() const; - + void hb_received(NodeId); + private: Uint32 noOfAliveNodes; Uint32 noOfConnectedNodes; @@ -128,6 +128,12 @@ ClusterMgr::getNoOfConnectedNodes() const { return noOfConnectedNodes; } +inline +void +ClusterMgr::hb_received(NodeId nodeId) { + theNodes[nodeId].m_info.m_heartbeat_cnt= 0; +} + /*****************************************************************************/ /** diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 34d1614d043..eccd175b1b9 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1244,6 +1244,7 @@ objectStateMapping[] = { { DictTabInfo::StateBuilding, NdbDictionary::Object::StateBuilding }, { DictTabInfo::StateDropping, NdbDictionary::Object::StateDropping }, { DictTabInfo::StateOnline, NdbDictionary::Object::StateOnline }, + { DictTabInfo::StateBackup, NdbDictionary::Object::StateBackup }, { DictTabInfo::StateBroken, NdbDictionary::Object::StateBroken }, { -1, -1 } }; diff --git a/ndb/src/ndbapi/TransporterFacade.cpp b/ndb/src/ndbapi/TransporterFacade.cpp index 96f376db5a5..b143f1a9944 100644 --- a/ndb/src/ndbapi/TransporterFacade.cpp +++ b/ndb/src/ndbapi/TransporterFacade.cpp @@ -126,6 +126,10 @@ reportDisconnect(void * callbackObj, NodeId nodeId, Uint32 error){ //TransporterFacade::instance()->reportDisconnected(nodeId); } +void +transporter_recv_from(void * callbackObj, NodeId nodeId){ + ((TransporterFacade*)(callbackObj))->hb_received(nodeId); +} /**************************************************************************** * diff --git a/ndb/src/ndbapi/TransporterFacade.hpp b/ndb/src/ndbapi/TransporterFacade.hpp index e74f4b51e00..fa070889dd9 100644 --- a/ndb/src/ndbapi/TransporterFacade.hpp +++ b/ndb/src/ndbapi/TransporterFacade.hpp @@ -114,6 +114,9 @@ public: TransporterRegistry* get_registry() { return theTransporterRegistry;}; + // heart beat received from a node (e.g. a signal came) + void hb_received(NodeId n); + private: /** * Send a signal unconditional of node status (used by ClusterMgr) @@ -296,6 +299,12 @@ TransporterFacade::get_node_alive(NodeId n) const { } inline +void +TransporterFacade::hb_received(NodeId n) { + theClusterMgr->hb_received(n); +} + +inline bool TransporterFacade::get_node_stopping(NodeId n) const { const ClusterMgr::Node & node = theClusterMgr->getNodeInfo(n); diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 840d358f225..ad5523d32eb 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -344,6 +344,8 @@ ErrorBundle ErrorCodes[] = { { 743, SE, "Unsupported character set in table or index" }, { 744, SE, "Character string is invalid for given character set" }, { 745, SE, "Distribution key not supported for char attribute (use binary attribute)" }, + { 761, SE, "Unable to drop table as backup is in progress" }, + { 762, SE, "Unable to alter table as backup is in progress" }, { 241, SE, "Invalid schema object version" }, { 283, SE, "Table is being dropped" }, { 284, SE, "Table not defined in transaction coordinator" }, diff --git a/ndb/test/include/HugoOperations.hpp b/ndb/test/include/HugoOperations.hpp index 05137710609..82fd5529fa2 100644 --- a/ndb/test/include/HugoOperations.hpp +++ b/ndb/test/include/HugoOperations.hpp @@ -41,6 +41,15 @@ public: int numRecords = 1, int updatesValue = 0); + int pkWriteRecord(Ndb*, + int recordNo, + int numRecords = 1, + int updatesValue = 0); + + int pkWritePartialRecord(Ndb*, + int recordNo, + int numRecords = 1); + int pkReadRecord(Ndb*, int recordNo, int numRecords = 1, @@ -97,6 +106,10 @@ public: NdbIndexScanOperation* pIndexScanOp; NDBT_ResultRow& get_row(Uint32 idx) { return *rows[idx];} + + int execute_async(Ndb*, NdbTransaction::ExecType, NdbTransaction::AbortOption = NdbTransaction::AbortOnError); + int wait_async(Ndb*, int timeout = -1); + protected: void allocRows(int rows); void deallocRows(); @@ -109,6 +122,11 @@ protected: struct RsPair { NdbScanOperation* m_result_set; int records; }; Vector<RsPair> m_result_sets; Vector<RsPair> m_executed_result_sets; + + int m_async_reply; + int m_async_return; + friend void HugoOperations_async_callback(int, NdbTransaction*, void*); + void callback(int res, NdbTransaction*); }; #endif diff --git a/ndb/test/include/UtilTransactions.hpp b/ndb/test/include/UtilTransactions.hpp index afdbc5c3445..333f5d98328 100644 --- a/ndb/test/include/UtilTransactions.hpp +++ b/ndb/test/include/UtilTransactions.hpp @@ -28,6 +28,8 @@ public: UtilTransactions(Ndb* ndb, const char * tableName, const char * indexName = 0); + int closeTransaction(Ndb*); + int clearTable(Ndb*, int records = 0, int parallelism = 0); diff --git a/ndb/test/ndbapi/testBackup.cpp b/ndb/test/ndbapi/testBackup.cpp index 7a6f11a6bb9..1ab348e735f 100644 --- a/ndb/test/ndbapi/testBackup.cpp +++ b/ndb/test/ndbapi/testBackup.cpp @@ -138,6 +138,61 @@ int runBackupOne(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } +int +runBackupLoop(NDBT_Context* ctx, NDBT_Step* step){ + NdbBackup backup(GETNDB(step)->getNodeId()+1); + unsigned backupId = 0; + + int loops = ctx->getNumLoops(); + while(!ctx->isTestStopped() && loops--) + { + if (backup.start(backupId) == -1) + { + sleep(1); + loops++; + } + else + { + sleep(3); + } + } + + ctx->stopTest(); + return NDBT_OK; +} + +int +runDDL(NDBT_Context* ctx, NDBT_Step* step){ + Ndb* pNdb= GETNDB(step); + NdbDictionary::Dictionary* pDict = pNdb->getDictionary(); + + const int tables = NDBT_Tables::getNumTables(); + while(!ctx->isTestStopped()) + { + const int tab_no = rand() % (tables); + NdbDictionary::Table tab = *NDBT_Tables::getTable(tab_no); + BaseString name= tab.getName(); + name.appfmt("-%d", step->getStepNo()); + tab.setName(name.c_str()); + if(pDict->createTable(tab) == 0) + { + HugoTransactions hugoTrans(* pDict->getTable(name.c_str())); + if (hugoTrans.loadTable(pNdb, 10000) != 0){ + return NDBT_FAILED; + } + + while(pDict->dropTable(tab.getName()) != 0 && + pDict->getNdbError().code != 4009) + g_err << pDict->getNdbError() << endl; + + sleep(1); + + } + } + return NDBT_OK; +} + + int runRestartInitial(NDBT_Context* ctx, NDBT_Step* step){ NdbRestarter restarter; @@ -417,6 +472,15 @@ TESTCASE("BackupOne", VERIFIER(runVerifyOne); FINALIZER(runClearTable); } +TESTCASE("BackupDDL", + "Test that backup and restore works on with DDL ongoing\n" + "1. Backups and DDL (create,drop,table.index)"){ + INITIALIZER(runLoadTable); + STEP(runBackupLoop); + STEP(runDDL); + STEP(runDDL); + FINALIZER(runClearTable); +} TESTCASE("BackupBank", "Test that backup and restore works during transaction load\n" " by backing up the bank" diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index 137a1d51d82..f456d852898 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -1037,6 +1037,8 @@ int runCheckGetNdbErrorOperation(NDBT_Context* ctx, NDBT_Step* step){ return result; } +#define C2(x) { int _x= (x); if(_x == 0){ ndbout << "line: " << __LINE__ << endl; return NDBT_FAILED;} } + int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; const NdbDictionary::Table* pTab = ctx->getTab(); @@ -1044,228 +1046,98 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){ HugoOperations hugoOps(*pTab); Ndb* pNdb = GETNDB(step); - Uint32 lm; - - NdbConnection* pCon = pNdb->startTransaction(); - if (pCon == NULL){ - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - NdbOperation* pOp = pCon->getNdbOperation(pTab->getName()); - if (pOp == NULL){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - if (pOp->readTuple(NdbOperation::LM_Exclusive) != 0){ - pNdb->closeTransaction(pCon); - ERR(pOp->getNdbError()); - return NDBT_FAILED; - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() == true){ - if(hugoOps.equalForAttr(pOp, a, 1) != 0){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() != true){ - if (pOp->getValue(pTab->getColumn(a)->getName()) == NULL) { - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - int check = pCon->execute(NoCommit); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } - - pOp = pCon->getNdbOperation(pTab->getName()); - if (pOp == NULL){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - if (pOp->deleteTuple() != 0){ - pNdb->closeTransaction(pCon); - ERR(pOp->getNdbError()); - return NDBT_FAILED; - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() == true){ - if(hugoOps.equalForAttr(pOp, a, 1) != 0){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - check = pCon->execute(NoCommit); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkReadRecord(pNdb, 0, 1, NdbOperation::LM_Exclusive) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + + Ndb ndb2(&ctx->m_cluster_connection, "TEST_DB"); + C2(ndb2.init() == 0); + C2(ndb2.waitUntilReady() == 0); + HugoOperations hugoOps2(*pTab); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps2.startTransaction(&ndb2) == 0); + C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0); + C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps2.wait_async(&ndb2) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + C2(hugoOps2.closeTransaction(&ndb2) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps2.startTransaction(&ndb2) == 0); + C2(hugoOps2.pkWriteRecord(&ndb2, 0, 1) == 0); + C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps2.wait_async(&ndb2) == 0); + C2(hugoOps2.execute_Commit(pNdb) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + C2(hugoOps2.closeTransaction(&ndb2) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkUpdateRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps2.startTransaction(&ndb2) == 0); + C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0); + C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps2.wait_async(&ndb2) == 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + C2(hugoOps2.closeTransaction(&ndb2) == 0); + + C2(hugoOps.startTransaction(pNdb) == 0); + C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0); + C2(hugoOps.execute_NoCommit(pNdb) == 0); + C2(hugoOps2.startTransaction(&ndb2) == 0); + C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0); + C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0); + C2(hugoOps.execute_Commit(pNdb) == 0); + C2(hugoOps2.wait_async(&ndb2) != 0); + C2(hugoOps.closeTransaction(pNdb) == 0); + C2(hugoOps2.closeTransaction(&ndb2) == 0); - pOp = pCon->getNdbOperation(pTab->getName()); - if (pOp == NULL){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - if (pOp->writeTuple() != 0){ - pNdb->closeTransaction(pCon); - ERR(pOp->getNdbError()); - return NDBT_FAILED; - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() == true){ - if(hugoOps.equalForAttr(pOp, a, 1) != 0){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() != true){ - if(hugoOps.setValueForAttr(pOp, a, 1, 1) != 0) - { - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - check = pCon->execute(NoCommit); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } - - pOp = pCon->getNdbOperation(pTab->getName()); - if (pOp == NULL){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - if (pOp->writeTuple() != 0){ - pNdb->closeTransaction(pCon); - ERR(pOp->getNdbError()); - return NDBT_FAILED; - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() == true){ - if(hugoOps.equalForAttr(pOp, a, 1) != 0){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() != true){ - if(hugoOps.setValueForAttr(pOp, a, 1, 1) != 0) - { - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - check = pCon->execute(NoCommit); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } - - check = pCon->execute(Rollback); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } - - pCon->close(); - - pCon = pNdb->startTransaction(); - if (pCon == NULL){ - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - pOp = pCon->getNdbOperation(pTab->getName()); - if (pOp == NULL){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - - if (pOp->writeTuple() != 0){ - pNdb->closeTransaction(pCon); - ERR(pOp->getNdbError()); - return NDBT_FAILED; - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() == true){ - if(hugoOps.equalForAttr(pOp, a, 1) != 0){ - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - for(int a = 0; a<pTab->getNoOfColumns(); a++){ - if (pTab->getColumn(a)->getPrimaryKey() != true){ - if(hugoOps.setValueForAttr(pOp, a, 1, 1) != 0) - { - ERR(pCon->getNdbError()); - pNdb->closeTransaction(pCon); - return NDBT_FAILED; - } - } - } - - check = pCon->execute(Commit); - if (check == 0){ - ndbout << "execute worked" << endl; - } else { - ERR(pCon->getNdbError()); - result = NDBT_FAILED; - } - return result; } @@ -1442,7 +1314,6 @@ TESTCASE("ReadWithoutGetValue", } TESTCASE("Bug_11133", "Test ReadEx-Delete-Write\n"){ - INITIALIZER(runLoadTable); INITIALIZER(runBug_11133); FINALIZER(runClearTable); } diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index 5d7d7f58f89..8b44594a9b5 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -54,6 +54,10 @@ max-time: 600 cmd: atrt-testBackup args: -n BackupOne T1 T6 T3 I3 +max-time: 600 +cmd: atrt-testBackup +args: -n BackupDDL T1 + # BASIC FUNCTIONALITY max-time: 500 cmd: testBasic diff --git a/ndb/test/run-test/ndb-autotest.sh b/ndb/test/run-test/ndb-autotest.sh index 573a9953924..4228d2354d3 100755 --- a/ndb/test/run-test/ndb-autotest.sh +++ b/ndb/test/run-test/ndb-autotest.sh @@ -84,7 +84,7 @@ fi for i in $vars do t=`echo echo \\$$i` - if [ -z `eval $t` ] + if [ -z "`eval $t`" ] then echo "Invalid config: $conf, variable $i is not set" exit @@ -301,8 +301,8 @@ choose_conf(){ echo "$test_dir/conf-$1.txt" else echo "Unable to find conf file looked for" 1>&2 - echo "$testdir/conf-$1-$HOST.txt and" 1>&2 - echo "$testdir/conf-$1.txt" 1>&2 + echo "$test_dir/conf-$1-$HOST.txt and" 1>&2 + echo "$test_dir/conf-$1.txt" 1>&2 exit fi } diff --git a/ndb/test/src/HugoOperations.cpp b/ndb/test/src/HugoOperations.cpp index f9a09eddd1f..f2e54971766 100644 --- a/ndb/test/src/HugoOperations.cpp +++ b/ndb/test/src/HugoOperations.cpp @@ -16,7 +16,6 @@ #include <HugoOperations.hpp> - int HugoOperations::startTransaction(Ndb* pNdb){ if (pTrans != NULL){ @@ -54,11 +53,7 @@ HugoOperations::setTransactionId(Uint64 id){ int HugoOperations::closeTransaction(Ndb* pNdb){ - if (pTrans != NULL){ - pNdb->closeTransaction(pTrans); - pTrans = NULL; - } - pTrans = NULL; + UtilTransactions::closeTransaction(pNdb); m_result_sets.clear(); m_executed_result_sets.clear(); @@ -226,6 +221,79 @@ int HugoOperations::pkInsertRecord(Ndb* pNdb, return NDBT_OK; } +int HugoOperations::pkWriteRecord(Ndb* pNdb, + int recordNo, + int numRecords, + int updatesValue){ + + int a, check; + for(int r=0; r < numRecords; r++){ + NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + + check = pOp->writeTuple(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + + // Define primary keys + for(a = 0; a<tab.getNoOfColumns(); a++){ + if (tab.getColumn(a)->getPrimaryKey() == true){ + if(equalForAttr(pOp, a, r+recordNo) != 0){ + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + } + } + + // Define attributes to update + for(a = 0; a<tab.getNoOfColumns(); a++){ + if (tab.getColumn(a)->getPrimaryKey() == false){ + if(setValueForAttr(pOp, a, recordNo+r, updatesValue ) != 0){ + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + } + } + } + return NDBT_OK; +} + +int HugoOperations::pkWritePartialRecord(Ndb* pNdb, + int recordNo, + int numRecords){ + + int a, check; + for(int r=0; r < numRecords; r++){ + NdbOperation* pOp = pTrans->getNdbOperation(tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + + check = pOp->writeTuple(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + + // Define primary keys + for(a = 0; a<tab.getNoOfColumns(); a++){ + if (tab.getColumn(a)->getPrimaryKey() == true){ + if(equalForAttr(pOp, a, r+recordNo) != 0){ + ERR(pTrans->getNdbError()); + return NDBT_FAILED; + } + } + } + } + return NDBT_OK; +} + int HugoOperations::pkDeleteRecord(Ndb* pNdb, int recordNo, int numRecords){ @@ -367,6 +435,57 @@ int HugoOperations::execute_Rollback(Ndb* pNdb){ return NDBT_OK; } +void +HugoOperations_async_callback(int res, NdbTransaction* pCon, void* ho) +{ + ((HugoOperations*)ho)->callback(res, pCon); +} + +void +HugoOperations::callback(int res, NdbTransaction* pCon) +{ + assert(pCon == pTrans); + m_async_reply= 1; + if(res) + { + m_async_return = pCon->getNdbError().code; + } + else + { + m_async_return = 0; + } +} + +int +HugoOperations::execute_async(Ndb* pNdb, NdbTransaction::ExecType et, + NdbTransaction::AbortOption eao){ + + m_async_reply= 0; + pTrans->executeAsynchPrepare(et, + HugoOperations_async_callback, + this, + eao); + + pNdb->sendPreparedTransactions(); + + return NDBT_OK; +} + +int +HugoOperations::wait_async(Ndb* pNdb, int timeout) +{ + pNdb->pollNdb(1000); + + if(m_async_reply) + { + if(m_async_return) + ndbout << "ERROR: " << pNdb->getNdbError(m_async_return) << endl; + return m_async_return; + } + ndbout_c("wait returned nothing..."); + return -1; +} + HugoOperations::HugoOperations(const NdbDictionary::Table& _tab, const NdbDictionary::Index* idx): UtilTransactions(_tab, idx), @@ -376,7 +495,8 @@ HugoOperations::HugoOperations(const NdbDictionary::Table& _tab, HugoOperations::~HugoOperations(){ deallocRows(); - if (pTrans != NULL){ + if (pTrans != NULL) + { pTrans->close(); pTrans = NULL; } @@ -508,7 +628,7 @@ int HugoOperations::compareRecordToCopy(int numRecords ){ void HugoOperations::refresh() { - NdbConnection* t = getTransaction(); + NdbTransaction * t = getTransaction(); if(t) t->refresh(); } diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index 65c1a7ded31..31c323045ed 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -109,7 +109,7 @@ UtilTransactions::clearTable3(Ndb* pNdb, err = pTrans->getNdbError(); if(err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); par = 1; goto restart; @@ -126,7 +126,7 @@ UtilTransactions::clearTable3(Ndb* pNdb, err = pTrans->getNdbError(); if(err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); continue; } @@ -150,7 +150,7 @@ UtilTransactions::clearTable3(Ndb* pNdb, if(check == -1){ if(err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); par = 1; goto restart; @@ -162,20 +162,20 @@ UtilTransactions::clearTable3(Ndb* pNdb, err = pTrans->getNdbError(); if(err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); par = 1; goto restart; } goto failed; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } return NDBT_FAILED; failed: - if(pTrans != 0) pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); ERR(err); return (err.code != 0 ? err.code : NDBT_FAILED); } @@ -219,20 +219,20 @@ UtilTransactions::copyTableData(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp->readTuples(NdbScanOperation::LM_Read, parallelism) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -241,7 +241,7 @@ UtilTransactions::copyTableData(Ndb* pNdb, if ((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -249,7 +249,7 @@ UtilTransactions::copyTableData(Ndb* pNdb, check = pTrans->execute(NoCommit); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -258,7 +258,7 @@ UtilTransactions::copyTableData(Ndb* pNdb, do { insertedRows++; if (addRowToInsert(pNdb, pTrans, row, destName) != 0){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } while((eof = pOp->nextResult(false)) == 0); @@ -268,7 +268,7 @@ UtilTransactions::copyTableData(Ndb* pNdb, if( check == -1 ) { const NdbError err = pTrans->getNdbError(); ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -277,7 +277,7 @@ UtilTransactions::copyTableData(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); // If error = 488 there should be no limit on number of retry attempts if (err.code != 488) @@ -285,11 +285,11 @@ UtilTransactions::copyTableData(Ndb* pNdb, continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); g_info << insertedRows << " rows copied" << endl; @@ -375,7 +375,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, pOp = getScanOperation(pTrans); if (pOp == NULL) { const NdbError err = pNdb->getNdbError(); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); if (err.status == NdbError::TemporaryError){ ERR(err); @@ -389,14 +389,14 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, if( pOp->readTuples(lm, 0, parallelism) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -408,7 +408,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, if ((row.attributeStore(attrib_list[a]) = pOp->getValue(tab.getColumn(attrib_list[a])->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -421,13 +421,13 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -447,17 +447,17 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); g_info << rows << " rows have been read" << endl; if (records != 0 && rows != records){ g_info << "Check expected number of records failed" << endl @@ -496,13 +496,13 @@ UtilTransactions::selectCount(Ndb* pNdb, pOp = getScanOperation(pTrans); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp->readTuples(lm) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -515,7 +515,7 @@ UtilTransactions::selectCount(Ndb* pNdb, check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -524,7 +524,7 @@ UtilTransactions::selectCount(Ndb* pNdb, check = pTrans->execute(NoCommit); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -539,17 +539,17 @@ UtilTransactions::selectCount(Ndb* pNdb, const NdbError err = pTrans->getNdbError(); if (err.status == NdbError::TemporaryError){ - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); if (count_rows != NULL){ *count_rows = rows; @@ -653,7 +653,7 @@ restart: pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { const NdbError err = pNdb->getNdbError(); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); ERR(err); if (err.status == NdbError::TemporaryError){ @@ -673,14 +673,14 @@ restart: if( rs != 0 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -689,7 +689,7 @@ restart: if ((row.attributeStore(a) = pOp->getValue(tab.getColumn(a)->getName())) == 0) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -700,13 +700,13 @@ restart: if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -733,13 +733,13 @@ restart: if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; goto restart; } } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -748,17 +748,17 @@ restart: if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } @@ -1057,20 +1057,20 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if( pOp->readTuples(NdbScanOperation::LM_Read, 0, parallelism) ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } check = pOp->interpret_exit_ok(); if( check == -1 ) { ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1085,13 +1085,13 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1146,7 +1146,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, g_err << "Error when comapring records" << endl; g_err << " scanRow: \n" << scanRow.c_str().c_str() << endl; g_err << " pkRow: \n" << pkRow.c_str().c_str() << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1156,7 +1156,7 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, if((res= iop->nextResult()) != 0){ g_err << "Failed to find row using index: " << res << endl; ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } @@ -1164,14 +1164,14 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, g_err << "Error when comapring records" << endl; g_err << " scanRow: \n" << scanRow.c_str().c_str() << endl; g_err << " indexRow: \n" << indexRow.c_str().c_str() << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } if(iop->nextResult() == 0){ g_err << "Found extra row!!" << endl; g_err << " indexRow: \n" << indexRow.c_str().c_str() << endl; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } } @@ -1184,18 +1184,18 @@ UtilTransactions::verifyOrderedIndex(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ ERR(err); iop = 0; - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); NdbSleep_MilliSleep(50); retryAttempt++; rows--; continue; } ERR(err); - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_FAILED; } - pNdb->closeTransaction(pTrans); + closeTransaction(pNdb); return NDBT_OK; } @@ -1303,6 +1303,16 @@ UtilTransactions::getOperation(NdbConnection* pTrans, #include <HugoOperations.hpp> +int +UtilTransactions::closeTransaction(Ndb* pNdb) +{ + if (pTrans != NULL){ + pNdb->closeTransaction(pTrans); + pTrans = NULL; + } + return 0; +} + int UtilTransactions::compare(Ndb* pNdb, const char* tab_name2, int flags){ @@ -1313,7 +1323,6 @@ UtilTransactions::compare(Ndb* pNdb, const char* tab_name2, int flags){ HugoCalculator calc(tab); NDBT_ResultRow row(tab); - NdbTransaction* pTrans= 0; const NdbDictionary::Table* tmp= pNdb->getDictionary()->getTable(tab_name2); if(tmp == 0) { diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 1008b166dfc..0ad8a01b9e2 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -9,7 +9,7 @@ ndbtools_PROGRAMS = \ ndb_show_tables \ ndb_select_all \ ndb_select_count \ - ndb_restore + ndb_restore ndb_config tools_common_sources = ../test/src/NDBT_ReturnCodes.cpp \ ../test/src/NDBT_Table.cpp \ @@ -33,6 +33,17 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/Restore.cpp \ ../test/src/NDBT_ResultRow.cpp $(tools_common_sources) +ndb_config_SOURCES = config.cpp \ + ../src/mgmsrv/Config.cpp \ + ../src/mgmsrv/ConfigInfo.cpp \ + ../src/mgmsrv/InitConfigFileParser.cpp + +ndb_config_CXXFLAGS = -I$(top_srcdir)/ndb/src/mgmapi \ + -I$(top_srcdir)/ndb/src/mgmsrv \ + -I$(top_srcdir)/ndb/include/mgmcommon \ + -DMYSQLCLUSTERDIR="\"\"" + + include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_ndbapitools.mk.am @@ -46,6 +57,7 @@ ndb_show_tables_LDFLAGS = @ndb_bin_am_ldflags@ ndb_select_all_LDFLAGS = @ndb_bin_am_ldflags@ ndb_select_count_LDFLAGS = @ndb_bin_am_ldflags@ ndb_restore_LDFLAGS = @ndb_bin_am_ldflags@ +ndb_config_LDFLAGS = @ndb_bin_am_ldflags@ # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/tools/config.cpp b/ndb/tools/config.cpp new file mode 100644 index 00000000000..7944f66f71c --- /dev/null +++ b/ndb/tools/config.cpp @@ -0,0 +1,407 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * ndb_config --nodes --query=nodeid --type=ndbd --host=local1 + */ + +#include <ndb_global.h> +#include <my_sys.h> +#include <my_getopt.h> +#include <mysql_version.h> + +#include <NdbOut.hpp> +#include <mgmapi.h> +#include <mgmapi_configuration.hpp> +#include <ConfigInfo.hpp> + +static int g_verbose = 0; +static int try_reconnect = 3; + +static int g_nodes = 1; +static const char * g_connectstring = 0; +static const char * g_query = 0; + +static int g_nodeid = 0; +static const char * g_type = 0; +static const char * g_host = 0; +static const char * g_field_delimiter=","; +static const char * g_row_delimiter=" "; + +int g_print_full_config, opt_ndb_shm; + +typedef ndb_mgm_configuration_iterator Iter; + +static void ndb_std_print_version() +{ + printf("MySQL distrib %s, for %s (%s)\n", + MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); +} + +static struct my_option my_long_options[] = +{ + { "usage", '?', "Display this help and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "help", '?', "Display this help and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "version", 'V', "Output version information and exit.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "ndb-connectstring", 256, + "Set connect string for connecting to ndb_mgmd. " + "Syntax: \"[nodeid=<id>;][host=]<hostname>[:<port>]\". " + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", + (gptr*) &g_connectstring, (gptr*) &g_connectstring, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "nodes", 256, "Print nodes", + (gptr*) &g_nodes, (gptr*) &g_nodes, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + { "query", 'q', "Query option(s)", + (gptr*) &g_query, (gptr*) &g_query, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "host", 257, "Host", + (gptr*) &g_host, (gptr*) &g_host, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "type", 258, "Type of node/connection", + (gptr*) &g_type, (gptr*) &g_type, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "id", 258, "Nodeid", + (gptr*) &g_nodeid, (gptr*) &g_nodeid, + 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "nodeid", 258, "Nodeid", + (gptr*) &g_nodeid, (gptr*) &g_nodeid, + 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "fields", 'f', "Field separator", + (gptr*) &g_field_delimiter, (gptr*) &g_field_delimiter, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "rows", 'r', "Row separator", + (gptr*) &g_row_delimiter, (gptr*) &g_row_delimiter, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + +static void usage() +{ + char desc[] = + "This program will retreive config options for a ndb cluster\n"; + ndb_std_print_version(); + my_print_help(my_long_options); + my_print_variables(my_long_options); +} +static my_bool +ndb_std_get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch (optid) { + case 'V': + ndb_std_print_version(); + exit(0); + case '?': + usage(); + exit(0); + } + return 0; +} + +/** + * Match/Apply framework + */ +struct Match +{ + int m_key; + BaseString m_value; + virtual int eval(NdbMgmHandle, const Iter&); +}; + +struct Apply +{ + Apply() {} + Apply(int val) { m_key = val;} + int m_key; + virtual int apply(NdbMgmHandle, const Iter&); +}; + +struct NodeTypeApply : public Apply +{ + virtual int apply(NdbMgmHandle, const Iter&); +}; + +static int parse_query(Vector<Apply*>&, int &argc, char**& argv); +static int parse_where(Vector<Match*>&, int &argc, char**& argv); +static int eval(NdbMgmHandle, const Iter&, const Vector<Match*>&); +static int apply(NdbMgmHandle, const Iter&, const Vector<Apply*>&); +int +main(int argc, char** argv){ + NDB_INIT(argv[0]); + const char *load_default_groups[]= { "mysql_cluster",0 }; + load_defaults("my",load_default_groups,&argc,&argv); + int ho_error; + if ((ho_error=handle_options(&argc, &argv, my_long_options, + ndb_std_get_one_option))) + return -1; + + NdbMgmHandle mgm = ndb_mgm_create_handle(); + if(mgm == NULL) { + fprintf(stderr, "Cannot create handle to management server.\n"); + exit(-1); + } + + ndb_mgm_set_error_stream(mgm, stderr); + + if (ndb_mgm_set_connectstring(mgm, g_connectstring)) + { + fprintf(stderr, "* %5d: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + fprintf(stderr, + "* %s", ndb_mgm_get_latest_error_desc(mgm)); + exit(-1); + } + + if(ndb_mgm_connect(mgm, try_reconnect-1, 5, 1)) + { + fprintf(stderr, "Connect failed"); + fprintf(stderr, " code: %d, msg: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + exit(-1); + } + else if(g_verbose) + { + fprintf(stderr, "Connected to %s:%d\n", + ndb_mgm_get_connected_host(mgm), + ndb_mgm_get_connected_port(mgm)); + } + + ndb_mgm_configuration * conf = ndb_mgm_get_configuration(mgm, 0); + if(conf == 0) + { + fprintf(stderr, "Could not get configuration"); + fprintf(stderr, "code: %d, msg: %s\n", + ndb_mgm_get_latest_error(mgm), + ndb_mgm_get_latest_error_msg(mgm)); + exit(-1); + } + else if(g_verbose) + { + fprintf(stderr, "Fetched configuration\n"); + } + + Vector<Apply*> select_list; + Vector<Match*> where_clause; + + if(strcmp(g_row_delimiter, "\\n") == 0) + g_row_delimiter = "\n"; + if(strcmp(g_field_delimiter, "\\n") == 0) + g_field_delimiter = "\n"; + + if(parse_query(select_list, argc, argv)) + { + exit(0); + } + + if(parse_where(where_clause, argc, argv)) + { + exit(0); + } + + Iter iter(* conf, CFG_SECTION_NODE); + bool prev= false; + iter.first(); + for(iter.first(); iter.valid(); iter.next()) + { + if(eval(mgm, iter, where_clause)) + { + if(prev) + printf("%s", g_row_delimiter); + prev= true; + apply(mgm, iter, select_list); + } + } + printf("\n"); + return 0; +} + +static +int +parse_query(Vector<Apply*>& select, int &argc, char**& argv) +{ + if(g_query) + { + BaseString q(g_query); + Vector<BaseString> list; + q.split(list, ","); + for(unsigned i = 0; i<list.size(); i++) + { + const char * str= list[i].c_str(); + if(strcasecmp(str, "id") == 0 || strcasecmp(str, "nodeid") == 0) + select.push_back(new Apply(CFG_NODE_ID)); + else if(strncasecmp(str, "host", 4) == 0) + select.push_back(new Apply(CFG_NODE_HOST)); + else if(strcasecmp(str, "type") == 0) + select.push_back(new NodeTypeApply()); + else if(g_nodes) + { + bool found = false; + for(int p = 0; p<ConfigInfo::m_NoOfParams; p++) + { + if(0)ndbout_c("%s %s", + ConfigInfo::m_ParamInfo[p]._section, + ConfigInfo::m_ParamInfo[p]._fname); + if(strcmp(ConfigInfo::m_ParamInfo[p]._section, "DB") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "API") == 0 || + strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0) + { + if(strcasecmp(ConfigInfo::m_ParamInfo[p]._fname, str) == 0) + { + select.push_back(new Apply(ConfigInfo::m_ParamInfo[p]._paramId)); + found = true; + break; + } + } + } + if(!found) + { + fprintf(stderr, "Unknown query option: %s\n", str); + return 1; + } + } + else + { + fprintf(stderr, "Unknown query option: %s\n", str); + return 1; + } + } + } + return 0; +} + +static +int +parse_where(Vector<Match*>& where, int &argc, char**& argv) +{ + Match m; + if(g_host) + { + m.m_key = CFG_NODE_HOST; + m.m_value.assfmt("%s", g_host); + where.push_back(new Match(m)); + } + + if(g_type) + { + m.m_key = CFG_TYPE_OF_SECTION; + m.m_value.assfmt("%d", ndb_mgm_match_node_type(g_type)); + where.push_back(new Match(m)); + } + + if(g_nodeid) + { + m.m_key = CFG_NODE_ID; + m.m_value.assfmt("%d", g_nodeid); + where.push_back(new Match(m)); + } + return 0; +} + +template class Vector<Apply*>; +template class Vector<Match*>; + +static +int +eval(NdbMgmHandle mgm, const Iter& iter, const Vector<Match*>& where) +{ + for(unsigned i = 0; i<where.size(); i++) + { + if(where[i]->eval(mgm, iter) == 0) + return 0; + } + + return 1; +} + +static +int +apply(NdbMgmHandle mgm, const Iter& iter, const Vector<Apply*>& list) +{ + for(unsigned i = 0; i<list.size(); i++) + { + list[i]->apply(mgm, iter); + if(i + 1 != list.size()) + printf("%s", g_field_delimiter); + } + return 0; +} + +int +Match::eval(NdbMgmHandle h, const Iter& iter) +{ + Uint32 val32; + Uint64 val64; + const char* valc; + if (iter.get(m_key, &val32) == 0) + { + if(atoi(m_value.c_str()) != val32) + return 0; + } + else if(iter.get(m_key, &val64) == 0) + { + if(atoll(m_value.c_str()) != val64) + return 0; + } + else if(iter.get(m_key, &valc) == 0) + { + if(strcmp(m_value.c_str(), valc) != 0) + return 0; + } + else + { + return 0; + } + return 1; +} + +int +Apply::apply(NdbMgmHandle h, const Iter& iter) +{ + Uint32 val32; + Uint64 val64; + const char* valc; + if (iter.get(m_key, &val32) == 0) + { + printf("%u", val32); + } + else if(iter.get(m_key, &val64) == 0) + { + printf("%llu", val64); + } + else if(iter.get(m_key, &valc) == 0) + { + printf("%s", valc); + } + return 0; +} + +int +NodeTypeApply::apply(NdbMgmHandle h, const Iter& iter) +{ + Uint32 val32; + if (iter.get(CFG_TYPE_OF_SECTION, &val32) == 0) + { + printf("%s", ndb_mgm_get_node_type_alias_string((ndb_mgm_node_type)val32, 0)); + } + return 0; +} diff --git a/ndb/tools/drop_index.cpp b/ndb/tools/drop_index.cpp index e2bf7f0bfae..24116f22784 100644 --- a/ndb/tools/drop_index.cpp +++ b/ndb/tools/drop_index.cpp @@ -35,7 +35,7 @@ static struct my_option my_long_options[] = static void usage() { char desc[] = - "<indexname>+\n"\ + "[<table> <index>]+\n"\ "This program will drop index(es) in Ndb\n"; ndb_std_print_version(); my_print_help(my_long_options); @@ -76,10 +76,10 @@ int main(int argc, char** argv){ } int res = 0; - for(int i = 0; i<argc; i++){ - ndbout << "Dropping index " << argv[i] << "..."; + for(int i = 0; i+1<argc; i += 2){ + ndbout << "Dropping index " << argv[i] << "/" << argv[i+1] << "..."; int tmp; - if((tmp = MyNdb.getDictionary()->dropIndex(argv[i], 0)) != 0){ + if((tmp = MyNdb.getDictionary()->dropIndex(argv[i+1], argv[i])) != 0){ ndbout << endl << MyNdb.getDictionary()->getNdbError() << endl; res = tmp; } else { diff --git a/ndb/tools/listTables.cpp b/ndb/tools/listTables.cpp index b4a2235f73b..fa078f7d351 100644 --- a/ndb/tools/listTables.cpp +++ b/ndb/tools/listTables.cpp @@ -131,6 +131,9 @@ list(const char * tabname, case NdbDictionary::Object::StateOnline: strcpy(state, "Online"); break; + case NdbDictionary::Object::StateBackup: + strcpy(state, "Backup"); + break; case NdbDictionary::Object::StateBroken: strcpy(state, "Broken"); break; diff --git a/ndb/tools/restore/Restore.cpp b/ndb/tools/restore/Restore.cpp index b53255820db..60fbf7f8ceb 100644 --- a/ndb/tools/restore/Restore.cpp +++ b/ndb/tools/restore/Restore.cpp @@ -646,7 +646,7 @@ bool RestoreDataIterator::readFragmentHeader(int & ret) } info << "_____________________________________________________" << endl - << "Restoring data in table: " << m_currentTable->getTableName() + << "Processing data in table: " << m_currentTable->getTableName() << "(" << Header.TableId << ") fragment " << Header.FragmentNo << endl; diff --git a/ndb/tools/restore/consumer_printer.hpp b/ndb/tools/restore/consumer_printer.hpp index 7cbc924e364..e47bc56f874 100644 --- a/ndb/tools/restore/consumer_printer.hpp +++ b/ndb/tools/restore/consumer_printer.hpp @@ -29,6 +29,8 @@ public: m_print_log = false; m_print_data = false; m_print_meta = false; + m_logCount = 0; + m_dataCount = 0; } virtual bool table(const TableS &); diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index d980f29057b..62fccfa3082 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -318,7 +318,7 @@ main(int argc, char** argv) if (ga_restore || ga_print) { - if (ga_restore) + if(_restore_data || _print_data) { RestoreDataIterator dataIter(metaData, &free_data_callback); @@ -365,7 +365,10 @@ main(int argc, char** argv) for (i= 0; i < g_consumers.size(); i++) g_consumers[i]->endOfTuples(); + } + if(_restore_data || _print_log) + { RestoreLogIterator logIter(metaData); if (!logIter.readHeader()) { @@ -389,6 +392,10 @@ main(int argc, char** argv) logIter.validateFooter(); //not implemented for (i= 0; i < g_consumers.size(); i++) g_consumers[i]->endOfLogEntrys(); + } + + if(_restore_data) + { for(i = 0; i<metaData.getNoOfTables(); i++) { if (checkSysTable(metaData[i]->getTableName())) diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 225e8bdccbb..474ebedda62 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -35,10 +35,13 @@ bin_SCRIPTS = @server_scripts@ \ mysqld_multi \ mysql_create_system_tables +noinst_SCRIPTS = make_binary_distribution \ + make_sharedlib_distribution \ + make_win_src_distribution + EXTRA_SCRIPTS = make_binary_distribution.sh \ make_sharedlib_distribution.sh \ make_win_src_distribution.sh \ - make_win_binary_distribution.sh \ msql2mysql.sh \ mysql_config.sh \ mysql_fix_privilege_tables.sh \ @@ -147,5 +150,3 @@ SUFFIXES = .sh # Don't update the files from bitkeeper %::SCCS/s.% - -all: make_win_src_distribution make_binary_distribution make_sharedlib_distribution diff --git a/scripts/make_win_binary_distribution.sh b/scripts/make_win_binary_distribution.sh deleted file mode 100644 index c611454450c..00000000000 --- a/scripts/make_win_binary_distribution.sh +++ /dev/null @@ -1,185 +0,0 @@ -#!/bin/sh - -# -# Script to create a Windows binary package -# -# This is intended to be used under Cygwin, and will generate -# an archive named in the form mysql<suffix>-<version>-noinstall.zip - -version=@VERSION@ - -DEBUG=0 -SUFFIX="" -DIRNAME="" -EXTRA="" - -# -# This script must run from MySQL top directory -# - -if [ ! -f scripts/make_win_binary_distribution ]; then - echo "ERROR : You must run this script from the MySQL top-level directory" - exit 1 -fi - -# -# Debug print of the status -# - -print_debug() -{ - for statement - do - if [ "$DEBUG" = "1" ] ; then - echo $statement - fi - done -} - -# -# Usage of the script -# - -show_usage() -{ - echo "MySQL utility script to create a Windows binary package" - echo "" - echo "This is intended to be used under Cygwin, and will generate" - echo "an archive named in the form mysql<suffix>-<version>-noinstall.zip" - echo "Takes the following arguments:" - echo "" - echo " --dirname Directory to use for copying files" - echo " --extra Directory to get extra files from" - echo " --suffix Name to append to 'mysql' for this binary" - echo " --help Show this help message" - exit 0 -} - -# -# Parse the input arguments -# - -parse_arguments() { - for arg do - case "$arg" in - --debug) DEBUG=1;; - --extra=*) EXTRA=`echo "$arg" | sed -e "s;--extra=;;"` ;; - --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; - --dirname=*) DIRNAME=`echo "$arg" | sed -e "s;--dirname=;;"` ;; - --help) show_usage ;; - *) - echo "Unknown argument '$arg'" - exit 1 - ;; - esac - done -} - -parse_arguments "$@" - -if [ -z "$DIRNAME" ]; then - $DIRNAME="dist" -fi - -print_debug "Making directories" -mkdir $DIRNAME -$DIRNAME="$DIRNAME/mysql-$version" -mkdir $DIRNAME - -for dir in bin lib lib/opt lib/debug Embedded Embedded/DLL Embedded/DLL/debug Embedded/DLL/release Embedded/static Embedded/static/release examples examples/libmysqltest -do - mkdir $DIRNAME/$dir -done - -if [ $EXTRA ]; then - print_debug "Copying extra files" - cp -fr $EXTRA/* $DIRNAME -fi - -# Dirs to be copied as-is -for dir in data Docs include scripts share -do - print_debug "Copying $dir to $DIRNAME/" - cp -fr $dir $DIRNAME -done - -print_debug "Copying tests to $DIRNAME/examples/" -cp -fr tests $DIRNAME/examples - -print_debug "Copying sql-bench to $DIRNAME/bench" -mkdir $DIRNAME/bench -cp -fr sql-bench/* $DIRNAME/bench - -print_debug "Copying mysql-test to $DIRNAME/mysql-test" -mkdir $DIRNAME/mysql-test -cp -fr mysql-test/* $DIRNAME/mysql-test - -print_debug "Copying support-files to $DIRNAME" -cp support-files/* $DIRNAME - -# Files for bin -for i in client_release/* client_debug/mysqld.exe lib_release/libmySQL.dll -do - print_debug "Copying $i to $DIRNAME/bin" - cp $i $DIRNAME/bin -done - -# Files for include -for i in libmysql/libmysql.def libmysqld/libmysqld.def -do - print_debug "Copying $i to $DIRNAME/include" - cp $i $DIRNAME/include -done - -# Windows users are used to having dbug.h ? -cp include/my_dbug.h $DIRNAME/include/dbug.h - -# Libraries found in lib_release and lib_debug -for i in libmySQL.dll libmysql.lib zlib.lib mysqlclient.lib mysys.lib regex.lib strings.lib -do - print_debug "Copying lib_release/$i to $DIRNAME/lib/opt" - cp lib_release/$i $DIRNAME/lib/opt - print_debug "Copying lib_debug/$i to $DIRNAME/lib/debug" - cp lib_debug/$i $DIRNAME/lib/debug -done - -print_debug "Copying lib_release/mysys-max.lib to $DIRNAME/lib/opt" -cp lib_release/mysys-max.lib $DIRNAME/lib/opt - -# Embedded server -for i in libmysqld.dll libmysqld.lib libmysqld.exp -do - print_debug "Copying lib_release/$i to $DIRNAME/Embedded/DLL/release" - cp lib_release/$i $DIRNAME/Embedded/DLL/release - print_debug "Copying lib_debug/$i to $DIRNAME/Embedded/DLL/debug" - cp lib_debug/$i $DIRNAME/Embedded/DLL/debug -done - -# Static embedded -print_debug "Copying lib_release/mysqlserver.lib to $DIRNAME/Embedded/static/release" -cp lib_release/mysqlserver.lib $DIRNAME/Embedded/static/release - -# libmysqltest -for i in mytest.c mytest.dsp mytest.dsw mytest.exe -do - print_debug "Copying libmysqltest/release/$i to $DIRNAME/examples/libmysqltest" - cp libmysqltest/release/$i $DIRNAME/examples/libmysqltest -done - -print_debug "Copying README.txt" -cp README.txt $DIRNAME - -if [ -f MySQLEULA.txt ]; then - print_debug "Commercial version: copying MySQLEULA.txt" - cp MySQLEULA.txt $DIRNAME - rm $DIRNAME/Docs/COPYING -else - print_debug "GPL version: copying COPYING" - cp Docs/COPYING $DIRNAME -fi - -print_debug "Invoking zip to package the binary" -zip -r mysql$SUFFIX-$version-win-noinstall.zip $DIRNAME - -print_debug "Deleting intermediate directory" -rm -rf $DIRNAME diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 3a06c4d1fb5..873aff251db 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -106,29 +106,47 @@ parse_arguments() { } +# +# First, try to find BASEDIR and ledir (where mysqld is) +# + MY_PWD=`pwd` -# Check if we are starting this relative (for the binary release) -if test -f ./share/mysql/english/errmsg.sys -a \ - -x ./bin/mysqld +# Check for the directories we would expect from a binary release install +if test -f ./share/mysql/english/errmsg.sys -a -x ./bin/mysqld then MY_BASEDIR_VERSION=$MY_PWD # Where bin, share and data are ledir=$MY_BASEDIR_VERSION/bin # Where mysqld is +# Check for the directories we would expect from a source install +elif test -f ./share/mysql/english/errmsg.sys -a \ + -x ./libexec/mysqld +then + MY_BASEDIR_VERSION=$MY_PWD # Where libexec, share and var are + ledir=$MY_BASEDIR_VERSION/libexec # Where mysqld is +# Since we didn't find anything, used the compiled-in defaults +else + MY_BASEDIR_VERSION=@prefix@ + ledir=@libexecdir@ +fi + +# +# Second, try to find the data directory +# + +# Try where the binary installs put it +if test -d $MY_BASEDIR_VERSION/data/mysql +then DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then defaults="--defaults-extra-file=$DATADIR/my.cnf" fi -# Check if this is a 'moved install directory' -elif test -f ./share/mysql/english/errmsg.sys -a \ - -x ./libexec/mysqld +# Next try where the source installs put it +elif test -d $MY_BASEDIR_VERSION/var/mysql then - MY_BASEDIR_VERSION=$MY_PWD # Where libexec, share and var are - ledir=$MY_BASEDIR_VERSION/libexec # Where mysqld is DATADIR=$MY_BASEDIR_VERSION/var +# Or just give up and use our compiled-in default else - MY_BASEDIR_VERSION=@prefix@ DATADIR=@localstatedir@ - ledir=@libexecdir@ fi if test -z "$MYSQL_HOME" diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am index 2788aef8f82..68c9d5b7d18 100644 --- a/server-tools/instance-manager/Makefile.am +++ b/server-tools/instance-manager/Makefile.am @@ -34,6 +34,7 @@ liboptions_a_CXXFLAGS= $(CXXFLAGS) \ -DDEFAULT_MYSQLD_PATH="$(libexecdir)/mysqld$(EXEEXT)" \ -DDEFAULT_MONITORING_INTERVAL="20" \ -DDEFAULT_PORT="2273" \ + -DDEFAULT_CONFIG_FILE="/etc/my.cnf" \ -DPROTOCOL_VERSION=@PROTOCOL_VERSION@ liboptions_a_SOURCES= options.h options.cc priv.h priv.cc diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc index 2357f97fd93..ad9d46be1ed 100644 --- a/server-tools/instance-manager/commands.cc +++ b/server-tools/instance-manager/commands.cc @@ -22,6 +22,7 @@ #include "mysql_manager_error.h" #include "protocol.h" #include "buffer.h" +#include "options.h" #include <m_string.h> #include <mysql.h> @@ -643,6 +644,7 @@ Set_option::Set_option(Instance_map *instance_map_arg, if ((instance= instance_map->find(name, len))) { instance_name= instance->options.instance_name; + /* add prefix for add_option */ if ((option_len_arg < MAX_OPTION_LEN - 1) || (option_value_len_arg < MAX_OPTION_LEN - 1)) @@ -689,15 +691,22 @@ int Set_option::correct_file(int skip) { int error; - error= modify_defaults_file("/etc/my.cnf", option, - option_value, instance_name, skip); - if (error > 0) + error= modify_defaults_file(Options::config_file, option, + option_value, instance_name, skip); + + switch (error) + { + case 0: + return 0; /* everything was fine */ + case 1: return ER_OUT_OF_RESOURCES; - else if (error < 0) + case 2: return ER_ACCESS_OPTION_FILE; + default: + DBUG_ASSERT(0); /* should never get here */ + } - /* everything was fine */ - return 0; + return 0; /* keep compiler happy */ } diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index fa8a5d58114..7356d79e27a 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -22,6 +22,8 @@ #include "buffer.h" #include "instance.h" +#include "log.h" +#include "options.h" #include <m_ctype.h> #include <mysql_com.h> @@ -111,9 +113,8 @@ err_new_instance: C_MODE_END -Instance_map::Instance_map(const char *default_mysqld_path_arg, - const char *first_option_arg): -mysqld_path(default_mysqld_path_arg), first_option(first_option_arg) +Instance_map::Instance_map(const char *default_mysqld_path_arg): +mysqld_path(default_mysqld_path_arg) { pthread_mutex_init(&LOCK_instance_map, 0); } @@ -202,7 +203,8 @@ int Instance_map::complete_initialization() hash_free should handle it's deletion => goto err, not err_instance. */ - if (instance->complete_initialization(this, mysqld_path, DEFAULT_SINGLE_INSTANCE)) + if (instance->complete_initialization(this, mysqld_path, + DEFAULT_SINGLE_INSTANCE)) goto err; } else @@ -236,18 +238,18 @@ int Instance_map::load() /* the name of the program may be orbitrary here in fact */ argv_options[0]= "mysqlmanager"; - if (first_option != NULL) - { - argc= 2; - argv_options[1]= first_option; - argv_options[2]= '\0'; - } - else - argv_options[1]= '\0'; - - if (my_search_option_files("my", &argc, (char ***) &argv, &args_used, - process_option, (void*) this) || - complete_initialization()) + argv_options[1]= '\0'; + + /* + If the routine failed, we'll simply fallback to defaults in + complete_initialization(). + */ + if (my_search_option_files(Options::config_file, &argc, + (char ***) &argv, &args_used, + process_option, (void*) this)) + log_info("Falling back to compiled-in defaults"); + + if (complete_initialization()) return 1; return 0; diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h index 46247c82a16..666a16c7040 100644 --- a/server-tools/instance-manager/instance_map.h +++ b/server-tools/instance-manager/instance_map.h @@ -64,8 +64,7 @@ public: int unlock(); int init(); - Instance_map(const char *default_mysqld_path_arg, - const char *first_option_arg); + Instance_map(const char *default_mysqld_path_arg); ~Instance_map(); /* loads options from config files */ @@ -80,7 +79,6 @@ public: Guardian_thread *guardian; private: - const char *first_option; enum { START_HASH_SIZE = 16 }; pthread_mutex_t LOCK_instance_map; HASH hash; diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index a4c81739b17..2bb887716b0 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -68,7 +68,7 @@ void manager(const Options &options) */ User_map user_map; - Instance_map instance_map(options.default_mysqld_path, options.first_option); + Instance_map instance_map(options.default_mysqld_path); Guardian_thread guardian_thread(thread_registry, &instance_map, options.monitoring_interval); diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index 5a6c398614b..8693b3c590f 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) if (set_user(options.user, user_info)) { options.cleanup(); - return 1; + goto err; } } diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index e44e4c6ff34..34a9a0792e9 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -36,7 +36,7 @@ const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); const char *Options::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH); -const char *Options::first_option= 0; /* No default value */ +const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE); const char *Options::bind_address= 0; /* No default value */ const char *Options::user= 0; /* No default value */ uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL; @@ -143,7 +143,12 @@ static void usage() printf("Usage: %s [OPTIONS] \n", my_progname); my_print_help(my_long_options); - print_defaults("my", default_groups); + printf("\nThe following options may be given as the first argument:\n" + "--print-defaults Print the program argument list and exit\n" + "--defaults-file=# Only read manager configuration and instance\n" + " setings from the given file #. The same file\n" + " will be used to modify configuration of instances\n" + " with SET commands.\n"); my_print_variables(my_long_options); } @@ -204,31 +209,48 @@ C_MODE_END /* - - call load_defaults to load configuration file section + - Process argv of original program: get tid of --defaults-extra-file + and print a message if met there. + - call load_defaults to load configuration file section and save the pointer + for free_defaults. - call handle_options to assign defaults and command-line arguments - to the class members - if either of these function fail, exit the program - May not return. + to the class members. + if either of these function fail, return the error code. */ int Options::load(int argc, char **argv) { - int rc; + saved_argv= argv; if (argc >= 2) { - if (is_prefix(argv[1],"--defaults-file=") || - is_prefix(argv[1],"--defaults-extra-file=")) - Options::first_option= argv[1]; + if (is_prefix(argv[1], "--defaults-file=")) + { + Options::config_file= strchr(argv[1], '=') + 1; + } + if (is_prefix(argv[1], "--defaults-extra-file=") || + is_prefix(argv[1], "--no-defaults")) + { + /* the log is not enabled yet */ + fprintf(stderr, "The --defaults-extra-file and --no-defaults options" + " are not supported by\n" + "Instance Manager. Program aborted.\n"); + goto err; + } } /* config-file options are prepended to command-line ones */ - load_defaults("my", default_groups, &argc, &argv); - Options::saved_argv= argv; + load_defaults(config_file, default_groups, &argc, + &saved_argv); + + if ((handle_options(&argc, &saved_argv, my_long_options, + get_one_option)) != 0) + goto err; - if ((rc= handle_options(&argc, &argv, my_long_options, get_one_option)) != 0) - return rc; return 0; + +err: + return 1; } void Options::cleanup() diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index 3df259864be..761d366dfb4 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -36,11 +36,12 @@ struct Options static const char *default_mysqld_path; static const char *user; /* the option which should be passed to process_default_option_files */ - static const char *first_option; static uint monitoring_interval; static uint port_number; static const char *bind_address; + static const char *config_file; + /* argv pointer returned by load_defaults() to be used by free_defaults() */ static char **saved_argv; static int load(int argc, char **argv); diff --git a/sql-common/client.c b/sql-common/client.c index 4ecc8d26fc7..4ec919553c6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2206,14 +2206,22 @@ my_bool mysql_reconnect(MYSQL *mysql) tmp_mysql.rpl_pivot = mysql->rpl_pivot; if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, - mysql->client_flag | CLIENT_REMEMBER_OPTIONS) || - mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) + mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) { mysql->net.last_errno= tmp_mysql.net.last_errno; strmov(mysql->net.last_error, tmp_mysql.net.last_error); strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); DBUG_RETURN(1); } + if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) + { + mysql_close(&tmp_mysql); + mysql->net.last_errno= tmp_mysql.net.last_errno; + strmov(mysql->net.last_error, tmp_mysql.net.last_error); + strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); + DBUG_RETURN(1); + } + tmp_mysql.reconnect= 1; tmp_mysql.free_me= mysql->free_me; diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 1078259f15d..c00c0e7be83 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -56,11 +56,14 @@ uint calc_days_in_year(uint year) } /* - check date. + Check datetime value for validity according to flags. - SYNOPOSIS - bool check_date() - time Date to check. + SYNOPSIS + check_date() + ltime - Date to check. + not_zero_date - ltime is not the zero date + flags - flags to check + was_cut - set to whether the value was truncated NOTES Here we assume that year and month is ok ! @@ -69,18 +72,35 @@ uint calc_days_in_year(uint year) RETURN 0 ok - 1 errro + 1 error */ -bool check_date(MYSQL_TIME *ltime) +bool check_date(const MYSQL_TIME *ltime, bool not_zero_date, ulong flags, + int *was_cut) { - if (ltime->month && ltime->day > days_in_month[ltime->month-1]) + + if (not_zero_date) { - if (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 || - ltime->day != 29) - return 1; + if ((((flags & TIME_NO_ZERO_IN_DATE) || !(flags & TIME_FUZZY_DATE)) && + (ltime->month == 0 || ltime->day == 0)) || + (!(flags & TIME_INVALID_DATES) && + ltime->month && ltime->day > days_in_month[ltime->month-1] && + (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 || + ltime->day != 29))) + { + *was_cut= 2; + return TRUE; + } } - return 0; + else if (flags & TIME_NO_ZERO_DATE) + { + /* + We don't set *was_cut here to signal that the problem was a zero date + and not an invalid date + */ + return TRUE; + } + return FALSE; } @@ -100,7 +120,7 @@ bool check_date(MYSQL_TIME *ltime) TIME_INVALID_DATES Allow 2000-02-31 was_cut 0 Value ok 1 If value was cut during conversion - 2 Date part was withing ranges but date was wrong + 2 Date part was within ranges but date was wrong DESCRIPTION At least the following formats are recogniced (based on number of digits) @@ -168,8 +188,6 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, *was_cut= 1; DBUG_RETURN(MYSQL_TIMESTAMP_NONE); } - if (flags & TIME_NO_ZERO_IN_DATE) - flags&= ~TIME_FUZZY_DATE; is_internal_format= 0; /* This has to be changed if want to activate different timestamp formats */ @@ -385,22 +403,10 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, if (year_length == 2 && not_zero_date) l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); - if (!not_zero_date && (flags & TIME_NO_ZERO_DATE)) - { - /* - We don't set *was_cut here to signal that the problem was a zero date - and not an invalid date - */ - goto err; - } - if (number_of_fields < 3 || l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || - l_time->minute > 59 || l_time->second > 59 || - (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || - l_time->day == 0) && - not_zero_date)) + l_time->minute > 59 || l_time->second > 59) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) /* If zero date */ @@ -418,15 +424,12 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, goto err; } + if (check_date(l_time, not_zero_date, flags, was_cut)) + goto err; + l_time->time_type= (number_of_fields <= 3 ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME); - if (not_zero_date && !(flags & TIME_INVALID_DATES) && check_date(l_time)) - { - *was_cut= 2; /* Not correct date */ - goto err; - } - for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) @@ -881,9 +884,10 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to) number_to_datetime() nr - datetime value as number time_res - pointer for structure for broken-down representation - fuzzy_date - indicates whenever we allow fuzzy dates - was_cut - set ot 1 if there was some kind of error during - conversion or to 0 if everything was OK. + flags - flags to use in validating date, as in str_to_datetime() + was_cut 0 Value ok + 1 If value was cut during conversion + 2 Date part was within ranges but date was wrong DESCRIPTION Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS, @@ -893,12 +897,13 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to) This function also checks if datetime value fits in DATETIME range. RETURN VALUE + -1 Timestamp with wrong values + anything else DATETIME as integer in YYYYMMDDHHMMSS format Datetime value in YYYYMMDDHHMMSS format. - If input value is not valid datetime value then 0 is returned. */ longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res, - my_bool fuzzy_date, int *was_cut) + uint flags, int *was_cut) { long part1,part2; @@ -952,13 +957,17 @@ longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res, if (time_res->year <= 9999 && time_res->month <= 12 && time_res->day <= 31 && time_res->hour <= 23 && time_res->minute <= 59 && time_res->second <= 59 && - (fuzzy_date || (time_res->month != 0 && time_res->day != 0) || nr==0)) + !check_date(time_res, (nr != 0), flags, was_cut)) return nr; + /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */ + if (!nr && flags & TIME_NO_ZERO_DATE) + return LL(-1); + err: *was_cut= 1; - return LL(0); + return LL(-1); } diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc index 34bcbd4fc4b..77cb0c8de0f 100644 --- a/sql/des_key_file.cc +++ b/sql/des_key_file.cc @@ -21,18 +21,6 @@ struct st_des_keyschedule des_keyschedule[10]; uint des_default_key; -pthread_mutex_t LOCK_des_key_file; -static int initialized= 0; - -void -init_des_key_file() -{ - if (!initialized) - { - initialized=1; - pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST); - } -} /* Function which loads DES keys from plaintext file into memory on MySQL @@ -55,8 +43,6 @@ load_des_key_file(const char *file_name) DBUG_ENTER("load_des_key_file"); DBUG_PRINT("enter",("name: %s",file_name)); - init_des_key_file(); - VOID(pthread_mutex_lock(&LOCK_des_key_file)); if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 || init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME))) @@ -113,15 +99,4 @@ error: VOID(pthread_mutex_unlock(&LOCK_des_key_file)); DBUG_RETURN(result); } - - -void free_des_key_file() -{ - if (initialized) - { - initialized= 01; - pthread_mutex_destroy(&LOCK_des_key_file); - } -} - #endif /* HAVE_OPENSSL */ diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index c362985f565..fd47b45ce52 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -140,16 +140,20 @@ static handlerton archive_hton = { "archive", 0, /* slot */ 0, /* savepoint size. */ - 0, /* close_connection */ - 0, /* savepoint */ - 0, /* rollback to savepoint */ - 0, /* releas savepoint */ - 0, /* commit */ - 0, /* rollback */ - 0, /* prepare */ - 0, /* recover */ - 0, /* commit_by_xid */ - 0 /* rollback_by_xid */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* releas savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS }; @@ -208,6 +212,15 @@ bool archive_db_end() return FALSE; } +ha_archive::ha_archive(TABLE *table_arg) + :handler(&archive_hton, table_arg), delayed_insert(0), bulk_insert(0) +{ + /* Set our original buffer from pre-allocated memory */ + buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); + + /* The size of the offset value we will use for position() */ + ref_length = sizeof(z_off_t); +} /* This method reads the header of a datafile and returns whether or not it was successful. diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 3932b62980c..41835c5fb6f 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -58,14 +58,7 @@ class ha_archive: public handler bool bulk_insert; /* If we are performing a bulk insert */ public: - ha_archive(TABLE *table): handler(table), delayed_insert(0), bulk_insert(0) - { - /* Set our original buffer from pre-allocated memory */ - buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); - - /* The size of the offset value we will use for position() */ - ref_length = sizeof(z_off_t); - } + ha_archive(TABLE *table_arg); ~ha_archive() { } diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index 9da297ccd1f..a7e193b9730 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -72,6 +72,27 @@ #ifdef HAVE_EXAMPLE_DB #include "ha_example.h" + +static handlerton example_hton= { + "CSV", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + /* Variables for example share methods */ static HASH example_open_tables; // Hash used to track open tables pthread_mutex_t example_mutex; // This is the mutex we use to init the hash @@ -179,6 +200,10 @@ static int free_share(EXAMPLE_SHARE *share) } +ha_example::ha_example(TABLE *table_arg) + :handler(&example_hton, table_arg) +{} + /* If frm_error() is called then we will use this to to find out what file extentions exist for the storage engine. This is also used by the default rename_table and diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h index ae72e5bb275..37f38fe5210 100644 --- a/sql/examples/ha_example.h +++ b/sql/examples/ha_example.h @@ -45,9 +45,7 @@ class ha_example: public handler EXAMPLE_SHARE *share; /* Shared lock info */ public: - ha_example(TABLE *table): handler(table) - { - } + ha_example(TABLE *table_arg); ~ha_example() { } diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index a030960d08a..1e2751f3016 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -54,6 +54,26 @@ pthread_mutex_t tina_mutex; static HASH tina_open_tables; static int tina_init= 0; +static handlerton tina_hton= { + "CSV", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + /***************************************************************************** ** TINA tables *****************************************************************************/ @@ -228,6 +248,20 @@ byte * find_eoln(byte *data, off_t begin, off_t end) return 0; } + +ha_tina::ha_tina(TABLE *table_arg) + :handler(&tina_hton, table_arg), + /* + These definitions are found in hanler.h + These are not probably completely right. + */ + current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH) +{ + /* Set our original buffers from pre-allocated memory */ + buffer.set(byte_buffer, IO_SIZE, system_charset_info); + chain= chain_buffer; +} + /* Encode a buffer into the quoted format. */ diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h index 22193c01013..5679d77a4dc 100644 --- a/sql/examples/ha_tina.h +++ b/sql/examples/ha_tina.h @@ -49,18 +49,8 @@ class ha_tina: public handler byte chain_alloced; uint32 chain_size; - public: - ha_tina(TABLE *table): handler(table), - /* - These definitions are found in hanler.h - Theses are not probably completely right. - */ - current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH) - { - /* Set our original buffers from pre-allocated memory */ - buffer.set(byte_buffer, IO_SIZE, system_charset_info); - chain = chain_buffer; - } +public: + ha_tina(TABLE *table_arg); ~ha_tina() { if (chain_alloced) diff --git a/sql/field.cc b/sql/field.cc index 52f260e7b2d..61c0a71b742 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4471,13 +4471,13 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) bool in_dst_time_gap; THD *thd= table->in_use; + /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ have_smth_to_conv= (str_to_datetime(from, len, &l_time, - ((table->in_use->variables.sql_mode & - MODE_NO_ZERO_DATE) | - MODE_NO_ZERO_IN_DATE), - &error) > + (table->in_use->variables.sql_mode & + MODE_NO_ZERO_DATE) | + MODE_NO_ZERO_IN_DATE, &error) > MYSQL_TIMESTAMP_ERROR); - + if (error || !have_smth_to_conv) { error= 1; @@ -4490,16 +4490,15 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap))) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, from, len, MYSQL_TIMESTAMP_DATETIME, !error); - error= 1; } else if (in_dst_time_gap) { set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_INVALID_TIMESTAMP, + ER_WARN_INVALID_TIMESTAMP, from, len, MYSQL_TIMESTAMP_DATETIME, !error); error= 1; } @@ -4524,8 +4523,8 @@ int Field_timestamp::store(double nr) int error= 0; if (nr < 0 || nr > 99991231235959.0) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_DATETIME); nr= 0; // Avoid overflow on buff error= 1; @@ -4543,35 +4542,35 @@ int Field_timestamp::store(longlong nr) bool in_dst_time_gap; THD *thd= table->in_use; - if (number_to_datetime(nr, &l_time, 0, &error)) + /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ + longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode & + MODE_NO_ZERO_DATE) | + MODE_NO_ZERO_IN_DATE, &error); + if (tmp < 0) + { + error= 2; + } + + if (!error && tmp) { if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap))) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, - nr, MYSQL_TIMESTAMP_DATETIME, 1); + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_OUT_OF_RANGE, + nr, MYSQL_TIMESTAMP_DATETIME, 1); error= 1; } - if (in_dst_time_gap) { set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_INVALID_TIMESTAMP, - nr, MYSQL_TIMESTAMP_DATETIME, !error); + ER_WARN_INVALID_TIMESTAMP, + nr, MYSQL_TIMESTAMP_DATETIME, 1); error= 1; } - } - else if (error) - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_DATA_TRUNCATED, - nr, MYSQL_TIMESTAMP_DATETIME, 1); - if (!error && timestamp == 0 && - (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)) - { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + } else if (error) + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATETIME, 1); - } #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -4581,7 +4580,7 @@ int Field_timestamp::store(longlong nr) else #endif longstore(ptr,(uint32) timestamp); - + return error; } @@ -5154,14 +5153,14 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) TIME l_time; uint32 tmp; int error; - + if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE | (table->in_use->variables.sql_mode & (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)), &error) <= MYSQL_TIMESTAMP_ERROR) { - tmp=0; + tmp= 0; error= 2; } else @@ -5185,63 +5184,57 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) int Field_date::store(double nr) { - long tmp; + longlong tmp; int error= 0; if (nr >= 19000000000000.0 && nr <= 99991231235959.0) nr=floor(nr/1000000.0); // Timestamp to date if (nr < 0.0 || nr > 99991231.0) { - tmp=0L; - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, + tmp= LL(0); + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_DATE); error= 1; } else - tmp=(long) rint(nr); - - /* - We don't need to check for zero dates here as this date type is only - used in .frm tables from very old MySQL versions - */ + tmp= (longlong) rint(nr); -#ifdef WORDS_BIGENDIAN - if (table->s->db_low_byte_first) - { - int4store(ptr,tmp); - } - else -#endif - longstore(ptr,tmp); - return error; + return Field_date::store(tmp); } int Field_date::store(longlong nr) { - long tmp; - int error= 0; - if (nr >= LL(19000000000000) && nr < LL(99991231235959)) - nr=nr/LL(1000000); // Timestamp to date - if (nr < 0 || nr > LL(99991231)) + TIME not_used; + int error; + longlong initial_nr= nr; + + nr= number_to_datetime(nr, ¬_used, (TIME_FUZZY_DATE | + (table->in_use->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | + MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); + + if (nr < 0) { - tmp=0L; - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, - nr, MYSQL_TIMESTAMP_DATE, 0); - error= 1; + nr= 0; + error= 2; } - else - tmp=(long) nr; + + if (error) + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + error == 2 ? ER_WARN_DATA_OUT_OF_RANGE : + WARN_DATA_TRUNCATED, initial_nr, + MYSQL_TIMESTAMP_DATETIME, 1); #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { - int4store(ptr,tmp); + int4store(ptr, nr); } else #endif - longstore(ptr,tmp); + longstore(ptr, nr); return error; } @@ -5365,7 +5358,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) MODE_INVALID_DATES))), &error) <= MYSQL_TIMESTAMP_ERROR) { - tmp=0L; + tmp= 0L; error= 2; } else @@ -5374,7 +5367,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) if (error) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, from, len, MYSQL_TIMESTAMP_DATE, 1); - + int3store(ptr,tmp); return error; } @@ -5385,7 +5378,7 @@ int Field_newdate::store(double nr) if (nr < 0.0 || nr > 99991231235959.0) { int3store(ptr,(int32) 0); - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE); return 1; } @@ -5395,52 +5388,28 @@ int Field_newdate::store(double nr) int Field_newdate::store(longlong nr) { - int32 tmp; - int error= 0; - if (nr >= LL(100000000) && nr <= LL(99991231235959)) - nr=nr/LL(1000000); // Timestamp to date - if (nr < 0L || nr > 99991231L) - { - tmp=0; - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, nr, - MYSQL_TIMESTAMP_DATE, 1); - error= 1; + TIME l_time; + longlong tmp; + int error; + if ((tmp= number_to_datetime(nr, &l_time, + (TIME_FUZZY_DATE | + (table->in_use->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), + &error) < 0)) + { + tmp= 0L; + error= 2; } else - { - uint month, day; + tmp= l_time.day + l_time.month*32 + l_time.year*16*32; - tmp=(int32) nr; - if (tmp) - { - if (tmp < YY_PART_YEAR*10000L) // Fix short dates - tmp+= (uint32) 20000000L; - else if (tmp < 999999L) - tmp+= (uint32) 19000000L; - - month= (uint) ((tmp/100) % 100); - day= (uint) (tmp%100); - if (month > 12 || day > 31) - { - tmp=0L; // Don't allow date to change - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, nr, - MYSQL_TIMESTAMP_DATE, 1); - error= 1; - } - else - tmp= day + month*32 + (tmp/10000)*16*32; - } - else if (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE) - { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, - 0, MYSQL_TIMESTAMP_DATE); - error= 1; - } - } - int3store(ptr, tmp); + if (error) + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + error == 2 ? ER_WARN_DATA_OUT_OF_RANGE : + WARN_DATA_TRUNCATED,nr,MYSQL_TIMESTAMP_DATE, 1); + + int3store(ptr,tmp); return error; } @@ -5567,7 +5536,7 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) int error; ulonglong tmp= 0; enum enum_mysql_timestamp_type func_res; - + func_res= str_to_datetime(from, len, &time_tmp, (TIME_FUZZY_DATE | (table->in_use->variables.sql_mode & @@ -5580,7 +5549,7 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; // Fix if invalid zero date if (error) - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, from, len, MYSQL_TIMESTAMP_DATETIME, 1); @@ -5617,21 +5586,25 @@ int Field_datetime::store(longlong nr) TIME not_used; int error; longlong initial_nr= nr; - - nr= number_to_datetime(nr, ¬_used, 1, &error); - if (error) - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_DATA_TRUNCATED, initial_nr, - MYSQL_TIMESTAMP_DATETIME, 1); - else if (nr == 0 && table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE) + nr= number_to_datetime(nr, ¬_used, (TIME_FUZZY_DATE | + (table->in_use->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | + MODE_NO_ZERO_DATE | + MODE_INVALID_DATES))), &error); + + if (nr < 0) { - set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, - initial_nr, MYSQL_TIMESTAMP_DATE, 1); - error= 1; + nr= 0; + error= 2; } + if (error) + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + error == 2 ? ER_WARN_DATA_OUT_OF_RANGE : + WARN_DATA_TRUNCATED, initial_nr, + MYSQL_TIMESTAMP_DATETIME, 1); + #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { @@ -6935,8 +6908,8 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)), my_decimal *Field_blob::val_decimal(my_decimal *decimal_value) { - char *blob; - memcpy_fixed(&blob, ptr+packlength, sizeof(char*)); + const char *blob; + memcpy_fixed(&blob, ptr+packlength, sizeof(const char*)); if (!blob) blob= ""; str2my_decimal(E_DEC_FATAL_ERROR, blob, get_length(ptr), charset(), @@ -7873,7 +7846,10 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) { set_rec_bits(0xff, bit_ptr, bit_ofs, bit_len); memset(ptr, 0xff, field_length); - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + if (table->in_use->really_abort_on_warning()) + set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + else + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } /* delta is >= -1 here */ @@ -8090,7 +8066,10 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) memset(ptr, 0xff, field_length); if (bits) *ptr&= ((1 << bits) - 1); /* set first byte */ - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + if (table->in_use->really_abort_on_warning()) + set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + else + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; } bzero(ptr, delta); @@ -8489,7 +8468,10 @@ create_field::create_field(Field *old_field,Field *orig_field) def=0; if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && !old_field->is_real_null() && - old_field->ptr && orig_field) + old_field->ptr && orig_field && + (sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */ + old_field->table->timestamp_field != old_field || /* timestamp field */ + unireg_check == Field::TIMESTAMP_UN_FIELD)) /* has default val */ { char buff[MAX_FIELD_WIDTH],*pos; String tmp(buff,sizeof(buff), charset), *res; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 0dc82666f52..fc7347ef9af 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -322,7 +322,34 @@ static void do_field_real(Copy_field *copy) } +/* + string copy for single byte characters set when to string is shorter than + from string +*/ + static void do_cut_string(Copy_field *copy) +{ + CHARSET_INFO *cs= copy->from_field->charset(); + memcpy(copy->to_ptr,copy->from_ptr,copy->to_length); + + /* Check if we loosed any important characters */ + if (cs->cset->scan(cs, + copy->from_ptr + copy->to_length, + copy->from_ptr + copy->from_length, + MY_SEQ_SPACES) < copy->from_length - copy->to_length) + { + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, 1); + } +} + + +/* + string copy for multi byte characters set when to string is shorter than + from string +*/ + +static void do_cut_string_complex(Copy_field *copy) { // Shorter string field int well_formed_error; CHARSET_INFO *cs= copy->from_field->charset(); @@ -349,6 +376,8 @@ static void do_cut_string(Copy_field *copy) } + + static void do_expand_string(Copy_field *copy) { CHARSET_INFO *cs= copy->from_field->charset(); @@ -550,7 +579,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) do_varstring1 : do_varstring2); } else if (to_length < from_length) - return do_cut_string; + return (from->charset()->mbmaxlen == 1 ? + do_cut_string : do_cut_string_complex); else if (to_length > from_length) return do_expand_string; } diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 568fb727e63..793029ab4c7 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -120,7 +120,11 @@ static handlerton berkeley_hton = { NULL, /* prepare */ NULL, /* recover */ NULL, /* commit_by_xid */ - NULL /* rollback_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_CLOSE_CURSORS_AT_COMMIT }; typedef struct st_berkeley_trx_data { @@ -372,6 +376,17 @@ void berkeley_cleanup_log_files(void) /***************************************************************************** ** Berkeley DB tables *****************************************************************************/ + +ha_berkeley::ha_berkeley(TABLE *table_arg) + :handler(&berkeley_hton, table_arg), alloc_ptr(0), rec_buff(0), file(0), + int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ | + HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT | + HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | + HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX), + changed_rows(0), last_dup_key((uint) -1), version(0), using_ignore(0) +{} + + static const char *ha_berkeley_exts[] = { ha_berkeley_ext, NullS diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index f6376939445..aa92908ecde 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -85,12 +85,7 @@ class ha_berkeley: public handler DBT *get_pos(DBT *to, byte *pos); public: - ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0), - int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ | - HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT | - HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | - HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX), - changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {} + ha_berkeley(TABLE *table_arg); ~ha_berkeley() {} const char *table_type() const { return "BerkeleyDB"; } ulong index_flags(uint idx, uint part, bool all_parts) const; diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index 6abbe983f48..43a286a541f 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -24,6 +24,37 @@ #include "ha_blackhole.h" +/* Blackhole storage engine handlerton */ + +static handlerton blackhole_hton= { + "BLACKHOLE", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + +/***************************************************************************** +** BLACKHOLE tables +*****************************************************************************/ + +ha_blackhole::ha_blackhole(TABLE *table_arg) + :handler(&blackhole_hton, table_arg) +{} + + static const char *ha_blackhole_exts[] = { NullS }; diff --git a/sql/ha_blackhole.h b/sql/ha_blackhole.h index 84a386e17f8..2dccabf17cc 100644 --- a/sql/ha_blackhole.h +++ b/sql/ha_blackhole.h @@ -28,9 +28,7 @@ class ha_blackhole: public handler THR_LOCK thr_lock; public: - ha_blackhole(TABLE *table): handler(table) - { - } + ha_blackhole(TABLE *table_arg); ~ha_blackhole() { } diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 383652e4a3a..639f09d10ca 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -54,6 +54,7 @@ ***IMPORTANT*** + This is a first release, conceptual release Only 'mysql://' is supported at this release. @@ -352,7 +353,8 @@ #ifdef HAVE_FEDERATED_DB #include "ha_federated.h" -#define MAX_REMOTE_SIZE IO_SIZE + +#include "m_string.h" /* Variables for federated share methods */ static HASH federated_open_tables; // Hash used to track open // tables @@ -413,13 +415,14 @@ bool federated_db_end() return FALSE; } - /* Check (in create) whether the tables exists, and that it can be connected to SYNOPSIS check_foreign_data_source() share pointer to FEDERATED share + table_create_flag tells us that ::create is the caller, + therefore, return CANT_CREATE_FEDERATED_TABLE DESCRIPTION This method first checks that the connection information that parse url @@ -427,23 +430,23 @@ bool federated_db_end() table, and if so, does the foreign table exist. */ -static int check_foreign_data_source(FEDERATED_SHARE *share) +static int check_foreign_data_source( + FEDERATED_SHARE *share, + bool table_create_flag) { - char escaped_table_base_name[IO_SIZE]; - MYSQL *mysql; - MYSQL_RES *result=0; + char escaped_table_name[NAME_LEN*2]; + char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; uint error_code; - char query_buffer[IO_SIZE]; - char error_buffer[IO_SIZE]; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); + MYSQL *mysql; DBUG_ENTER("ha_federated::check_foreign_data_source"); + /* Zero the length, otherwise the string will have misc chars */ query.length(0); /* error out if we can't alloc memory for mysql_init(NULL) (per Georg) */ - if (! (mysql= mysql_init(NULL))) - { + if (!(mysql= mysql_init(NULL))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } /* check if we can connect */ if (!mysql_real_connect(mysql, share->hostname, @@ -453,11 +456,18 @@ static int check_foreign_data_source(FEDERATED_SHARE *share) share->port, share->socket, 0)) { + /* + we want the correct error message, but it to return + ER_CANT_CREATE_FEDERATED_TABLE if called by ::create + */ + error_code= table_create_flag? + ER_CANT_CREATE_FEDERATED_TABLE : ER_CONNECT_TO_FOREIGN_DATA_SOURCE; + my_sprintf(error_buffer, - (error_buffer, - "unable to connect to database '%s' on host '%s as user '%s' !", - share->database, share->hostname, share->username)); - error_code= ER_CONNECT_TO_MASTER; + (error_buffer, " database %s username %s hostname %s", + share->database, share->username, share->hostname)); + + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), error_buffer); goto error; } else @@ -468,48 +478,42 @@ static int check_foreign_data_source(FEDERATED_SHARE *share) with transactions */ mysql->reconnect= 1; - /* + /* Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0 if we can connect, then make sure the table exists + + the query will be: SELECT * FROM `tablename` WHERE 1=0 */ - query.append("SHOW TABLES LIKE '"); - escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_base_name, - sizeof(escaped_table_base_name), - share->table_base_name, - share->table_base_name_length); - query.append(escaped_table_base_name); - query.append("'"); - - error_code= ER_QUERY_ON_MASTER; + query.append(FEDERATED_SELECT); + query.append(FEDERATED_STAR); + query.append(FEDERATED_FROM); + query.append(FEDERATED_BTICK); + escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name, + sizeof(escaped_table_name), + share->table_name, + share->table_name_length); + query.append(escaped_table_name); + query.append(FEDERATED_BTICK); + query.append(FEDERATED_WHERE); + query.append(FEDERATED_FALSE); + + DBUG_PRINT("info", ("check_foreign_data_source query %s", query.c_ptr_quick())); if (mysql_real_query(mysql, query.ptr(), query.length())) - goto error; - - result= mysql_store_result(mysql); - if (! result) - goto error; - - /* if ! mysql_num_rows, the table doesn't exist, send error */ - if (! mysql_num_rows(result)) { - my_sprintf(error_buffer, - (error_buffer, "foreign table '%s' does not exist!", - share->table_base_name)); + error_code= table_create_flag ? + ER_CANT_CREATE_FEDERATED_TABLE : ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST; + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); + + my_error(error_code, MYF(0), error_buffer); goto error; } - mysql_free_result(result); - result= 0; - mysql_close(mysql); - } - DBUG_RETURN(0); + error_code=0; error: - if (result) - mysql_free_result(result); mysql_close(mysql); - my_error(error_code, MYF(0), error_buffer); DBUG_RETURN(error_code); - } @@ -545,22 +549,27 @@ error: 'password' and 'port' are both optional. RETURN VALUE - 0 success - 1 failure, wrong string format + 0 success + error_num particular error code */ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_flag) { - uint error_num= (table_create_flag ? ER_CANT_CREATE_TABLE : - ER_CONNECT_TO_MASTER); + uint error_num= (table_create_flag ? + ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE : + ER_FOREIGN_DATA_STRING_INVALID); DBUG_ENTER("ha_federated::parse_url"); share->port= 0; - share->socket= 0; share->scheme= my_strdup(table->s->comment, MYF(0)); + DBUG_PRINT("info",("parse_url alloced share->scheme %lx", share->scheme)); + /* + remove addition of null terminator and store length + for each string in share + */ if ((share->username= strstr(share->scheme, "://"))) { share->scheme[share->username - share->scheme]= '\0'; @@ -613,20 +622,20 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, share->port= atoi(share->sport); } - if ((share->table_base_name= strchr(share->database, '/'))) + if ((share->table_name= strchr(share->database, '/'))) { - share->database[share->table_base_name - share->database]= '\0'; - share->table_base_name++; + share->database[share->table_name - share->database]= '\0'; + share->table_name++; } else goto error; - share->table_base_name_length= strlen(share->table_base_name); + share->table_name_length= strlen(share->table_name); } else goto error; /* make sure there's not an extra / */ - if ((strchr(share->table_base_name, '/'))) + if ((strchr(share->table_name, '/'))) goto error; if (share->hostname[0] == '\0') @@ -645,7 +654,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, hostname %s port %d database %s tablename %s\n", share->scheme, share->username, share->password, share->hostname, share->port, share->database, - share->table_base_name)); + share->table_name)); } else goto error; @@ -656,13 +665,54 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, DBUG_RETURN(0); error: - my_error(error_num, MYF(0), - "connection string is not in the correct format",0); - DBUG_RETURN(1); + if (share->scheme) + { + DBUG_PRINT("info", + ("error: parse_url. Returning error code %d \ + freeing share->scheme %lx", error_num, share->scheme)); + my_free((gptr) share->scheme, MYF(0)); + share->scheme= 0; + } + my_error(error_num, MYF(0), table->s->comment); + DBUG_RETURN(error_num); } +/* Federated storage engine handlerton */ + +static handlerton federated_hton= { + "FEDERATED", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + + +/***************************************************************************** +** FEDERATED tables +*****************************************************************************/ + +ha_federated::ha_federated(TABLE *table_arg) + :handler(&federated_hton, table_arg), + mysql(0), stored_result(0), scan_flag(0), + ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) +{} + + /* Convert MySQL result set row to handler internal format @@ -684,25 +734,115 @@ error: uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) { - ulong *lengths; uint num_fields; - uint x= 0; + ulong *lengths; + Field **field; DBUG_ENTER("ha_federated::convert_row_to_internal_format"); - num_fields= mysql_num_fields(result); - lengths= mysql_fetch_lengths(result); + num_fields= mysql_num_fields(stored_result); + lengths= mysql_fetch_lengths(stored_result); memset(record, 0, table->s->null_bytes); - for (Field **field= table->field; *field; field++, x++) + for (field= table->field; *field; field++) { + /* + index variable to move us through the row at the + same iterative step as the field + */ + int x= field - table->field; + my_ptrdiff_t old_ptr; + old_ptr= (my_ptrdiff_t) (record - table->record[0]); + (*field)->move_field(old_ptr); if (!row[x]) (*field)->set_null(); else + { + (*field)->set_notnull(); (*field)->store(row[x], lengths[x], &my_charset_bin); + } + (*field)->move_field(-old_ptr); + } + + DBUG_RETURN(0); +} + +static bool emit_key_part_name(String *to, KEY_PART_INFO *part) +{ + DBUG_ENTER("emit_key_part_name"); + if (to->append(FEDERATED_BTICK) || + to->append(part->field->field_name) || + to->append(FEDERATED_BTICK)) + DBUG_RETURN(1); // Out of memory + DBUG_RETURN(0); +} + +static bool emit_key_part_element(String *to, KEY_PART_INFO *part, + bool needs_quotes, bool is_like, + const byte *ptr, uint len) +{ + Field *field= part->field; + DBUG_ENTER("emit_key_part_element"); + + if (needs_quotes && to->append(FEDERATED_SQUOTE)) + DBUG_RETURN(1); + + if (part->type == HA_KEYTYPE_BIT) + { + char buff[STRING_BUFFER_USUAL_SIZE], *buf= buff; + + *buf++= '0'; + *buf++= 'x'; + for (; len; ptr++,len--) + { + uint tmp= (uint)(uchar) *ptr; + *buf++= _dig_vec_upper[tmp >> 4]; + *buf++= _dig_vec_upper[tmp & 15]; + } + if (to->append(buff, (uint)(buf - buff))) + DBUG_RETURN(1); + } + else if (part->key_part_flag & HA_BLOB_PART) + { + String blob; + uint blob_length= uint2korr(ptr); + blob.set_quick((char*) ptr+HA_KEY_BLOB_LENGTH, + blob_length, &my_charset_bin); + if (append_escaped(to, &blob)) + DBUG_RETURN(1); + } + else if (part->key_part_flag & HA_VAR_LENGTH_PART) + { + String varchar; + uint var_length= uint2korr(ptr); + varchar.set_quick((char*) ptr+HA_KEY_BLOB_LENGTH, + var_length, &my_charset_bin); + if (append_escaped(to, &varchar)) + DBUG_RETURN(1); + } + else + { + char strbuff[MAX_FIELD_WIDTH]; + String str(strbuff, sizeof(strbuff), part->field->charset()), *res; + + res= field->val_str(&str, (char *)ptr); + + if (field->result_type() == STRING_RESULT) + { + if (append_escaped(to, res)) + DBUG_RETURN(1); + } + else if (to->append(res->ptr(), res->length())) + DBUG_RETURN(1); } + if (is_like && to->append(FEDERATED_PERCENT)) + DBUG_RETURN(1); + + if (needs_quotes && to->append(FEDERATED_SQUOTE)) + DBUG_RETURN(1); + DBUG_RETURN(0); } @@ -716,6 +856,8 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) key_info KEY struct pointer key byte pointer containing key key_length length of key + range_type 0 - no range, 1 - min range, 2 - max range + (see enum range_operation) DESCRIPTION Using iteration through all the keys via a KEY_PART_INFO pointer, @@ -726,112 +868,402 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) 0 After all keys have been accounted for to create the WHERE clause 1 No keys found - */ + Range flags Table per Timour: + + ----------------- + - start_key: + * ">" -> HA_READ_AFTER_KEY + * ">=" -> HA_READ_KEY_OR_NEXT + * "=" -> HA_READ_KEY_EXACT + + - end_key: + * "<" -> HA_READ_BEFORE_KEY + * "<=" -> HA_READ_AFTER_KEY + + records_in_range: + ----------------- + - start_key: + * ">" -> HA_READ_AFTER_KEY + * ">=" -> HA_READ_KEY_EXACT + * "=" -> HA_READ_KEY_EXACT + + - end_key: + * "<" -> HA_READ_BEFORE_KEY + * "<=" -> HA_READ_AFTER_KEY + * "=" -> HA_READ_AFTER_KEY + +0 HA_READ_KEY_EXACT, Find first record else error +1 HA_READ_KEY_OR_NEXT, Record or next record +2 HA_READ_KEY_OR_PREV, Record or previous +3 HA_READ_AFTER_KEY, Find next rec. after key-record +4 HA_READ_BEFORE_KEY, Find next rec. before key-record +5 HA_READ_PREFIX, Key which as same prefix +6 HA_READ_PREFIX_LAST, Last key with the same prefix +7 HA_READ_PREFIX_LAST_OR_PREV, Last or prev key with the same prefix + +Flags that I've found: + +id, primary key, varchar + +id = 'ccccc' +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 0 end_key NULL + +id > 'ccccc' +records_in_range: start_key 3 end_key NULL +read_range_first: start_key 3 end_key NULL + +id < 'ccccc' +records_in_range: start_key NULL end_key 4 +read_range_first: start_key NULL end_key 4 + +id <= 'ccccc' +records_in_range: start_key NULL end_key 3 +read_range_first: start_key NULL end_key 3 + +id >= 'ccccc' +records_in_range: start_key 0 end_key NULL +read_range_first: start_key 1 end_key NULL + +id like 'cc%cc' +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 1 end_key 3 + +id > 'aaaaa' and id < 'ccccc' +records_in_range: start_key 3 end_key 4 +read_range_first: start_key 3 end_key 4 + +id >= 'aaaaa' and id < 'ccccc'; +records_in_range: start_key 0 end_key 4 +read_range_first: start_key 1 end_key 4 + +id >= 'aaaaa' and id <= 'ccccc'; +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 1 end_key 3 + +id > 'aaaaa' and id <= 'ccccc'; +records_in_range: start_key 3 end_key 3 +read_range_first: start_key 3 end_key 3 + +numeric keys: + +id = 4 +index_read_idx: start_key 0 end_key NULL + +id > 4 +records_in_range: start_key 3 end_key NULL +read_range_first: start_key 3 end_key NULL + +id >= 4 +records_in_range: start_key 0 end_key NULL +read_range_first: start_key 1 end_key NULL + +id < 4 +records_in_range: start_key NULL end_key 4 +read_range_first: start_key NULL end_key 4 + +id <= 4 +records_in_range: start_key NULL end_key 3 +read_range_first: start_key NULL end_key 3 + +id like 4 +full table scan, select * from + +id > 2 and id < 8 +records_in_range: start_key 3 end_key 4 +read_range_first: start_key 3 end_key 4 + +id >= 2 and id < 8 +records_in_range: start_key 0 end_key 4 +read_range_first: start_key 1 end_key 4 + +id >= 2 and id <= 8 +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 1 end_key 3 + +id > 2 and id <= 8 +records_in_range: start_key 3 end_key 3 +read_range_first: start_key 3 end_key 3 + +multi keys (id int, name varchar, other varchar) + +id = 1; +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 0 end_key NULL + +id > 4; +id > 2 and name = '333'; remote: id > 2 +id > 2 and name > '333'; remote: id > 2 +id > 2 and name > '333' and other < 'ddd'; remote: id > 2 no results +id > 2 and name >= '333' and other < 'ddd'; remote: id > 2 1 result +id >= 4 and name = 'eric was here' and other > 'eeee'; +records_in_range: start_key 3 end_key NULL +read_range_first: start_key 3 end_key NULL -bool ha_federated::create_where_from_key(String *to, KEY *key_info, - const byte *key, uint key_length) +id >= 4; +id >= 2 and name = '333' and other < 'ddd'; +remote: `id` >= 2 AND `name` >= '333'; +records_in_range: start_key 0 end_key NULL +read_range_first: start_key 1 end_key NULL + +id < 4; +id < 3 and name = '222' and other <= 'ccc'; remote: id < 3 +records_in_range: start_key NULL end_key 4 +read_range_first: start_key NULL end_key 4 + +id <= 4; +records_in_range: start_key NULL end_key 3 +read_range_first: start_key NULL end_key 3 + +id like 4; +full table scan + +id > 2 and id < 4; +records_in_range: start_key 3 end_key 4 +read_range_first: start_key 3 end_key 4 + +id >= 2 and id < 4; +records_in_range: start_key 0 end_key 4 +read_range_first: start_key 1 end_key 4 + +id >= 2 and id <= 4; +records_in_range: start_key 0 end_key 3 +read_range_first: start_key 1 end_key 3 + +id > 2 and id <= 4; +id = 6 and name = 'eric was here' and other > 'eeee'; +remote: (`id` > 6 AND `name` > 'eric was here' AND `other` > 'eeee') +AND (`id` <= 6) AND ( AND `name` <= 'eric was here') +no results +records_in_range: start_key 3 end_key 3 +read_range_first: start_key 3 end_key 3 + +Summary: + +* If the start key flag is 0 the max key flag shouldn't even be set, + and if it is, the query produced would be invalid. +* Multipart keys, even if containing some or all numeric columns, + are treated the same as non-numeric keys + + If the query is " = " (quotes or not): + - records in range start key flag HA_READ_KEY_EXACT, + end key flag HA_READ_AFTER_KEY (incorrect) + - any other: start key flag HA_READ_KEY_OR_NEXT, + end key flag HA_READ_AFTER_KEY (correct) + +* 'like' queries (of key) + - Numeric, full table scan + - Non-numeric + records_in_range: start_key 0 end_key 3 + other : start_key 1 end_key 3 + +* If the key flag is HA_READ_AFTER_KEY: + if start_key, append > + if end_key, append <= + +* If create_where_key was called by records_in_range: + + - if the key is numeric: + start key flag is 0 when end key is NULL, end key flag is 3 or 4 + - if create_where_key was called by any other function: + start key flag is 1 when end key is NULL, end key flag is 3 or 4 + - if the key is non-numeric, or multipart + When the query is an exact match, the start key flag is 0, + end key flag is 3 for what should be a no-range condition where + you should have 0 and max key NULL, which it is if called by + read_range_first + +Conclusion: + +1. Need logic to determin if a key is min or max when the flag is +HA_READ_AFTER_KEY, and handle appending correct operator accordingly + +2. Need a boolean flag to pass to create_where_from_key, used in the +switch statement. Add 1 to the flag if: + - start key flag is HA_READ_KEY_EXACT and the end key is NULL + +*/ + +bool ha_federated::create_where_from_key(String *to, + KEY *key_info, + const key_range *start_key, + const key_range *end_key, + bool records_in_range) { - uint second_loop= 0; - KEY_PART_INFO *key_part; - bool needs_quotes; - String tmp; + bool both_not_null= + (start_key != NULL && end_key != NULL) ? TRUE : FALSE; + const byte *ptr; + uint remainder, length; + char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE]; + String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info); + const key_range *ranges[2]= { start_key, end_key }; DBUG_ENTER("ha_federated::create_where_from_key"); - for (key_part= key_info->key_part; (int) key_length > 0; key_part++) - { - Field *field= key_part->field; - needs_quotes= field->needs_quotes(); - uint length= key_part->length; + tmp.length(0); + if (start_key == NULL && end_key == NULL) + DBUG_RETURN(1); - if (second_loop++ && to->append(" AND ", 5)) - DBUG_RETURN(1); - if (to->append('`') || to->append(field->field_name) || to->append("` ", 2)) - DBUG_RETURN(1); // Out of memory + for (int i= 0; i <= 1; i++) + { + bool needs_quotes; + uint loop_counter= 0; + KEY_PART_INFO *key_part; + if (ranges[i] == NULL) + continue; + const byte *key= ranges[i]->key; + uint key_length= ranges[i]->length; - if (key_part->null_bit) + if (both_not_null) { - if (*key++) - { - if (to->append("IS NULL", 7)) - DBUG_RETURN(1); - - DBUG_PRINT("info", - ("NULL type %s", to->c_ptr_quick())); - key_length-= key_part->store_length; - key+= key_part->store_length - 1; - continue; - } - key_length--; + if (i > 0) + tmp.append(FEDERATED_CONJUNCTION); + else + tmp.append(FEDERATED_OPENPAREN); } - if (to->append("= ")) - DBUG_RETURN(1); - if (needs_quotes && to->append("'")) - DBUG_RETURN(1); - if (key_part->type == HA_KEYTYPE_BIT) - { - /* This is can be treated as a hex string */ - Field_bit *field= (Field_bit *) (key_part->field); - char buff[64 + 2], *ptr; - byte *end= (byte*)(key)+length; - - buff[0]= '0'; - buff[1]= 'x'; - for (ptr= buff + 2; key < end; key++) - { - uint tmp= (uint)(uchar) *key; - *ptr++= _dig_vec_upper[tmp >> 4]; - *ptr++= _dig_vec_upper[tmp & 15]; - } - if (to->append(buff, (uint)(ptr - buff))) - DBUG_RETURN(1); - key_length-= length; - continue; - } - if (key_part->key_part_flag & HA_BLOB_PART) + for (key_part= key_info->key_part, + remainder= key_info->key_parts, + length= ranges[i]->length, + ptr= ranges[i]->key; ; + remainder--, + key_part++) { - uint blob_length= uint2korr(key); - key+= HA_KEY_BLOB_LENGTH; - key_length-= HA_KEY_BLOB_LENGTH; + Field *field= key_part->field; + uint store_length= key_part->store_length; + uint part_length= min(store_length, length); + needs_quotes= field->needs_quotes(); + DBUG_DUMP("key, start of loop", (char *) ptr, length); - tmp.set_quick((char*) key, blob_length, &my_charset_bin); - if (append_escaped(to, &tmp)) - DBUG_RETURN(1); + if (key_part->null_bit) + { + if (*ptr++) + { + if (emit_key_part_name(&tmp, key_part) || + tmp.append(FEDERATED_ISNULL)) + DBUG_RETURN(1); + continue; + } + } - length= key_part->length; - } - else if (key_part->key_part_flag & HA_VAR_LENGTH_PART) - { - length= uint2korr(key); - key+= HA_KEY_BLOB_LENGTH; - tmp.set_quick((char*) key, length, &my_charset_bin); - if (append_escaped(to, &tmp)) + if (tmp.append(FEDERATED_OPENPAREN)) DBUG_RETURN(1); - } - else - { - char buff[MAX_FIELD_WIDTH]; - String str(buff, sizeof(buff), field->charset()), *res; - res= field->val_str(&str, (char*) (key)); - if (field->result_type() == STRING_RESULT) - { - if (append_escaped(to, res)) + switch(ranges[i]->flag) { + case(HA_READ_KEY_EXACT): + if (store_length >= length || + !needs_quotes || + key_part->type == HA_KEYTYPE_BIT || + field->result_type() != STRING_RESULT) + { + if (emit_key_part_name(&tmp, key_part)) + DBUG_RETURN(1); + + if (records_in_range) + { + if (tmp.append(FEDERATED_GE)) + DBUG_RETURN(1); + } + else + { + if (tmp.append(FEDERATED_EQ)) + DBUG_RETURN(1); + } + + if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, + part_length)) + DBUG_RETURN(1); + } + else + /* LIKE */ + { + if (emit_key_part_name(&tmp, key_part) || + tmp.append(FEDERATED_LIKE) || + emit_key_part_element(&tmp, key_part, needs_quotes, 1, ptr, + part_length)) + DBUG_RETURN(1); + } + break; + case(HA_READ_AFTER_KEY): + if (store_length >= length) /* end key */ + { + if (emit_key_part_name(&tmp, key_part)) + DBUG_RETURN(1); + + if (i > 0) /* end key */ + { + if (tmp.append(FEDERATED_LE)) + DBUG_RETURN(1); + } + else /* start key */ + { + if (tmp.append(FEDERATED_GT)) + DBUG_RETURN(1); + } + + if (emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, + part_length)) + { + DBUG_RETURN(1); + } + break; + } + case(HA_READ_KEY_OR_NEXT): + if (emit_key_part_name(&tmp, key_part) || + tmp.append(FEDERATED_GE) || + emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, + part_length)) DBUG_RETURN(1); - res= field->val_str(&str, (char*) (key)); + break; + case(HA_READ_BEFORE_KEY): + if (store_length >= length) + { + if (emit_key_part_name(&tmp, key_part) || + tmp.append(FEDERATED_LT) || + emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, + part_length)) + DBUG_RETURN(1); + break; + } + case(HA_READ_KEY_OR_PREV): + if (emit_key_part_name(&tmp, key_part) || + tmp.append(FEDERATED_LE) || + emit_key_part_element(&tmp, key_part, needs_quotes, 0, ptr, + part_length)) + DBUG_RETURN(1); + break; + default: + DBUG_PRINT("info",("cannot handle flag %d", ranges[i]->flag)); + DBUG_RETURN(1); } - else if (to->append(res->ptr(), res->length())) + if (tmp.append(FEDERATED_CLOSEPAREN)) DBUG_RETURN(1); + +next_loop: + if (store_length >= length) + break; + DBUG_PRINT("info", ("remainder %d", remainder)); + DBUG_ASSERT(remainder > 1); + length-= store_length; + ptr+= store_length; + if (tmp.append(FEDERATED_AND)) + DBUG_RETURN(1); + + DBUG_PRINT("info", + ("create_where_from_key WHERE clause: %s", + tmp.c_ptr_quick())); } - if (needs_quotes && to->append("'")) - DBUG_RETURN(1); - DBUG_PRINT("info", - ("final value for 'to' %s", to->c_ptr_quick())); - key+= length; - key_length-= length; - DBUG_RETURN(0); } - DBUG_RETURN(1); + if (both_not_null) + if (tmp.append(FEDERATED_CLOSEPAREN)) + DBUG_RETURN(1); + + if (to->append(FEDERATED_WHERE)) + DBUG_RETURN(1); + + if (to->append(tmp)) + DBUG_RETURN(1); + + DBUG_RETURN(0); } /* @@ -842,40 +1274,47 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) { - FEDERATED_SHARE *share; - char query_buffer[IO_SIZE]; + char *select_query, *tmp_table_name; + char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + uint tmp_table_name_length; + Field **field; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); + FEDERATED_SHARE *share; + /* + In order to use this string, we must first zero it's length, + or it will contain garbage + */ query.length(0); - uint table_name_length, table_base_name_length; - char *tmp_table_name, *table_base_name, *select_query; - - /* share->table_name has the file location - we want the table's name! */ - table_base_name= (char*) table->s->table_name; - DBUG_PRINT("info", ("table_name %s", table_base_name)); - /* - So why does this exist? There is no way currently to init a storage engine. - Innodb and BDB both have modifications to the server to allow them to - do this. Since you will not want to do this, this is probably the next - best method. - */ pthread_mutex_lock(&federated_mutex); - table_name_length= (uint) strlen(table_name); - table_base_name_length= (uint) strlen(table_base_name); + tmp_table_name= (char *)table->s->table_name; + tmp_table_name_length= (uint) strlen(tmp_table_name); if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables, (byte*) table_name, - table_name_length))) + strlen(table_name)))) { query.set_charset(system_charset_info); - query.append("SELECT * FROM `"); + query.append(FEDERATED_SELECT); + for (field= table->field; *field; field++) + { + query.append(FEDERATED_BTICK); + query.append((*field)->field_name); + query.append(FEDERATED_BTICK); + query.append(FEDERATED_COMMA); + } + query.length(query.length()- strlen(FEDERATED_COMMA)); + query.append(FEDERATED_FROM); + query.append(FEDERATED_BTICK); + if (!(share= (FEDERATED_SHARE *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + my_multi_malloc(MYF(MY_WME), &share, sizeof(*share), - &tmp_table_name, table_name_length + 1, - &select_query, query.length() + - strlen(table->s->comment) + 1, NullS))) + &tmp_table_name, tmp_table_name_length+ 1, + &select_query, + query.length()+strlen(table->s->comment)+1, + NullS))) { pthread_mutex_unlock(&federated_mutex); return NULL; @@ -884,16 +1323,15 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) if (parse_url(share, table, 0)) goto error; - query.append(share->table_base_name); - query.append("`"); - share->use_count= 0; - share->table_name_length= table_name_length; - share->table_name= tmp_table_name; + query.append(share->table_name, share->table_name_length); + query.append(FEDERATED_BTICK); share->select_query= select_query; - strmov(share->table_name, table_name); strmov(share->select_query, query.ptr()); + share->use_count= 0; + share->table_name_length= strlen(share->table_name); DBUG_PRINT("info", ("share->select_query %s", share->select_query)); + if (my_hash_insert(&federated_open_tables, (byte*) share)) goto error; thr_lock_init(&share->lock); @@ -907,9 +1345,10 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) error: pthread_mutex_unlock(&federated_mutex); if (share->scheme) + { my_free((gptr) share->scheme, MYF(0)); - my_free((gptr) share, MYF(0)); - + share->scheme= 0; + } return NULL; } @@ -922,12 +1361,16 @@ error: static int free_share(FEDERATED_SHARE *share) { + DBUG_ENTER("free_share"); pthread_mutex_lock(&federated_mutex); if (!--share->use_count) { if (share->scheme) + { my_free((gptr) share->scheme, MYF(0)); + share->scheme= 0; + } hash_delete(&federated_open_tables, (byte*) share); thr_lock_delete(&share->lock); @@ -936,23 +1379,37 @@ static int free_share(FEDERATED_SHARE *share) } pthread_mutex_unlock(&federated_mutex); - return 0; + DBUG_RETURN(0); } +ha_rows ha_federated::records_in_range(uint inx, key_range *start_key, + key_range *end_key) +{ + /* + + We really want indexes to be used as often as possible, therefore + we just need to hard-code the return value to a very low number to + force the issue + +*/ + DBUG_ENTER("ha_federated::records_in_range"); + DBUG_RETURN(FEDERATED_RECORDS_IN_RANGE); +} /* If frm_error() is called then we will use this to to find out what file extentions exist for the storage engine. This is also used by the default rename_table and delete_table method in handler.cc. */ -static const char *ha_federated_exts[] = { - NullS -}; const char **ha_federated::bas_ext() const { - return ha_federated_exts; + static const char *ext[]= + { + NullS + }; + return ext; } @@ -969,6 +1426,7 @@ const char **ha_federated::bas_ext() const int ha_federated::open(const char *name, int mode, uint test_if_locked) { + int rc; DBUG_ENTER("ha_federated::open"); if (!(share= get_share(name, table))) @@ -977,11 +1435,6 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) /* Connect to foreign database mysql_real_connect() */ mysql= mysql_init(0); - DBUG_PRINT("info", ("hostname %s", share->hostname)); - DBUG_PRINT("info", ("username %s", share->username)); - DBUG_PRINT("info", ("password %s", share->password)); - DBUG_PRINT("info", ("database %s", share->database)); - DBUG_PRINT("info", ("port %d", share->port)); if (!mysql_real_connect(mysql, share->hostname, share->username, @@ -990,8 +1443,13 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) share->port, share->socket, 0)) { - my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_CONNECT_TO_MASTER); + int error_code; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + error_code= ER_CONNECT_TO_FOREIGN_DATA_SOURCE; + 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); } /* Since we do not support transactions at this version, we can let the client @@ -1016,19 +1474,21 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) int ha_federated::close(void) { + int retval; DBUG_ENTER("ha_federated::close"); /* free the result set */ - if (result) + if (stored_result) { DBUG_PRINT("info", - ("mysql_free_result result at address %lx", result)); - mysql_free_result(result); - result= 0; + ("mysql_free_result result at address %lx", stored_result)); + mysql_free_result(stored_result); + stored_result= 0; } /* Disconnect from mysql */ mysql_close(mysql); - DBUG_RETURN(free_share(share)); + retval= free_share(share); + DBUG_RETURN(retval); } @@ -1085,30 +1545,32 @@ inline uint field_in_record_is_null(TABLE *table, int ha_federated::write_row(byte *buf) { - uint x= 0, num_fields= 0; - Field **field; - query_id_t current_query_id= 1; - ulong tmp_query_id= 1; + bool has_fields= FALSE; uint all_fields_have_same_query_id= 1; - - char insert_buffer[IO_SIZE]; - char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE]; + ulong current_query_id= 1; + ulong tmp_query_id= 1; + char insert_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char values_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; + Field **field; /* The main insert query string */ String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin); - insert_string.length(0); /* The string containing the values to be added to the insert */ String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin); - values_string.length(0); /* The actual value of the field, to be added to the values_string */ String insert_field_value_string(insert_field_value_buffer, sizeof(insert_field_value_buffer), &my_charset_bin); + values_string.length(0); + insert_string.length(0); insert_field_value_string.length(0); DBUG_ENTER("ha_federated::write_row"); - DBUG_PRINT("info", ("table charset name %s csname %s", - table->s->table_charset->name, table->s->table_charset->csname)); + DBUG_PRINT("info", + ("table charset name %s csname %s", + table->s->table_charset->name, + table->s->table_charset->csname)); statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) @@ -1122,22 +1584,27 @@ int ha_federated::write_row(byte *buf) current_query_id= table->in_use->query_id; DBUG_PRINT("info", ("current query id %d", current_query_id)); - /* start off our string */ - insert_string.append("INSERT INTO `"); - insert_string.append(share->table_base_name); - insert_string.append("`"); - /* start both our field and field values strings */ - insert_string.append(" ("); - values_string.append(" VALUES ("); + /* + start both our field and field values strings + */ + insert_string.append(FEDERATED_INSERT); + insert_string.append(FEDERATED_BTICK); + insert_string.append(share->table_name, share->table_name_length); + insert_string.append(FEDERATED_BTICK); + insert_string.append(FEDERATED_OPENPAREN); + + values_string.append(FEDERATED_VALUES); + values_string.append(FEDERATED_OPENPAREN); /* Even if one field is different, all_fields_same_query_id can't remain 0 if it remains 0, then that means no fields were specified in the query such as in the case of INSERT INTO table VALUES (val1, val2, valN) + */ - for (field= table->field; *field; field++, x++) + for (field= table->field; *field; field++) { - if (x > 0 && tmp_query_id != (*field)->query_id) + if (field > table->field && tmp_query_id != (*field)->query_id) all_fields_have_same_query_id= 0; tmp_query_id= (*field)->query_id; @@ -1145,31 +1612,30 @@ int ha_federated::write_row(byte *buf) /* loop through the field pointer array, add any fields to both the values list and the fields list that match the current query id + + You might ask "Why an index variable (has_fields) ?" My answer is that + we need to count how many fields we actually need */ - x=0; - for (field= table->field; *field; field++, x++) + for (field= table->field; *field; field++) { /* if there is a query id and if it's equal to the current query id */ if (((*field)->query_id && (*field)->query_id == current_query_id) || all_fields_have_same_query_id) { - num_fields++; + /* + There are some fields. This will be used later to determine + whether to chop off commas and parens. + */ + has_fields= TRUE; if ((*field)->is_null()) - { - DBUG_PRINT("info", - ("column %d current query id %d field is_null query id %d", - x, current_query_id, (*field)->query_id)); - insert_field_value_string.append("NULL"); - } + insert_field_value_string.append(FEDERATED_NULL); else { - DBUG_PRINT("info", - ("column %d current query id %d field is not null query ID %d", - x, current_query_id, (*field)->query_id)); (*field)->val_str(&insert_field_value_string); /* quote these fields if they require it */ - (*field)->quote_data(&insert_field_value_string); } + (*field)->quote_data(&insert_field_value_string); + } /* append the field name */ insert_string.append((*field)->field_name); @@ -1178,34 +1644,35 @@ int ha_federated::write_row(byte *buf) insert_field_value_string.length(0); /* append commas between both fields and fieldnames */ - insert_string.append(','); - values_string.append(','); - + /* + unfortunately, we can't use the logic + if *(fields + 1) to make the following + appends conditional because we may not append + if the next field doesn't match the condition: + (((*field)->query_id && (*field)->query_id == current_query_id) + */ + insert_string.append(FEDERATED_COMMA); + values_string.append(FEDERATED_COMMA); } } /* - chop of the trailing comma, or if there were no fields, a '(' - So, "INSERT INTO foo (" becomes "INSERT INTO foo " - or, with fields, "INSERT INTO foo (field1, field2," becomes - "INSERT INTO foo (field1, field2" + remove trailing comma */ - insert_string.chop(); - + insert_string.length(insert_string.length() - strlen(FEDERATED_COMMA)); /* if there were no fields, we don't want to add a closing paren AND, we don't want to chop off the last char '(' insert will be "INSERT INTO t1 VALUES ();" */ - DBUG_PRINT("info", ("x %d num fields %d", x, num_fields)); - if (num_fields > 0) + if (has_fields) { /* chops off leading commas */ - values_string.chop(); - insert_string.append(')'); + values_string.length(values_string.length() - strlen(FEDERATED_COMMA)); + insert_string.append(FEDERATED_CLOSEPAREN); } /* we always want to append this, even if there aren't any fields */ - values_string.append(')'); + values_string.append(FEDERATED_CLOSEPAREN); /* add the values */ insert_string.append(values_string); @@ -1214,8 +1681,69 @@ int ha_federated::write_row(byte *buf) if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length())) { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + int error_code; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + 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); + } + + DBUG_RETURN(0); +} + + +int ha_federated::optimize(THD* thd, HA_CHECK_OPT* check_opt) +{ + char query_buffer[STRING_BUFFER_USUAL_SIZE]; + String query(query_buffer, sizeof(query_buffer), &my_charset_bin); + + DBUG_ENTER("ha_federated::optimize"); + + query.length(0); + + query.set_charset(system_charset_info); + query.append(FEDERATED_OPTIMIZE); + query.append(FEDERATED_BTICK); + query.append(share->table_name, share->table_name_length); + query.append(FEDERATED_BTICK); + + if (mysql_real_query(mysql, query.ptr(), query.length())) + { + my_error(-1, MYF(0), mysql_error(mysql)); + DBUG_RETURN(-1); + } + + DBUG_RETURN(0); +} + + +int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt) +{ + char query_buffer[STRING_BUFFER_USUAL_SIZE]; + String query(query_buffer, sizeof(query_buffer), &my_charset_bin); + + DBUG_ENTER("ha_federated::repair"); + + query.length(0); + + query.set_charset(system_charset_info); + query.append(FEDERATED_REPAIR); + query.append(FEDERATED_BTICK); + query.append(share->table_name, share->table_name_length); + query.append(FEDERATED_BTICK); + if (check_opt->flags & T_QUICK) + query.append(FEDERATED_QUICK); + if (check_opt->flags & T_EXTEND) + query.append(FEDERATED_EXTENDED); + if (check_opt->sql_flags & TT_USEFRM) + query.append(FEDERATED_USE_FRM); + + if (mysql_real_query(mysql, query.ptr(), query.length())) + { + my_error(-1, MYF(0), mysql_error(mysql)); + DBUG_RETURN(-1); } DBUG_RETURN(0); @@ -1241,39 +1769,57 @@ int ha_federated::write_row(byte *buf) int ha_federated::update_row(const byte *old_data, byte *new_data) { - uint x= 0; - uint has_a_primary_key= 0; - uint primary_key_field_num; - char old_field_value_buffer[IO_SIZE], new_field_value_buffer[IO_SIZE]; - char update_buffer[IO_SIZE], where_buffer[IO_SIZE]; + /* + This used to control how the query was built. If there was a primary key, + the query would be built such that there was a where clause with only + that column as the condition. This is flawed, because if we have a multi-part + primary key, it would only use the first part! We don't need to do this anyway, + because read_range_first will retrieve the correct record, which is what is used + to build the WHERE clause. We can however use this to append a LIMIT to the end + if there is NOT a primary key. Why do this? Because we only are updating one + record, and LIMIT enforces this. + */ + bool has_a_primary_key= (table->s->primary_key == 0 ? TRUE : FALSE); + /* + buffers for following strings + */ + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char old_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; + char new_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; + char update_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char where_buffer[FEDERATED_QUERY_BUFFER_SIZE]; /* stores the value to be replaced of the field were are updating */ - String old_field_value(old_field_value_buffer, sizeof(old_field_value_buffer), + String old_field_value(old_field_value_buffer, + sizeof(old_field_value_buffer), &my_charset_bin); /* stores the new value of the field */ - String new_field_value(new_field_value_buffer, sizeof(new_field_value_buffer), + String new_field_value(new_field_value_buffer, + sizeof(new_field_value_buffer), &my_charset_bin); /* stores the update query */ - String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin); + String update_string(update_buffer, + sizeof(update_buffer), + &my_charset_bin); /* stores the WHERE clause */ - String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin); + String where_string(where_buffer, + sizeof(where_buffer), + &my_charset_bin); DBUG_ENTER("ha_federated::update_row"); + /* + set string lengths to 0 to avoid misc chars in string + */ old_field_value.length(0); new_field_value.length(0); update_string.length(0); where_string.length(0); - has_a_primary_key= (table->s->primary_key == 0 ? 1 : 0); - primary_key_field_num= has_a_primary_key ? - table->key_info[table->s->primary_key].key_part->fieldnr - 1 : -1; - if (has_a_primary_key) - DBUG_PRINT("info", ("has a primary key")); - - update_string.append("UPDATE `"); - update_string.append(share->table_base_name); - update_string.append("`"); - update_string.append(" SET "); + update_string.append(FEDERATED_UPDATE); + update_string.append(FEDERATED_BTICK); + update_string.append(share->table_name); + update_string.append(FEDERATED_BTICK); + update_string.append(FEDERATED_SET); /* In this loop, we want to match column names to values being inserted @@ -1285,104 +1831,73 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) field=oldvalue */ - for (Field **field= table->field; *field; field++, x++) + for (Field **field= table->field; *field; field++) { - /* - In all of these tests for 'has_a_primary_key', what I'm trying to - accomplish is to only use the primary key in the WHERE clause if the - table has a primary key, as opposed to a table without a primary key - in which case we have to use all the fields to create a WHERE clause - using the old/current values, as well as adding a LIMIT statement - */ - if (has_a_primary_key) - { - if (x == primary_key_field_num) - where_string.append((*field)->field_name); - } - else - where_string.append((*field)->field_name); - + where_string.append((*field)->field_name); update_string.append((*field)->field_name); - update_string.append('='); + update_string.append(FEDERATED_EQ); if ((*field)->is_null()) - { - DBUG_PRINT("info", ("column %d is NULL", x )); - new_field_value.append("NULL"); - } + new_field_value.append(FEDERATED_NULL); else { /* otherwise = */ (*field)->val_str(&new_field_value); (*field)->quote_data(&new_field_value); - if (has_a_primary_key) - { - if (x == primary_key_field_num) - where_string.append("="); - } - else if (!field_in_record_is_null(table, *field, (char*) old_data)) - where_string.append("="); + if (!field_in_record_is_null(table, *field, (char*) old_data)) + where_string.append(FEDERATED_EQ); } - if (has_a_primary_key) - { - if (x == primary_key_field_num) - { - (*field)->val_str(&old_field_value, - (char*) (old_data + (*field)->offset())); - (*field)->quote_data(&old_field_value); - where_string.append(old_field_value); - } - } + if (field_in_record_is_null(table, *field, (char*) old_data)) + where_string.append(FEDERATED_ISNULL); else { - if (field_in_record_is_null(table, *field, (char*) old_data)) - where_string.append(" IS NULL "); - else - { - uint o_len; - (*field)->val_str(&old_field_value, - (char*) (old_data + (*field)->offset())); - o_len= (*field)->pack_length(); - DBUG_PRINT("info", ("o_len %lu", o_len)); - (*field)->quote_data(&old_field_value); - where_string.append(old_field_value); - } + uint o_len; + (*field)->val_str(&old_field_value, + (char*) (old_data + (*field)->offset())); + o_len= (*field)->pack_length(); + (*field)->quote_data(&old_field_value); + where_string.append(old_field_value); } - DBUG_PRINT("info", - ("column %d new value %s old value %s", - x, new_field_value.c_ptr_quick(), old_field_value.c_ptr_quick() )); + update_string.append(new_field_value); new_field_value.length(0); - if (x + 1 < table->s->fields) + /* + Only append conjunctions if we have another field in which + to iterate + */ + if (*(field + 1)) { - update_string.append(", "); - if (!has_a_primary_key) - where_string.append(" AND "); + update_string.append(FEDERATED_COMMA); + where_string.append(FEDERATED_AND); } old_field_value.length(0); } - update_string.append(" WHERE "); + update_string.append(FEDERATED_WHERE); update_string.append(where_string); - if (! has_a_primary_key) - update_string.append(" LIMIT 1"); + /* + If this table has not a primary key, then we could possibly + update multiple rows. We want to make sure to only update one! + */ + if (!has_a_primary_key) + update_string.append(FEDERATED_LIMIT1); - DBUG_PRINT("info", ("Final update query: %s", - update_string.c_ptr_quick())); if (mysql_real_query(mysql, update_string.ptr(), update_string.length())) { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + 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); } - - DBUG_RETURN(0); } /* - This will delete a row. 'buf' will contain a copy of the row to be deleted. + This will delete a row. 'buf' will contain a copy of the row to be =deleted. The server will call this right after the current row has been called (from either a previous rnd_nexT() or index call). If you keep a pointer to the last row or can access a primary key it will @@ -1398,49 +1913,60 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) int ha_federated::delete_row(const byte *buf) { - char delete_buffer[IO_SIZE]; - char data_buffer[IO_SIZE]; + char delete_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char data_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin); String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin); + delete_string.length(0); + data_string.length(0); + DBUG_ENTER("ha_federated::delete_row"); - delete_string.length(0); - delete_string.append("DELETE FROM `"); - delete_string.append(share->table_base_name); - delete_string.append("`"); - delete_string.append(" WHERE "); + delete_string.append(FEDERATED_DELETE); + delete_string.append(FEDERATED_FROM); + delete_string.append(FEDERATED_BTICK); + delete_string.append(share->table_name); + delete_string.append(FEDERATED_BTICK); + delete_string.append(FEDERATED_WHERE); for (Field **field= table->field; *field; field++) { - Field *cur_field= *field; - data_string.length(0); - delete_string.append(cur_field->field_name); + delete_string.append((*field)->field_name); - if (cur_field->is_null_in_record((const uchar*) buf)) + if ((*field)->is_null()) { - delete_string.append(" IS "); - data_string.append("NULL"); + delete_string.append(FEDERATED_IS); + data_string.append(FEDERATED_NULL); } else { - delete_string.append("="); - cur_field->val_str(&data_string, (char*) buf+ cur_field->offset()); - cur_field->quote_data(&data_string); + delete_string.append(FEDERATED_EQ); + (*field)->val_str(&data_string); + (*field)->quote_data(&data_string); } delete_string.append(data_string); - delete_string.append(" AND "); + data_string.length(0); + + if (*(field + 1)) + delete_string.append(FEDERATED_AND); } - delete_string.length(delete_string.length()-5); // Remove AND - delete_string.append(" LIMIT 1"); + delete_string.append(FEDERATED_LIMIT1); DBUG_PRINT("info", ("Delete sql: %s", delete_string.c_ptr_quick())); if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length())) { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + int error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + my_error(error_code, MYF(0), error_buffer); + DBUG_RETURN(error_code); } + deleted+= mysql->affected_rows; + DBUG_PRINT("info", + ("rows deleted %d rows deleted for all time %d", + int(mysql->affected_rows), deleted)); DBUG_RETURN(0); } @@ -1454,12 +1980,12 @@ int ha_federated::delete_row(const byte *buf) */ int ha_federated::index_read(byte *buf, const byte *key, - uint key_len __attribute__ ((unused)), - enum ha_rkey_function find_flag - __attribute__ ((unused))) + uint key_len, enum ha_rkey_function find_flag) { + int retval; DBUG_ENTER("ha_federated::index_read"); - DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag)); + retval= index_read_idx(buf, active_index, key, key_len, find_flag); + DBUG_RETURN(retval); } @@ -1473,17 +1999,23 @@ int ha_federated::index_read(byte *buf, const byte *key, */ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, - uint key_len __attribute__ ((unused)), - enum ha_rkey_function find_flag - __attribute__ ((unused))) + uint key_len, enum ha_rkey_function find_flag) { - char index_value[IO_SIZE]; - String index_string(index_value, sizeof(index_value), &my_charset_bin); - index_string.length(0); - uint keylen; + int retval; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char index_value[STRING_BUFFER_USUAL_SIZE]; + char key_value[STRING_BUFFER_USUAL_SIZE]; + char test_value[STRING_BUFFER_USUAL_SIZE]; + char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + String index_string(index_value, + sizeof(index_value), + &my_charset_bin); + String sql_query(sql_query_buffer, + sizeof(sql_query_buffer), + &my_charset_bin); + key_range range; - char sql_query_buffer[IO_SIZE]; - String sql_query(sql_query_buffer, sizeof(sql_query_buffer), &my_charset_bin); + index_string.length(0); sql_query.length(0); DBUG_ENTER("ha_federated::index_read_idx"); @@ -1492,10 +2024,14 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, &LOCK_status); sql_query.append(share->select_query); - sql_query.append(" WHERE "); - keylen= strlen((char*) (key)); - create_where_from_key(&index_string, &table->key_info[index], key, keylen); + range.key= key; + range.length= key_len; + range.flag= find_flag; + create_where_from_key(&index_string, + &table->key_info[index], + &range, + NULL, 0); sql_query.append(index_string); DBUG_PRINT("info", @@ -1507,42 +2043,50 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, ("current position %d sql_query %s", current_position, sql_query.c_ptr_quick())); - if (result) + if (stored_result) { - mysql_free_result(result); - result= 0; + mysql_free_result(stored_result); + stored_result= 0; } if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length())) { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); + retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + goto error; } - result= mysql_store_result(mysql); + stored_result= mysql_store_result(mysql); - if (!result) + if (!stored_result) { - table->status= STATUS_NOT_FOUND; - DBUG_RETURN(HA_ERR_END_OF_FILE); + retval= HA_ERR_END_OF_FILE; + goto error; } + /* + This basically says that the record in table->record[0] is legal, + and that it is ok to use this record, for whatever reason, such + as with a join (without it, joins will not work) + */ + table->status= 0; + + retval= rnd_next(buf); + DBUG_RETURN(retval); - if (mysql_errno(mysql)) +error: + if (stored_result) { - table->status= STATUS_NOT_FOUND; - DBUG_RETURN(mysql_errno(mysql)); + mysql_free_result(stored_result); + stored_result= 0; } - /* - This basically says that the record in table->record[0] is legal, and that it is - ok to use this record, for whatever reason, such as with a join (without it, joins - will not work) - */ - table->status=0; - - DBUG_RETURN(rnd_next(buf)); + table->status= STATUS_NOT_FOUND; + my_error(retval, MYF(0), error_buffer); + DBUG_RETURN(retval); } /* Initialized at each key walk (called multiple times unlike rnd_init()) */ int ha_federated::index_init(uint keynr) { + int error; DBUG_ENTER("ha_federated::index_init"); DBUG_PRINT("info", ("table: '%s' key: %d", table->s->table_name, keynr)); @@ -1550,14 +2094,90 @@ int ha_federated::index_init(uint keynr) DBUG_RETURN(0); } +/* + + int read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted); +*/ +int ha_federated::read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted) +{ + char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + int retval; + String sql_query(sql_query_buffer, + sizeof(sql_query_buffer), + &my_charset_bin); + + DBUG_ENTER("ha_federated::read_range_first"); + if (start_key == NULL && end_key == NULL) + DBUG_RETURN(0); + + sql_query.length(0); + sql_query.append(share->select_query); + create_where_from_key(&sql_query, + &table->key_info[active_index], + start_key, end_key, 0); + + if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length())) + { + retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + goto error; + } + sql_query.length(0); + + if (stored_result) + { + DBUG_PRINT("info", + ("mysql_free_result address %lx", stored_result)); + mysql_free_result(stored_result); + stored_result= 0; + } + stored_result= mysql_store_result(mysql); + + if (!stored_result) + { + retval= HA_ERR_END_OF_FILE; + goto error; + } + + /* This was successful, please let it be known! */ + table->status= 0; + + retval= rnd_next(table->record[0]); + DBUG_RETURN(retval); + +error: + table->status= STATUS_NOT_FOUND; + if (stored_result) + { + DBUG_PRINT("info", ("mysql_free_result address %lx", stored_result)); + mysql_free_result(stored_result); + stored_result= 0; + } + DBUG_RETURN(retval); +} + +int ha_federated::read_range_next() +{ + int retval; + DBUG_ENTER("ha_federated::read_range_next"); + retval= rnd_next(table->record[0]); + DBUG_RETURN(retval); +} + + /* Used to read forward through the index. */ int ha_federated::index_next(byte *buf) { + int retval; DBUG_ENTER("ha_federated::index_next"); - DBUG_RETURN(rnd_next(buf)); + statistic_increment(table->in_use->status_var.ha_read_next_count, + &LOCK_status); + retval= rnd_next(buf); + DBUG_RETURN(retval); } - - /* rnd_init() is called when the system wants the storage engine to do a table scan. @@ -1573,12 +2193,15 @@ int ha_federated::index_next(byte *buf) int ha_federated::rnd_init(bool scan) { - DBUG_ENTER("ha_federated::rnd_init"); + int num_fields, rows; + int retval; + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + DBUG_ENTER("ha_federated::rnd_init"); /* - This 'scan' flag is incredibly important for this handler to work - properly, especially with updates containing WHERE clauses using - indexed columns. + The use of the 'scan' flag is incredibly important for this handler + to work properly, especially with updates containing WHERE clauses + using indexed columns. When the initial query contains a WHERE clause of the query using an indexed column, it's index_read_idx that selects the exact record from @@ -1613,40 +2236,48 @@ int ha_federated::rnd_init(bool scan) if (scan) { DBUG_PRINT("info", ("share->select_query %s", share->select_query)); - if (result) + if (stored_result) { DBUG_PRINT("info", - ("mysql_free_result address %lx", result)); - mysql_free_result(result); - result= 0; + ("mysql_free_result address %lx", stored_result)); + mysql_free_result(stored_result); + stored_result= 0; } - if (mysql_real_query - (mysql, share->select_query, strlen(share->select_query))) - { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); - } - result= mysql_store_result(mysql); + if (mysql_real_query(mysql, + share->select_query, + strlen(share->select_query))) + goto error; - if (mysql_errno(mysql)) - DBUG_RETURN(mysql_errno(mysql)); + stored_result= mysql_store_result(mysql); + if (!stored_result) + goto error; } DBUG_RETURN(0); + +error: + retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); + my_error(retval, MYF(0), error_buffer); + DBUG_PRINT("info", + ("return error code %d", retval)); + DBUG_RETURN(retval); } int ha_federated::rnd_end() { + int retval; DBUG_ENTER("ha_federated::rnd_end"); - if (result) + + if (stored_result) { - DBUG_PRINT("info", ("mysql_free_result address %lx", result)); - mysql_free_result(result); - result= 0; + DBUG_PRINT("info", ("mysql_free_result address %lx", stored_result)); + mysql_free_result(stored_result); + stored_result= 0; } - - mysql_free_result(result); - DBUG_RETURN(index_end()); + retval= index_end(); + DBUG_RETURN(retval); } int ha_federated::index_end(void) @@ -1668,10 +2299,11 @@ int ha_federated::index_end(void) int ha_federated::rnd_next(byte *buf) { + int retval; MYSQL_ROW row; DBUG_ENTER("ha_federated::rnd_next"); - if (result == 0) + if (stored_result == 0) { /* Return value of rnd_init is not always checked (see records.cc), @@ -1682,12 +2314,13 @@ int ha_federated::rnd_next(byte *buf) } /* Fetch a row, insert it back in a row format. */ - current_position= result->data_cursor; + current_position= stored_result->data_cursor; DBUG_PRINT("info", ("current position %d", current_position)); - if (!(row= mysql_fetch_row(result))) + if (!(row= mysql_fetch_row(stored_result))) DBUG_RETURN(HA_ERR_END_OF_FILE); - DBUG_RETURN(convert_row_to_internal_format(buf, row)); + retval= convert_row_to_internal_format(buf, row); + DBUG_RETURN(retval); } @@ -1734,13 +2367,15 @@ int ha_federated::rnd_pos(byte *buf, byte *pos) */ if (scan_flag) { + int retval; statistic_increment(table->in_use->status_var.ha_read_rnd_count, &LOCK_status); memcpy_fixed(¤t_position, pos, sizeof(MYSQL_ROW_OFFSET)); // pos /* is not aligned */ - result->current_row= 0; - result->data_cursor= current_position; - DBUG_RETURN(rnd_next(buf)); + stored_result->current_row= 0; + stored_result->data_cursor= current_position; + retval= rnd_next(buf); + DBUG_RETURN(retval); } DBUG_RETURN(0); } @@ -1789,12 +2424,91 @@ int ha_federated::rnd_pos(byte *buf, byte *pos) sql_update.cc */ -/* FIX: later version provide better information to the optimizer */ void ha_federated::info(uint flag) { + char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char status_buf[FEDERATED_QUERY_BUFFER_SIZE]; + char escaped_table_name[FEDERATED_QUERY_BUFFER_SIZE]; + int error; + uint error_code; + MYSQL_RES *result= 0; + MYSQL_ROW row; + String status_query_string(status_buf, sizeof(status_buf), &my_charset_bin); + DBUG_ENTER("ha_federated::info"); - records= 10000; // fix later + + error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE; + /* we want not to show table status if not needed to do so */ + if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST)) + { + status_query_string.length(0); + status_query_string.append(FEDERATED_INFO); + status_query_string.append(FEDERATED_SQUOTE); + + escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name, + sizeof(escaped_table_name), + share->table_name, + share->table_name_length); + status_query_string.append(escaped_table_name); + status_query_string.append(FEDERATED_SQUOTE); + + if (mysql_real_query(mysql, status_query_string.ptr(), + status_query_string.length())) + goto error; + + status_query_string.length(0); + + result= mysql_store_result(mysql); + if (!result) + goto error; + + if (!mysql_num_rows(result)) + goto error; + + if (!(row= mysql_fetch_row(result))) + goto error; + + if (flag & HA_STATUS_VARIABLE | HA_STATUS_CONST) + { + /* + deleted is set in ha_federated::info + */ + /* + need to figure out what this means as far as federated is concerned, + since we don't have a "file" + + data_file_length = ? + index_file_length = ? + delete_length = ? + */ + if (row[4] != NULL) + records= (ha_rows) my_strtoll10(row[4], (char**) 0, &error); + if (row[5] != NULL) + mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0, &error); + if (row[12] != NULL) + update_time= (ha_rows) my_strtoll10(row[12], (char**) 0, &error); + if (row[13] != NULL) + check_time= (ha_rows) my_strtoll10(row[13], (char**) 0, &error); + } + if (flag & HA_STATUS_CONST) + { + TABLE_SHARE *share= table->s; + block_size= 4096; + } + } + + if (result) + mysql_free_result(result); + + DBUG_VOID_RETURN; + +error: + if (result) + mysql_free_result(result); + my_sprintf(error_buffer, (error_buffer, ": %d : %s", + mysql_errno(mysql), mysql_error(mysql))); + my_error(error_code, MYF(0), error_buffer); DBUG_VOID_RETURN; } @@ -1815,22 +2529,30 @@ int ha_federated::delete_all_rows() { DBUG_ENTER("ha_federated::delete_all_rows"); - char query_buffer[IO_SIZE]; + char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); query.length(0); query.set_charset(system_charset_info); - query.append("TRUNCATE `"); - query.append(share->table_base_name); - query.append("`"); + query.append(FEDERATED_TRUNCATE); + query.append(FEDERATED_BTICK); + query.append(share->table_name); + query.append(FEDERATED_BTICK); + /* + TRUNCATE won't return anything in mysql_affected_rows + */ + deleted+= records; if (mysql_real_query(mysql, query.ptr(), query.length())) { - my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + 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); } - - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(0); } @@ -1878,7 +2600,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !thd->in_lock_tables && !thd->tablespace_op) + lock_type <= TL_WRITE) && !thd->in_lock_tables) lock_type= TL_WRITE_ALLOW_WRITE; /* @@ -1908,28 +2630,33 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, int ha_federated::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { - int connection_error=0; - FEDERATED_SHARE tmp; + int retval= 0; + /* + only a temporary share, to test the url + */ + FEDERATED_SHARE tmp_share; DBUG_ENTER("ha_federated::create"); - if (parse_url(&tmp, table_arg, 1)) - { - my_error(ER_CANT_CREATE_TABLE, MYF(0), name, 1); + if ((retval= parse_url(&tmp_share, table_arg, 1))) goto error; - } - if ((connection_error= check_foreign_data_source(&tmp))) - { - my_error(connection_error, MYF(0), name, 1); + + if ((retval= check_foreign_data_source(&tmp_share, 1))) goto error; + + if (tmp_share.scheme) + { + my_free((gptr) tmp_share.scheme, MYF(0)); + tmp_share.scheme= 0; } - - my_free((gptr) tmp.scheme, MYF(0)); - DBUG_RETURN(0); - + DBUG_RETURN(retval); + error: - DBUG_PRINT("info", ("errors, returning %d", ER_CANT_CREATE_TABLE)); - my_free((gptr) tmp.scheme, MYF(0)); - DBUG_RETURN(ER_CANT_CREATE_TABLE); + if (tmp_share.scheme) + { + my_free((gptr) tmp_share.scheme, MYF(0)); + tmp_share.scheme= 0; + } + DBUG_RETURN(retval); } #endif /* HAVE_FEDERATED_DB */ diff --git a/sql/ha_federated.h b/sql/ha_federated.h index f084976718c..58b78ab0dde 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -26,16 +26,95 @@ #endif #include <mysql.h> -//#include <client.h> + +#define FEDERATED_QUERY_BUFFER_SIZE STRING_BUFFER_USUAL_SIZE * 5 +#define FEDERATED_RECORDS_IN_RANGE 2 + +#define FEDERATED_INFO " SHOW TABLE STATUS LIKE " +#define FEDERATED_INFO_LEN sizeof(FEDERATED_INFO) +#define FEDERATED_SELECT "SELECT " +#define FEDERATED_SELECT_LEN sizeof(FEDERATED_SELECT) +#define FEDERATED_WHERE " WHERE " +#define FEDERATED_WHERE_LEN sizeof(FEDERATED_WHERE) +#define FEDERATED_FROM " FROM " +#define FEDERATED_FROM_LEN sizeof(FEDERATED_FROM) +#define FEDERATED_PERCENT "%" +#define FEDERATED_PERCENT_LEN sizeof(FEDERATED_PERCENT) +#define FEDERATED_IS " IS " +#define FEDERATED_IS_LEN sizeof(FEDERATED_IS) +#define FEDERATED_NULL " NULL " +#define FEDERATED_NULL_LEN sizeof(FEDERATED_NULL) +#define FEDERATED_ISNULL " IS NULL " +#define FEDERATED_ISNULL_LEN sizeof(FEDERATED_ISNULL) +#define FEDERATED_LIKE " LIKE " +#define FEDERATED_LIKE_LEN sizeof(FEDERATED_LIKE) +#define FEDERATED_TRUNCATE "TRUNCATE " +#define FEDERATED_TRUNCATE_LEN sizeof(FEDERATED_TRUNCATE) +#define FEDERATED_DELETE "DELETE " +#define FEDERATED_DELETE_LEN sizeof(FEDERATED_DELETE) +#define FEDERATED_INSERT "INSERT INTO " +#define FEDERATED_INSERT_LEN sizeof(FEDERATED_INSERT) +#define FEDERATED_OPTIMIZE "OPTIMIZE TABLE " +#define FEDERATED_OPTIMIZE_LEN sizeof(FEDERATED_OPTIMIZE) +#define FEDERATED_REPAIR "REPAIR TABLE " +#define FEDERATED_REPAIR_LEN sizeof(FEDERATED_REPAIR) +#define FEDERATED_QUICK " QUICK" +#define FEDERATED_QUICK_LEN sizeof(FEDERATED_QUICK) +#define FEDERATED_EXTENDED " EXTENDED" +#define FEDERATED_EXTENDED_LEN sizeof(FEDERATED_EXTENDED) +#define FEDERATED_USE_FRM " USE_FRM" +#define FEDERATED_USE_FRM_LEN sizeof(FEDERATED_USE_FRM) +#define FEDERATED_LIMIT1 " LIMIT 1" +#define FEDERATED_LIMIT1_LEN sizeof(FEDERATED_LIMIT1) +#define FEDERATED_VALUES "VALUES " +#define FEDERATED_VALUES_LEN sizeof(FEDERATED_VALUES) +#define FEDERATED_UPDATE "UPDATE " +#define FEDERATED_UPDATE_LEN sizeof(FEDERATED_UPDATE) +#define FEDERATED_SET "SET " +#define FEDERATED_SET_LEN sizeof(FEDERATED_SET) +#define FEDERATED_AND " AND " +#define FEDERATED_AND_LEN sizeof(FEDERATED_AND) +#define FEDERATED_CONJUNCTION ") AND (" +#define FEDERATED_CONJUNCTION_LEN sizeof(FEDERATED_CONJUNCTION) +#define FEDERATED_OR " OR " +#define FEDERATED_OR_LEN sizeof(FEDERATED_OR) +#define FEDERATED_NOT " NOT " +#define FEDERATED_NOT_LEN sizeof(FEDERATED_NOT) +#define FEDERATED_STAR "* " +#define FEDERATED_STAR_LEN sizeof(FEDERATED_STAR) +#define FEDERATED_SPACE " " +#define FEDERATED_SPACE_LEN sizeof(FEDERATED_SPACE) +#define FEDERATED_SQUOTE "'" +#define FEDERATED_SQUOTE_LEN sizeof(FEDERATED_SQUOTE) +#define FEDERATED_COMMA ", " +#define FEDERATED_COMMA_LEN sizeof(FEDERATED_COMMA) +#define FEDERATED_BTICK "`" +#define FEDERATED_BTICK_LEN sizeof(FEDERATED_BTICK) +#define FEDERATED_OPENPAREN " (" +#define FEDERATED_OPENPAREN_LEN sizeof(FEDERATED_OPENPAREN) +#define FEDERATED_CLOSEPAREN ") " +#define FEDERATED_CLOSEPAREN_LEN sizeof(FEDERATED_CLOSEPAREN) +#define FEDERATED_NE " != " +#define FEDERATED_NE_LEN sizeof(FEDERATED_NE) +#define FEDERATED_GT " > " +#define FEDERATED_GT_LEN sizeof(FEDERATED_GT) +#define FEDERATED_LT " < " +#define FEDERATED_LT_LEN sizeof(FEDERATED_LT) +#define FEDERATED_LE " <= " +#define FEDERATED_LE_LEN sizeof(FEDERATED_LE) +#define FEDERATED_GE " >= " +#define FEDERATED_GE_LEN sizeof(FEDERATED_GE) +#define FEDERATED_EQ " = " +#define FEDERATED_EQ_LEN sizeof(FEDERATED_EQ) +#define FEDERATED_FALSE " 1=0" +#define FEDERATED_FALSE_LEN sizeof(FEDERATED_FALSE) /* FEDERATED_SHARE is a structure that will be shared amoung all open handlers The example implements the minimum of what you will probably need. */ typedef struct st_federated_share { - char *table_name; - char *table_base_name; - /* + /* the primary select query to be used in rnd_init */ char *select_query; @@ -47,11 +126,12 @@ typedef struct st_federated_share { char *username; char *password; char *database; + char *table_name; char *table; char *socket; char *sport; - int port; - uint table_name_length,table_base_name_length,use_count; + ushort port; + uint table_name_length, use_count; pthread_mutex_t mutex; THR_LOCK lock; } FEDERATED_SHARE; @@ -63,8 +143,8 @@ class ha_federated: public handler { THR_LOCK_DATA lock; /* MySQL lock */ FEDERATED_SHARE *share; /* Shared lock info */ - MYSQL *mysql; - MYSQL_RES *result; + MYSQL *mysql; /* MySQL connection */ + MYSQL_RES *stored_result; bool scan_flag; uint ref_length; uint fetch_num; // stores the fetch num @@ -77,14 +157,12 @@ private: */ uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row); bool create_where_from_key(String *to, KEY *key_info, - const byte *key, uint key_length); + const key_range *start_key, + const key_range *end_key, + bool records_in_range); public: - ha_federated(TABLE *table): handler(table), - mysql(0), result(0), scan_flag(0), - ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) - { - } + ha_federated(TABLE *table_arg); ~ha_federated() { } @@ -94,20 +172,20 @@ public: The name of the index type that will be used for display don't implement this method unless you really have indexes */ + // perhaps get index type const char *index_type(uint inx) { return "REMOTE"; } const char **bas_ext() const; /* This is a list of flags that says what the storage engine implements. The current table flags are documented in handler.h - Serg: Double check these (Brian) - // FIX add blob support */ ulong table_flags() const { - return (HA_TABLE_SCAN_ON_INDEX | HA_NOT_EXACT_COUNT | - HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | - HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS); + /* fix server to be able to get remote server table flags */ + return (HA_NOT_EXACT_COUNT | + HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | HA_REC_NOT_IN_SEQ | + HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS| HA_NO_PREFIX_CHAR_KEYS); } /* This is a bitmap of flags that says how the storage engine @@ -119,29 +197,45 @@ public: If all_parts it's set, MySQL want to know the flags for the combined index up to and including 'part'. */ + /* fix server to be able to get remote server index flags */ ulong index_flags(uint inx, uint part, bool all_parts) const { - return (HA_READ_NEXT); - // return (HA_READ_NEXT | HA_ONLY_WHOLE_INDEX); + return (HA_READ_NEXT | HA_READ_RANGE | HA_READ_AFTER_KEY); } uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; } uint max_supported_keys() const { return MAX_KEY; } - uint max_supported_key_parts() const { return 1024; } - uint max_supported_key_length() const { return 1024; } + uint max_supported_key_parts() const { return MAX_REF_PARTS; } + uint max_supported_key_length() const { return MAX_KEY_LENGTH; } /* Called in test_quick_select to determine if indexes should be used. + Normally, we need to know number of blocks . For federated we need to + know number of blocks on remote side, and number of packets and blocks + on the network side (?) + Talk to Kostja about this - how to get the + number of rows * ... + disk scan time on other side (block size, size of the row) + network time ... + The reason for "records * 1000" is that such a large number forces + this to use indexes " */ - virtual double scan_time() + double scan_time() { - DBUG_PRINT("ha_federated::scan_time", - ("rows %d", records)); return (double)(records*2); + DBUG_PRINT("info", + ("records %d", records)); + return (double)(records*1000); } /* The next method will never be called if you do not implement indexes. */ - virtual double read_time(uint index, uint ranges, ha_rows rows) - { return (double) rows / 20.0+1; } + double read_time(uint index, uint ranges, ha_rows rows) + { + /* + Per Brian, this number is bugus, but this method must be implemented, + and at a later date, he intends to document this issue for handler code + */ + return (double) rows / 20.0+1; + } + const key_map *keys_to_use_for_scanning() { return &key_map_full; } /* Everything below are methods that we implment in ha_federated.cc. @@ -151,16 +245,20 @@ public: int open(const char *name, int mode, uint test_if_locked); // required int close(void); // required - int write_row(byte * buf); - int update_row(const byte * old_data, byte * new_data); - int delete_row(const byte * buf); + int write_row(byte *buf); + int update_row(const byte *old_data, byte *new_data); + int delete_row(const byte *buf); int index_init(uint keynr); - int index_read(byte * buf, const byte * key, + int index_read(byte *buf, const byte *key, uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, + int index_read_idx(byte *buf, uint idx, const byte *key, uint key_len, enum ha_rkey_function find_flag); - int index_next(byte * buf); + int index_next(byte *buf); int index_end(); + int read_range_first(const key_range *start_key, + const key_range *end_key, + bool eq_range, bool sorted); + int read_range_next(); /* unlike index_init(), rnd_init() can be called two times without rnd_end() in between (it only makes sense if scan=1). @@ -172,13 +270,18 @@ public: int rnd_init(bool scan); //required int rnd_end(); int rnd_next(byte *buf); //required - int rnd_pos(byte * buf, byte *pos); //required + int rnd_pos(byte *buf, byte *pos); //required void position(const byte *record); //required void info(uint); //required + int repair(THD* thd, HA_CHECK_OPT* check_opt); + int optimize(THD* thd, HA_CHECK_OPT* check_opt); + int delete_all_rows(void); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); //required + ha_rows records_in_range(uint inx, key_range *start_key, + key_range *end_key); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); //required diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 6e609a94be3..94ee3f8e656 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -23,9 +23,36 @@ #include <myisampack.h> #include "ha_heap.h" +static handlerton heap_hton= { + "MEMORY", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + /***************************************************************************** ** HEAP tables *****************************************************************************/ + +ha_heap::ha_heap(TABLE *table_arg) + :handler(&heap_hton, table_arg), file(0), records_changed(0), + key_stats_ok(0) +{} + + static const char *ha_heap_exts[] = { NullS }; diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 7a97c727049..f7368436456 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -31,8 +31,7 @@ class ha_heap: public handler uint records_changed; bool key_stats_ok; public: - ha_heap(TABLE *table): handler(table), file(0), records_changed(0), - key_stats_ok(0) {} + ha_heap(TABLE *table); ~ha_heap() {} const char *table_type() const { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e33a0939e27..d40e58aa4cb 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -215,7 +215,11 @@ static handlerton innobase_hton = { innobase_xa_prepare, /* prepare */ innobase_xa_recover, /* recover */ innobase_commit_by_xid, /* commit_by_xid */ - innobase_rollback_by_xid /* rollback_by_xid */ + innobase_rollback_by_xid, /* rollback_by_xid */ + innobase_create_cursor_view, + innobase_set_cursor_view, + innobase_close_cursor_view, + HTON_NO_FLAGS }; /********************************************************************* @@ -765,6 +769,24 @@ check_trx_exists( return(trx); } + +/************************************************************************* +Construct ha_innobase handler. */ + +ha_innobase::ha_innobase(TABLE *table_arg) + :handler(&innobase_hton, table_arg), + int_table_flags(HA_REC_NOT_IN_SEQ | + HA_NULL_IN_KEY | + HA_CAN_INDEX_BLOBS | + HA_CAN_SQL_HANDLER | + HA_NOT_EXACT_COUNT | + HA_PRIMARY_KEY_IN_READ_INDEX | + HA_TABLE_SCAN_ON_INDEX), + last_dup_key((uint) -1), + start_of_scan(0), + num_write_row(0) +{} + /************************************************************************* Updates the user_thd field in a handle and also allocates a new InnoDB transaction handle if needed, and updates the transaction fields in the @@ -5484,7 +5506,7 @@ ha_innobase::update_table_comment( external_lock(). To be safe, update the thd of the current table handle. */ - if(length > 64000 - 3) { + if (length > 64000 - 3) { return((char*)comment); /* string too long */ } @@ -5522,7 +5544,7 @@ ha_innobase::update_table_comment( if (str) { char* pos = str + length; - if(length) { + if (length) { memcpy(str, comment, length); *pos++ = ';'; *pos++ = ' '; @@ -5580,7 +5602,7 @@ ha_innobase::get_foreign_key_create_info(void) flen = ftell(file); if (flen < 0) { flen = 0; - } else if(flen > 64000 - 1) { + } else if (flen > 64000 - 1) { flen = 64000 - 1; } @@ -5857,7 +5879,7 @@ ha_innobase::start_stmt( innobase_release_stat_resources(trx); if (trx->isolation_level <= TRX_ISO_READ_COMMITTED - && trx->read_view) { + && trx->global_read_view) { /* At low transaction isolation levels we let each consistent read set its own snapshot */ @@ -6078,7 +6100,7 @@ ha_innobase::external_lock( } } else { if (trx->isolation_level <= TRX_ISO_READ_COMMITTED - && trx->read_view) { + && trx->global_read_view) { /* At low transaction isolation levels we let each consistent read set its own snapshot */ @@ -7108,4 +7130,45 @@ innobase_rollback_by_xid( } } +/*********************************************************************** +This function creates a consistent view for a cursor and start a transaction +if it has not been started. This consistent view is then used inside of MySQL +when accesing records using a cursor. */ + +void* +innobase_create_cursor_view(void) +/*=============================*/ + /* out: Pointer to cursor view or NULL */ +{ + return(read_cursor_view_create_for_mysql( + check_trx_exists(current_thd))); +} + +/*********************************************************************** +This function closes the given consistent cursor view. Note that +global read view is restored to a transaction and a transaction is +started if it has not been started. */ + +void +innobase_close_cursor_view( +/*=======================*/ + void* curview)/* in: Consistent read view to be closed */ +{ + read_cursor_view_close_for_mysql(check_trx_exists(current_thd), + (cursor_view_t*) curview); +} + +/*********************************************************************** +This function sets the given consistent cursor view to a transaction. +If a transaction does not exist, transaction is started. */ + +void +innobase_set_cursor_view( +/*=====================*/ + void* curview)/* in: Consistent cursor view to be closed */ +{ + read_cursor_set_for_mysql(check_trx_exists(current_thd), + (cursor_view_t*) curview); +} + #endif /* HAVE_INNOBASE_DB */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 90cae3998ed..2cbc1c8d91b 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -81,19 +81,7 @@ class ha_innobase: public handler /* Init values for the class: */ public: - ha_innobase(TABLE *table): handler(table), - int_table_flags(HA_REC_NOT_IN_SEQ | - HA_NULL_IN_KEY | - HA_CAN_INDEX_BLOBS | - HA_CAN_SQL_HANDLER | - HA_NOT_EXACT_COUNT | - HA_PRIMARY_KEY_IN_READ_INDEX | - HA_TABLE_SCAN_ON_INDEX), - last_dup_key((uint) -1), - start_of_scan(0), - num_write_row(0) - { - } + ha_innobase(TABLE *table_arg); ~ha_innobase() {} /* Get the row type from the storage engine. If this method returns @@ -322,3 +310,32 @@ int innobase_xa_end(THD *thd); int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, my_off_t end_offset); + +/*********************************************************************** +This function creates a consistent view for a cursor and start a transaction +if it has not been started. This consistent view is then used inside of MySQL +when accesing records using a cursor. */ + +void* +innobase_create_cursor_view(void); +/*=============================*/ + /* out: Pointer to cursor view or NULL */ + +/*********************************************************************** +This function closes the given consistent cursor view. Note that +global read view is restored to a transaction and a transaction is +started if it has not been started. */ + +void +innobase_close_cursor_view( +/*=======================*/ + void* curview); /* in: Consistent read view to be closed */ + +/*********************************************************************** +This function sets the given consistent cursor view to a transaction. +If a transaction does not exist, transaction is started. */ + +void +innobase_set_cursor_view( +/*=====================*/ + void* curview); /* in: Consistent read view to be closed */ diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 0d9c32adbfa..8f3970d69e6 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -44,6 +44,32 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", ** MyISAM tables *****************************************************************************/ +/* MyISAM handlerton */ + +static handlerton myisam_hton= { + "MyISAM", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + /* + MyISAM doesn't support transactions and doesn't have + transaction-dependent context: cursors can survive a commit. + */ + HTON_NO_FLAGS +}; + // collect errors printed by mi_check routines static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, @@ -123,6 +149,17 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) } + +ha_myisam::ha_myisam(TABLE *table_arg) + :handler(&myisam_hton, table_arg), file(0), + int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | + HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | + HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME | + HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD), + can_enable_indexes(1) +{} + + static const char *ha_myisam_exts[] = { ".MYI", ".MYD", @@ -602,7 +639,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) !(share->state.changed & STATE_NOT_OPTIMIZED_KEYS)))) { ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ? - ((ulonglong) 1L << share->base.keys)-1 : + mi_get_mask_all_keys_active(share->base.keys) : share->state.key_map); uint testflag=param.testflag; if (mi_test_if_sort_rep(file,file->state->records,key_map,0) && @@ -903,7 +940,7 @@ int ha_myisam::enable_indexes(uint mode) { int error; - if (file->s->state.key_map == set_bits(ulonglong, file->s->base.keys)) + if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys)) { /* All indexes are enabled already. */ return 0; @@ -1002,8 +1039,8 @@ void ha_myisam::start_bulk_insert(ha_rows rows) if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE)) mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size); - can_enable_indexes= (file->s->state.key_map == - set_bits(ulonglong, file->s->base.keys)); + can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map, + file->s->base.keys); if (!(specialflag & SPECIAL_SAFE_MODE)) { @@ -1256,7 +1293,7 @@ void ha_myisam::info(uint flag) share->db_options_in_use= info.options; block_size= myisam_block_size; share->keys_in_use.set_prefix(share->keys); - share->keys_in_use.intersect(info.key_map); + share->keys_in_use.intersect_extended(info.key_map); share->keys_for_keyread.intersect(share->keys_in_use); share->db_record_offset= info.record_offset; if (share->key_parts) diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index bbd9721f8e2..ca684463311 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -43,13 +43,7 @@ class ha_myisam: public handler int repair(THD *thd, MI_CHECK ¶m, bool optimize); public: - ha_myisam(TABLE *table): handler(table), file(0), - int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | - HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | - HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME | - HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD), - can_enable_indexes(1) - {} + ha_myisam(TABLE *table_arg); ~ha_myisam() {} const char *table_type() const { return "MyISAM"; } const char *index_type(uint key_number); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 5d3f379081c..f92717e11eb 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -32,6 +32,33 @@ ** MyISAM MERGE tables *****************************************************************************/ +/* MyISAM MERGE handlerton */ + +static handlerton myisammrg_hton= { + "MRG_MyISAM", + 0, /* slot */ + 0, /* savepoint size. */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS +}; + + +ha_myisammrg::ha_myisammrg(TABLE *table_arg) + :handler(&myisammrg_hton, table_arg), file(0) +{} + static const char *ha_myisammrg_exts[] = { ".MRG", NullS diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 7348096b695..c762b7c286e 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -28,7 +28,7 @@ class ha_myisammrg: public handler MYRG_INFO *file; public: - ha_myisammrg(TABLE *table): handler(table), file(0) {} + ha_myisammrg(TABLE *table_arg); ~ha_myisammrg() {} const char *table_type() const { return "MRG_MyISAM"; } const char **bas_ext() const; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 27019c94284..86325c2fd45 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -62,7 +62,11 @@ static handlerton ndbcluster_hton = { NULL, /* prepare */ NULL, /* recover */ NULL, /* commit_by_xid */ - NULL /* rollback_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ + HTON_NO_FLAGS }; #define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8 @@ -706,8 +710,8 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, blob_ptr= (char*)""; } - DBUG_PRINT("value", ("set blob ptr=%x len=%u", - (unsigned)blob_ptr, blob_len)); + DBUG_PRINT("value", ("set blob ptr=%p len=%u", + blob_ptr, blob_len)); DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); if (set_blob_value) @@ -4174,7 +4178,7 @@ ulonglong ha_ndbcluster::get_auto_increment() */ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): - handler(table_arg), + handler(&ndbcluster_hton, table_arg), m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), @@ -5445,7 +5449,7 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, Uint64 sum_commits= 0; Uint64 sum_row_size= 0; Uint64 sum_mem= 0; - while((check= pOp->nextResult(TRUE, TRUE)) == 0) + while ((check= pOp->nextResult(TRUE, TRUE)) == 0) { sum_rows+= rows; sum_commits+= commits; @@ -5473,7 +5477,7 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, sum_mem, count)); DBUG_RETURN(0); - } while(0); + } while (0); if (pTrans) ndb->closeTransaction(pTrans); @@ -6564,17 +6568,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case Item_func::NOTLIKE_FUNC: - { - DBUG_PRINT("info", ("NOTLIKE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect(Item::FUNC_ITEM); - break; - } case Item_func::ISNULL_FUNC: { DBUG_PRINT("info", ("ISNULL_FUNC")); @@ -7168,25 +7161,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case Item_func::NOTLIKE_FUNC: - { - if (!value || !field) break; - if ((value->qualification.value_type != Item::STRING_ITEM) && - (value->qualification.value_type != Item::VARBIN_ITEM)) - break; - // Save value in right format for the field type - value->save_in_field(field); - DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)", - field->get_field_no(), value->get_val(), - value->pack_length())); - if (filter->cmp(NdbScanFilter::COND_NOT_LIKE, - field->get_field_no(), - value->get_val(), - value->pack_length()) == -1) - DBUG_RETURN(1); - cond= cond->next->next->next; - DBUG_RETURN(0); - } case Item_func::ISNULL_FUNC: if (!field) break; diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index b34f8dd063c..91cfdde16fe 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -103,8 +103,6 @@ static const negated_function_mapping neg_map[]= {Item_func::LE_FUNC, Item_func::GT_FUNC}, {Item_func::GT_FUNC, Item_func::LE_FUNC}, {Item_func::GE_FUNC, Item_func::LT_FUNC}, - {Item_func::LIKE_FUNC, Item_func::NOTLIKE_FUNC}, - {Item_func::NOTLIKE_FUNC, Item_func::LIKE_FUNC}, {Item_func::ISNULL_FUNC, Item_func::ISNOTNULL_FUNC}, {Item_func::ISNOTNULL_FUNC, Item_func::ISNULL_FUNC}, {Item_func::UNKNOWN_FUNC, Item_func::NOT_FUNC} diff --git a/sql/handler.cc b/sql/handler.cc index a61dce35501..2731cb8480d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -208,15 +208,8 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) case DB_TYPE_HASH: return new ha_hash(table); #endif -#ifdef HAVE_ISAM - case DB_TYPE_MRG_ISAM: - return new ha_isammrg(table); - case DB_TYPE_ISAM: - return new ha_isam(table); -#else case DB_TYPE_MRG_ISAM: return new ha_myisammrg(table); -#endif #ifdef HAVE_BERKELEY_DB case DB_TYPE_BERKELEY_DB: return new ha_berkeley(table); @@ -634,6 +627,11 @@ int ha_commit_trans(THD *thd, bool all) DBUG_RETURN(1); } DBUG_EXECUTE_IF("crash_commit_before", abort();); + + /* Close all cursors that can not survive COMMIT */ + if (is_real_trans) /* not a statement commit */ + thd->stmt_map.close_transient_cursors(); + if (!trans->no_2pc && trans->nht > 1) { for (; *ht && !error; ht++) @@ -735,6 +733,10 @@ int ha_rollback_trans(THD *thd, bool all) #ifdef USING_TRANSACTIONS if (trans->nht) { + /* Close all cursors that can not survive ROLLBACK */ + if (is_real_trans) /* not a statement commit */ + thd->stmt_map.close_transient_cursors(); + for (handlerton **ht=trans->ht; *ht; ht++) { int err; @@ -2099,6 +2101,8 @@ int ha_discover(THD *thd, const char *db, const char *name, int error= -1; // Table does not exist in any handler DBUG_ENTER("ha_discover"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); + if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */ + DBUG_RETURN(error); #ifdef HAVE_NDBCLUSTER_DB if (have_ndbcluster == SHOW_OPTION_YES) error= ndbcluster_discover(thd, db, name, frmblob, frmlen); @@ -2434,6 +2438,7 @@ TYPELIB *ha_known_exts(void) known_extensions_id= mysys_usage_id; found_exts.push_back((char*) triggers_file_ext); + found_exts.push_back((char*) trigname_file_ext); for (types= sys_table_types; types->type; types++) { if (*types->value == SHOW_OPTION_YES) diff --git a/sql/handler.h b/sql/handler.h index df906e284e7..276f50bde63 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -106,9 +106,11 @@ /* Note: the following includes binlog and closing 0. - so: innodb+bdb+ndb+binlog+0 + so: innodb + bdb + ndb + binlog + myisam + myisammrg + archive + + example + csv + heap + blackhole + federated + 0 + (yes, the sum is deliberately inaccurate) */ -#define MAX_HA 6 +#define MAX_HA 14 /* Bits in index_ddl_flags(KEY *wanted_index) @@ -349,8 +351,16 @@ typedef struct int (*recover)(XID *xid_list, uint len); int (*commit_by_xid)(XID *xid); int (*rollback_by_xid)(XID *xid); + void *(*create_cursor_read_view)(); + void (*set_cursor_read_view)(void *); + void (*close_cursor_read_view)(void *); + uint32 flags; /* global handler flags */ } handlerton; +/* Possible flags of a handlerton */ +#define HTON_NO_FLAGS 0 +#define HTON_CLOSE_CURSORS_AT_COMMIT 1 + typedef struct st_thd_trans { /* number of entries in the ht[] */ @@ -445,6 +455,7 @@ class handler :public Sql_alloc virtual int rnd_end() { return 0; } public: + const handlerton *ht; /* storage engine of this handler */ byte *ref; /* Pointer to current row */ byte *dupp_ref; /* Pointer to dupp row */ ulonglong data_file_length; /* Length off data file */ @@ -486,7 +497,8 @@ public: bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; - handler(TABLE *table_arg) :table(table_arg), + handler(const handlerton *ht_arg, TABLE *table_arg) :table(table_arg), + ht(ht_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), delete_length(0), auto_increment_value(0), records(0), deleted(0), mean_rec_length(0), diff --git a/sql/hostname.cc b/sql/hostname.cc index 39223556024..3b1eeb63d37 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)) // is expanded inline by gcc + 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/item.cc b/sql/item.cc index d26e4ba7c20..25a12bc2d67 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1082,6 +1082,176 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) return 0; } +/******************************/ +static +void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) +{ + my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + fname); +} + + +static +void my_coll_agg_error(DTCollation &c1, DTCollation &c2, DTCollation &c3, + const char *fname) +{ + my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + c3.collation->name,c3.derivation_name(), + fname); +} + + +static +void my_coll_agg_error(Item** args, uint count, const char *fname) +{ + if (count == 2) + my_coll_agg_error(args[0]->collation, args[1]->collation, fname); + else if (count == 3) + my_coll_agg_error(args[0]->collation, args[1]->collation, + args[2]->collation, fname); + else + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); +} + + +bool agg_item_collations(DTCollation &c, const char *fname, + Item **av, uint count, uint flags) +{ + uint i; + c.set(av[0]->collation); + for (i= 1; i < count; i++) + { + if (c.aggregate(av[i]->collation, flags)) + { + my_coll_agg_error(av, count, fname); + return TRUE; + } + } + if ((flags & MY_COLL_DISALLOW_NONE) && + c.derivation == DERIVATION_NONE) + { + my_coll_agg_error(av, count, fname); + return TRUE; + } + return FALSE; +} + + +bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, + Item **av, uint count, uint flags) +{ + return (agg_item_collations(c, fname, av, count, + flags | MY_COLL_DISALLOW_NONE)); +} + + +/* + Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + (i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column) + - character set of A is either superset for character set of B, + or B is a string constant which can be converted into the + character set of A without data loss. + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + + For functions with more than two arguments: + + collect(A,B,C) ::= collect(collect(A,B),C) +*/ + +bool agg_item_charsets(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags) +{ + Item **arg, **last, *safe_args[2]; + if (agg_item_collations(coll, fname, args, nargs, flags)) + return TRUE; + + /* + For better error reporting: save the first and the second argument. + We need this only if the the number of args is 3 or 2: + - for a longer argument list, "Illegal mix of collations" + doesn't display each argument's characteristics. + - if nargs is 1, then this error cannot happen. + */ + if (nargs >=2 && nargs <= 3) + { + safe_args[0]= args[0]; + safe_args[1]= args[1]; + } + + THD *thd= current_thd; + Query_arena *arena, backup; + bool res= FALSE; + /* + In case we're in statement prepare, create conversion item + in its memory: it will be reused on each execute. + */ + arena= thd->change_arena_if_needed(&backup); + + for (arg= args, last= args + nargs; arg < last; arg++) + { + Item* conv; + uint32 dummy_offset; + if (!String::needs_conversion(0, coll.collation, + (*arg)->collation.collation, + &dummy_offset)) + continue; + + if (!(conv= (*arg)->safe_charset_converter(coll.collation))) + { + if (nargs >=2 && nargs <= 3) + { + /* restore the original arguments for better error message */ + args[0]= safe_args[0]; + args[1]= safe_args[1]; + } + my_coll_agg_error(args, nargs, fname); + res= TRUE; + break; // we cannot return here, we need to restore "arena". + } + if ((*arg)->type() == Item::FIELD_ITEM) + ((Item_field *)(*arg))->no_const_subst= 1; + /* + If in statement prepare, then we create a converter for two + constant items, do it once and then reuse it. + If we're in execution of a prepared statement, arena is NULL, + and the conv was created in runtime memory. This can be + the case only if the argument is a parameter marker ('?'), + because for all true constants the charset converter has already + been created in prepare. In this case register the change for + rollback. + */ + if (arena) + *arg= conv; + else + thd->change_item_tree(arg, conv); + /* + We do not check conv->fixed, because Item_func_conv_charset which can + be return by safe_charset_converter can't be fixed at creation + */ + conv->fix_fields(thd, arg); + } + if (arena) + thd->restore_backup_item_arena(arena, &backup); + return res; +} + + + + +/**********************************************/ + Item_field::Item_field(Field *f) :Item_ident(0, NullS, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), @@ -2018,6 +2188,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) void Item_param::reset() { + DBUG_ENTER("Item_param::reset"); /* Shrink string buffer if it's bigger than max possible CHAR column */ if (str_value.alloced_length() > MAX_CHAR_WIDTH) str_value.free(); @@ -2042,6 +2213,7 @@ void Item_param::reset() DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_* methods). */ + DBUG_VOID_RETURN; } @@ -3323,7 +3495,12 @@ void Item::make_field(Send_field *tmp_field) void Item_empty_string::make_field(Send_field *tmp_field) { - init_make_field(tmp_field, MYSQL_TYPE_VARCHAR); + enum_field_types type= FIELD_TYPE_VAR_STRING; + if (max_length >= 16777216) + type= FIELD_TYPE_LONG_BLOB; + else if (max_length >= 65536) + type= FIELD_TYPE_MEDIUM_BLOB; + init_make_field(tmp_field, type); } diff --git a/sql/item.h b/sql/item.h index f195557fb69..d3e920faa68 100644 --- a/sql/item.h +++ b/sql/item.h @@ -767,6 +767,15 @@ public: }; +bool agg_item_collations(DTCollation &c, const char *name, + Item **items, uint nitems, uint flags= 0); +bool agg_item_collations_for_comparison(DTCollation &c, const char *name, + Item **items, uint nitems, + uint flags= 0); +bool agg_item_charsets(DTCollation &c, const char *name, + Item **items, uint nitems, uint flags= 0); + + class Item_num: public Item { public: @@ -1142,6 +1151,7 @@ class Item_uint :public Item_int public: Item_uint(const char *str_arg, uint length); Item_uint(uint32 i) :Item_int((ulonglong) i, 10) {} + Item_uint(ulong i) :Item_int((ulonglong) i, 10) {} Item_uint(const char *str_arg, longlong i, uint length); double val_real() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } @@ -1464,7 +1474,13 @@ public: void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } - Field *get_tmp_table_field() { return result_field; } + Field *get_tmp_table_field() + { return result_field ? result_field : (*ref)->get_tmp_table_field(); } + Item *get_tmp_table_item(THD *thd) + { + return (result_field ? new Item_field(result_field) : + (*ref)->get_tmp_table_item(thd)); + } table_map used_tables() const { return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables(); @@ -1702,7 +1718,7 @@ class Cached_item_field :public Cached_item public: Cached_item_field(Item_field *item) { - field=item->field; + field= item->field; buff= (char*) sql_calloc(length=field->pack_length()); } bool cmp(void); @@ -1781,7 +1797,7 @@ public: */ enum trg_action_time_type { - TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1 + TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; /* @@ -1789,7 +1805,7 @@ enum trg_action_time_type */ enum trg_event_type { - TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2 + TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX }; class Table_triggers_list; diff --git a/sql/item_buff.cc b/sql/item_buff.cc index a67e420170a..9db2f465080 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -25,9 +25,9 @@ Cached_item *new_Cached_item(THD *thd, Item *item) { - if (item->type() == Item::FIELD_ITEM && - !(((Item_field *) item)->field->flags & BLOB_FLAG)) - return new Cached_item_field((Item_field *) item); + if (item->real_item()->type() == Item::FIELD_ITEM && + !(((Item_field *) (item->real_item()))->field->flags & BLOB_FLAG)) + return new Cached_item_field((Item_field *) (item->real_item())); switch (item->result_type()) { case STRING_RESULT: return new Cached_item_str(thd, (Item_field *) item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d7c117db6c0..d430d0d3c23 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2184,7 +2184,13 @@ void Item_func_in::fix_length_and_dec() return; for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++) - const_itm&= arg[0]->const_item(); + { + if (!arg[0]->const_item()) + { + const_itm= 0; + break; + } + } /* Row item with NULLs inside can return NULL or FALSE => diff --git a/sql/item_func.cc b/sql/item_func.cc index c3bdb11418f..d2fabf4167a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -42,73 +42,6 @@ bool check_reserved_words(LEX_STRING *name) } -static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), - c1.collation->name, c1.derivation_name(), - c2.collation->name, c2.derivation_name(), - fname); -} - -static void my_coll_agg_error(DTCollation &c1, - DTCollation &c2, - DTCollation &c3, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_3COLLATIONS, MYF(0), - c1.collation->name, c1.derivation_name(), - c2.collation->name, c2.derivation_name(), - c3.collation->name, c3.derivation_name(), - fname); -} - - -static void my_coll_agg_error(Item** args, uint count, const char *fname) -{ - if (count == 2) - my_coll_agg_error(args[0]->collation, args[1]->collation, fname); - else if (count == 3) - my_coll_agg_error(args[0]->collation, - args[1]->collation, - args[2]->collation, - fname); - else - my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), fname); -} - - -bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count, - uint flags) -{ - uint i; - c.set(av[0]->collation); - for (i= 1; i < count; i++) - { - if (c.aggregate(av[i]->collation, flags)) - { - my_coll_agg_error(av, count, func_name()); - return TRUE; - } - } - if ((flags & MY_COLL_DISALLOW_NONE) && - c.derivation == DERIVATION_NONE) - { - my_coll_agg_error(av, count, func_name()); - return TRUE; - } - return FALSE; -} - - -bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, - Item **av, uint count, - uint flags) -{ - return (agg_arg_collations(c, av, count, flags | MY_COLL_DISALLOW_NONE)); -} - - /* return TRUE if item is a constant */ bool @@ -118,107 +51,6 @@ eval_const_cond(COND *cond) } - -/* - Collect arguments' character sets together. - We allow to apply automatic character set conversion in some cases. - The conditions when conversion is possible are: - - arguments A and B have different charsets - - A wins according to coercibility rules - (i.e. a column is stronger than a string constant, - an explicit COLLATE clause is stronger than a column) - - character set of A is either superset for character set of B, - or B is a string constant which can be converted into the - character set of A without data loss. - - If all of the above is true, then it's possible to convert - B into the character set of A, and then compare according - to the collation of A. - - For functions with more than two arguments: - - collect(A,B,C) ::= collect(collect(A,B),C) -*/ - -bool Item_func::agg_arg_charsets(DTCollation &coll, - Item **args, uint nargs, uint flags) -{ - Item **arg, **last, *safe_args[2]; - if (agg_arg_collations(coll, args, nargs, flags)) - return TRUE; - - /* - For better error reporting: save the first and the second argument. - We need this only if the the number of args is 3 or 2: - - for a longer argument list, "Illegal mix of collations" - doesn't display each argument's characteristics. - - if nargs is 1, then this error cannot happen. - */ - if (nargs >=2 && nargs <= 3) - { - safe_args[0]= args[0]; - safe_args[1]= args[1]; - } - - THD *thd= current_thd; - Query_arena *arena, backup; - bool res= FALSE; - /* - In case we're in statement prepare, create conversion item - in its memory: it will be reused on each execute. - */ - arena= thd->change_arena_if_needed(&backup); - - for (arg= args, last= args + nargs; arg < last; arg++) - { - Item* conv; - uint32 dummy_offset; - if (!String::needs_conversion(0, coll.collation, - (*arg)->collation.collation, - &dummy_offset)) - continue; - - if (!(conv= (*arg)->safe_charset_converter(coll.collation))) - { - if (nargs >=2 && nargs <= 3) - { - /* restore the original arguments for better error message */ - args[0]= safe_args[0]; - args[1]= safe_args[1]; - } - my_coll_agg_error(args, nargs, func_name()); - res= TRUE; - break; // we cannot return here, we need to restore "arena". - } - if ((*arg)->type() == FIELD_ITEM) - ((Item_field *)(*arg))->no_const_subst= 1; - /* - If in statement prepare, then we create a converter for two - constant items, do it once and then reuse it. - If we're in execution of a prepared statement, arena is NULL, - and the conv was created in runtime memory. This can be - the case only if the argument is a parameter marker ('?'), - because for all true constants the charset converter has already - been created in prepare. In this case register the change for - rollback. - */ - if (arena) - *arg= conv; - else - thd->change_item_tree(arg, conv); - /* - We do not check conv->fixed, because Item_func_conv_charset which can - be return by safe_charset_converter can't be fixed at creation - */ - conv->fix_fields(thd, arg); - } - if (arena) - thd->restore_backup_item_arena(arena, &backup); - return res; -} - - - void Item_func::set_arguments(List<Item> &list) { allowed_arg_cols= 1; @@ -4231,14 +4063,15 @@ Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg, bool Item_func_get_system_var::fix_fields(THD *thd, Item **ref) { - Item *item= var->item(thd, var_type, &component); + Item *item; DBUG_ENTER("Item_func_get_system_var::fix_fields"); + /* Evaluate the system variable and substitute the result (a basic constant) instead of this item. If the variable can not be evaluated, the error is reported in sys_var::item(). */ - if (item == 0) + if (!(item= var->item(thd, var_type, &component))) DBUG_RETURN(1); // Impossible item->set_name(name, 0, system_charset_info); // don't allocate a new name thd->change_item_tree(ref, item); diff --git a/sql/item_func.h b/sql/item_func.h index 43a85e6aa0b..e8db9d70ae7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -43,7 +43,7 @@ public: bool const_item_cache; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, GE_FUNC,GT_FUNC,FT_FUNC, - LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, + LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC, COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC, MULT_EQUAL_FUNC, INTERVAL_FUNC, ISNOTNULLTEST_FUNC, @@ -166,12 +166,22 @@ public: my_decimal *val_decimal(my_decimal *); bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, - uint flags= 0); + uint flags= 0) + { + return agg_item_collations(c, func_name(), items, nitems, flags); + } bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems, - uint flags= 0); + uint flags= 0) + { + return agg_item_collations_for_comparison(c, func_name(), + items, nitems, flags); + } bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, - uint flags= 0); + uint flags= 0) + { + return agg_item_charsets(c, func_name(), items, nitems, flags); + } bool walk(Item_processor processor, byte *arg); Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ec30dbf8aea..256090d3e61 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -335,19 +335,20 @@ null: void Item_func_concat::fix_length_and_dec() { - max_length=0; + ulonglong max_result_length= 0; if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV)) return; for (uint i=0 ; i < arg_count ; i++) - max_length+=args[i]->max_length; + max_result_length+= args[i]->max_length; - if (max_length > MAX_BLOB_WIDTH) + if (max_result_length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_result_length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) max_result_length; } /* @@ -378,9 +379,6 @@ String *Item_func_des_encrypt::val_str(String *str) if (arg_count == 1) { - /* Make sure LOCK_des_key_file was initialized. */ - init_des_key_file(); - /* Protect against someone doing FLUSH DES_KEY_FILE */ VOID(pthread_mutex_lock(&LOCK_des_key_file)); keyschedule= des_keyschedule[key_number=des_default_key]; @@ -391,10 +389,6 @@ String *Item_func_des_encrypt::val_str(String *str) key_number= (uint) args[1]->val_int(); if (key_number > 9) goto error; - - /* Make sure LOCK_des_key_file was initialized. */ - init_des_key_file(); - VOID(pthread_mutex_lock(&LOCK_des_key_file)); keyschedule= des_keyschedule[key_number]; VOID(pthread_mutex_unlock(&LOCK_des_key_file)); @@ -482,9 +476,6 @@ String *Item_func_des_decrypt::val_str(String *str) if (!(current_thd->master_access & SUPER_ACL) || key_number > 9) goto error; - /* Make sure LOCK_des_key_file was initialized. */ - init_des_key_file(); - VOID(pthread_mutex_lock(&LOCK_des_key_file)); keyschedule= des_keyschedule[key_number]; VOID(pthread_mutex_unlock(&LOCK_des_key_file)); @@ -658,7 +649,7 @@ null: void Item_func_concat_ws::fix_length_and_dec() { - max_length=0; + ulonglong max_result_length; if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV)) return; @@ -668,15 +659,16 @@ void Item_func_concat_ws::fix_length_and_dec() it is done on parser level in sql_yacc.yy so, (arg_count - 2) is safe here. */ - max_length= args[0]->max_length * (arg_count - 2); + max_result_length= (ulonglong) args[0]->max_length * (arg_count - 2); for (uint i=1 ; i < arg_count ; i++) - max_length+=args[i]->max_length; + max_result_length+=args[i]->max_length; - if (max_length > MAX_BLOB_WIDTH) + if (max_result_length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_result_length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) max_result_length; } @@ -855,18 +847,19 @@ null: void Item_func_replace::fix_length_and_dec() { - max_length=args[0]->max_length; + ulonglong max_result_length= args[0]->max_length; int diff=(int) (args[2]->max_length - args[1]->max_length); if (diff > 0 && args[1]->max_length) { // Calculate of maxreplaces - uint max_substrs= max_length/args[1]->max_length; - max_length+= max_substrs * (uint) diff; + ulonglong max_substrs= max_result_length/args[1]->max_length; + max_result_length+= max_substrs * (uint) diff; } - if (max_length > MAX_BLOB_WIDTH) + if (max_result_length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_result_length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) max_result_length; if (agg_arg_charsets(collation, args, 3, MY_COLL_CMP_CONV)) return; @@ -914,18 +907,22 @@ null: void Item_func_insert::fix_length_and_dec() { Item *cargs[2]; + ulonglong max_result_length; + cargs[0]= args[0]; cargs[1]= args[3]; if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV)) return; args[0]= cargs[0]; args[3]= cargs[1]; - max_length=args[0]->max_length+args[3]->max_length; - if (max_length > MAX_BLOB_WIDTH) + max_result_length= ((ulonglong) args[0]->max_length+ + (ulonglong) args[3]->max_length); + if (max_result_length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_result_length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) max_result_length; } @@ -2001,17 +1998,19 @@ void Item_func_repeat::fix_length_and_dec() collation.set(args[0]->collation); if (args[1]->const_item()) { - max_length=(long) (args[0]->max_length * args[1]->val_int()); - if (max_length >= MAX_BLOB_WIDTH) + ulonglong max_result_length= ((ulonglong) args[0]->max_length * + args[1]->val_int()); + if (max_result_length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_result_length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) max_result_length; } else { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_length= MAX_BLOB_WIDTH; + maybe_null= 1; } } @@ -2066,6 +2065,7 @@ err: void Item_func_rpad::fix_length_and_dec() { Item *cargs[2]; + cargs[0]= args[0]; cargs[1]= args[2]; if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV)) @@ -2074,18 +2074,19 @@ void Item_func_rpad::fix_length_and_dec() args[2]= cargs[1]; if (args[1]->const_item()) { - uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen; - max_length=max(args[0]->max_length,length); - if (max_length >= MAX_BLOB_WIDTH) + ulonglong length= ((ulonglong) args[1]->val_int() * + collation.collation->mbmaxlen); + if (length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) length; } else { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_length= MAX_BLOB_WIDTH; + maybe_null= 1; } } @@ -2118,7 +2119,7 @@ String *Item_func_rpad::val_str(String *str) func_name(), current_thd->variables.max_allowed_packet); goto err; } - if(args[2]->null_value || !pad_char_length) + if (args[2]->null_value || !pad_char_length) goto err; res_byte_length= res->length(); /* Must be done before alloc_buffer */ if (!(res= alloc_buffer(res,str,&tmp_value,byte_count))) @@ -2160,18 +2161,19 @@ void Item_func_lpad::fix_length_and_dec() if (args[1]->const_item()) { - uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen; - max_length=max(args[0]->max_length,length); - if (max_length >= MAX_BLOB_WIDTH) + ulonglong length= ((ulonglong) args[1]->val_int() * + collation.collation->mbmaxlen); + if (length >= MAX_BLOB_WIDTH) { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + length= MAX_BLOB_WIDTH; + maybe_null= 1; } + max_length= (ulong) length; } else { - max_length=MAX_BLOB_WIDTH; - maybe_null=1; + max_length= MAX_BLOB_WIDTH; + maybe_null= 1; } } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d2f1016891b..e26b6a75b7c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2976,6 +2976,10 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) maybe_null|= args[i]->maybe_null; } + if (agg_item_charsets(collation, func_name(), + args, arg_count, MY_COLL_ALLOW_CONV)) + return 1; + result_field= 0; null_value= 1; thd->allow_sum_func= 1; @@ -3033,6 +3037,7 @@ bool Item_func_group_concat::setup(THD *thd) DBUG_RETURN(TRUE); count_field_types(tmp_table_param,all_fields,0); + tmp_table_param->need_const= 1; DBUG_ASSERT(table == 0); /* We have to create a temporary table to get descriptions of fields diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index cac9613f1ad..aa377d0bdd8 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1555,7 +1555,7 @@ void Item_func_date_format::fix_length_and_dec() { fixed_length=0; /* The result is a binary string (no reason to use collation->mbmaxlen */ - max_length=args[1]->max_length*10; + max_length=min(args[1]->max_length,MAX_BLOB_WIDTH) * 10; set_if_smaller(max_length,MAX_BLOB_WIDTH); } maybe_null=1; // If wrong date @@ -2524,7 +2524,7 @@ void Item_func_add_time::print(String *str) } args[0]->print(str); str->append(','); - args[0]->print(str); + args[1]->print(str); str->append(')'); } diff --git a/sql/lex.h b/sql/lex.h index aa10328ced0..122e7040c80 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -497,6 +497,7 @@ static SYMBOL symbols[] = { { "TRAILING", SYM(TRAILING)}, { "TRANSACTION", SYM(TRANSACTION_SYM)}, { "TRIGGER", SYM(TRIGGER_SYM)}, + { "TRIGGERS", SYM(TRIGGERS_SYM)}, { "TRUE", SYM(TRUE_SYM)}, { "TRUNCATE", SYM(TRUNCATE_SYM)}, { "TYPE", SYM(TYPE_SYM)}, diff --git a/sql/lock.cc b/sql/lock.cc index 7f3fe5ac5da..d51d9083058 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -99,10 +99,15 @@ static void print_lock_error(int error, const char *); NULL on error. */ +static int thr_lock_errno_to_mysql[]= +{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; + MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; + int rc; + /* Map the return value of thr_lock to an error from errmsg.txt */ DBUG_ENTER("mysql_lock_tables"); for (;;) @@ -135,15 +140,24 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) { my_free((gptr) sql_lock,MYF(0)); sql_lock=0; - thd->proc_info=0; break; } thd->proc_info="Table lock"; thd->locked=1; - if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count)) + rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks, + sql_lock->lock_count, + thd->lock_id)]; + if (rc > 1) /* a timeout or a deadlock */ + { + my_error(rc, MYF(0)); + my_free((gptr) sql_lock,MYF(0)); + sql_lock= 0; + break; + } + else if (rc == 1) /* aborted */ { thd->some_tables_deleted=1; // Try again - sql_lock->lock_count=0; // Locks are alread freed + sql_lock->lock_count= 0; // Locks are already freed } else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH)) { @@ -335,22 +349,37 @@ void mysql_lock_abort(THD *thd, TABLE *table) } -/* Abort one thread / table combination */ +/* + Abort one thread / table combination + + SYNOPSIS + mysql_lock_abort_for_thread() + thd Thread handler + table Table that should be removed from lock queue + + RETURN + 0 Table was not locked by another thread + 1 Table was locked by at least one other thread +*/ -void mysql_lock_abort_for_thread(THD *thd, TABLE *table) +bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) { MYSQL_LOCK *locked; TABLE *write_lock_used; + bool result= FALSE; DBUG_ENTER("mysql_lock_abort_for_thread"); if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used))) { for (uint i=0; i < locked->lock_count; i++) - thr_abort_locks_for_thread(locked->locks[i]->lock, - table->in_use->real_id); + { + if (thr_abort_locks_for_thread(locked->locks[i]->lock, + table->in_use->real_id)) + result= TRUE; + } my_free((gptr) locked,MYF(0)); } - DBUG_VOID_RETURN; + DBUG_RETURN(result); } @@ -583,6 +612,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(-1); table->s= &table->share_not_to_be_used; memcpy((table->s->table_cache_key= (char*) (table+1)), key, key_length); + table->s->db= table->s->table_cache_key; table->s->key_length=key_length; table->in_use=thd; table->locked_by_name=1; @@ -593,9 +623,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) my_free((gptr) table,MYF(0)); DBUG_RETURN(-1); } - if (remove_table_from_cache(thd, db, table_list->table_name, 0)) - DBUG_RETURN(1); // Table is in use - DBUG_RETURN(0); + + /* Return 1 if table is in use */ + DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name, + RTFC_NO_FLAG))); } diff --git a/sql/log.cc b/sql/log.cc index 44fff28b612..540e482f578 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2209,7 +2209,7 @@ bool flush_error_log() On Windows is necessary a temporary file for to rename the current error file. */ - strmov(strmov(err_temp, err_renamed),"-tmp"); + strxmov(err_temp, err_renamed,"-tmp",NullS); (void) my_delete(err_temp, MYF(0)); if (freopen(err_temp,"a+",stdout)) { @@ -2650,7 +2650,7 @@ int TC_LOG_MMAP::log(THD *thd, my_xid xid) { // somebody's syncing. let's wait p->waiters++; /* - note - it must be while(), not do ... while() here + note - it must be while (), not do ... while () here as p->state may be not DIRTY when we come here */ while (p->state == DIRTY && syncing) diff --git a/sql/log_event.cc b/sql/log_event.cc index 0873ee50743..bdf17ba20e3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,15 +1,15 @@ /* Copyright (C) 2000-2004 MySQL AB - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -242,7 +242,7 @@ static void print_set_option(FILE* file, uint32 bits_changed, uint32 option, { if (*need_comma) fprintf(file,", "); - fprintf(file,"%s=%d", name, (bool)(flags & option)); + fprintf(file,"%s=%d", name, test(flags & option)); *need_comma= 1; } } @@ -2774,6 +2774,16 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, */ handle_dup= DUP_ERROR; } + /* + We need to set thd->lex->sql_command and thd->lex->duplicates + since InnoDB tests these variables to decide if this is a LOAD + DATA ... REPLACE INTO ... statement even though mysql_parse() + is not called. This is not needed in 5.0 since there the LOAD + DATA ... statement is replicated using mysql_parse(), which + sets the thd->lex fields correctly. + */ + thd->lex->sql_command= SQLCOM_LOAD; + thd->lex->duplicates= handle_dup; sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG); String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 49eb50be580..cafb15971b5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -526,6 +526,7 @@ struct Query_cache_query_flags { unsigned int client_long_flag:1; unsigned int client_protocol_41:1; + unsigned int more_results_exists:1; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; @@ -791,9 +792,7 @@ extern char *des_key_file; extern struct st_des_keyschedule des_keyschedule[10]; extern uint des_default_key; extern pthread_mutex_t LOCK_des_key_file; -void init_des_key_file(); bool load_des_key_file(const char *file_name); -void free_des_key_file(); #endif /* HAVE_OPENSSL */ /* sql_do.cc */ @@ -953,8 +952,15 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db, const char *table_name); void remove_db_from_cache(const char *db); void flush_tables(); + +/* bits for last argument to remove_table_from_cache() */ +#define RTFC_NO_FLAG 0x0000 +#define RTFC_OWNED_BY_THD_FLAG 0x0001 +#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002 +#define RTFC_CHECK_KILLED_FLAG 0x0004 bool remove_table_from_cache(THD *thd, const char *db, const char *table, - bool return_if_owned_by_thd); + uint flags); + bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables); void copy_field_from_tmp_record(Field *field,int offset); bool fill_record(THD *thd, Field **field, List<Item> &values, @@ -1082,6 +1088,7 @@ extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern const char *in_left_expr_name, *in_additional_cond; extern const char * const triggers_file_ext; +extern const char * const trigname_file_ext; extern Eq_creator eq_creator; extern Ne_creator ne_creator; extern Gt_creator gt_creator; @@ -1156,8 +1163,11 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, - LOCK_global_system_variables, LOCK_user_conn, + LOCK_global_system_variables, LOCK_user_conn, LOCK_bytes_sent, LOCK_bytes_received; +#ifdef HAVE_OPENSSL +extern pthread_mutex_t LOCK_des_key_file; +#endif extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; @@ -1213,7 +1223,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table); -void mysql_lock_abort_for_thread(THD *thd, TABLE *table); +bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); bool lock_global_read_lock(THD *thd); void unlock_global_read_lock(THD *thd); @@ -1239,10 +1249,13 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list, void unireg_init(ulong options); void unireg_end(void); bool mysql_create_frm(THD *thd, my_string file_name, + const char *db, const char *table, HA_CREATE_INFO *create_info, List<create_field> &create_field, uint key_count,KEY *key_info,handler *db_type); -int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info, +int rea_create_table(THD *thd, my_string file_name, + const char *db, const char *table, + HA_CREATE_INFO *create_info, List<create_field> &create_field, uint key_count,KEY *key_info); int format_number(uint inputflag,uint max_length,my_string pos,uint length, @@ -1309,7 +1322,8 @@ ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames, const char *newname); ulong next_io_size(ulong pos); void append_unescaped(String *res, const char *pos, uint length); -int create_frm(THD *thd, char *name,uint reclength,uchar *fileinfo, +int create_frm(THD *thd, char *name, const char *db, const char *table, + uint reclength,uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys); void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form); int rename_file_ext(const char * from,const char * to,const char * ext); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 78d9af387da..93688689cd7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -220,21 +220,58 @@ extern "C" int gethostname(char *name, int namelen); /* Constants */ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; -static const char *sql_mode_names[] = +static const char *sql_mode_names[]= { "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", "NO_DIR_IN_CREATE", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI", - "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", "STRICT_ALL_TABLES", - "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO", + "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", + "STRICT_ALL_TABLES", + "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", + "ERROR_FOR_DIVISION_BY_ZERO", "TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE", "NO_ENGINE_SUBSTITUTION", NullS }; +static const unsigned int sql_mode_names_len[]= +{ + /*REAL_AS_FLOAT*/ 13, + /*PIPES_AS_CONCAT*/ 15, + /*ANSI_QUOTES*/ 11, + /*IGNORE_SPACE*/ 12, + /*?*/ 1, + /*ONLY_FULL_GROUP_BY*/ 18, + /*NO_UNSIGNED_SUBTRACTION*/ 23, + /*NO_DIR_IN_CREATE*/ 16, + /*POSTGRESQL*/ 10, + /*ORACLE*/ 6, + /*MSSQL*/ 5, + /*DB2*/ 3, + /*MAXDB*/ 5, + /*NO_KEY_OPTIONS*/ 14, + /*NO_TABLE_OPTIONS*/ 16, + /*NO_FIELD_OPTIONS*/ 16, + /*MYSQL323*/ 8, + /*MYSQL40*/ 7, + /*ANSI*/ 4, + /*NO_AUTO_VALUE_ON_ZERO*/ 21, + /*NO_BACKSLASH_ESCAPES*/ 20, + /*STRICT_TRANS_TABLES*/ 19, + /*STRICT_ALL_TABLES*/ 17, + /*NO_ZERO_IN_DATE*/ 15, + /*NO_ZERO_DATE*/ 12, + /*ALLOW_INVALID_DATES*/ 19, + /*ERROR_FOR_DIVISION_BY_ZERO*/ 26, + /*TRADITIONAL*/ 11, + /*NO_AUTO_CREATE_USER*/ 19, + /*HIGH_NOT_PRECEDENCE*/ 19, + /*NO_ENGINE_SUBSTITUTION*/ 22 +}; TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"", - sql_mode_names, NULL }; + sql_mode_names, + (unsigned int *)sql_mode_names_len }; static const char *tc_heuristic_recover_names[]= { "COMMIT", "ROLLBACK", NullS @@ -447,6 +484,9 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; +#ifdef HAVE_OPENSSL +pthread_mutex_t LOCK_des_key_file; +#endif rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; pthread_cond_t COND_refresh,COND_thread_count; pthread_t signal_thread; @@ -675,7 +715,11 @@ static void close_connections(void) end_thr_alarm(0); // Abort old alarms. end_slave(); - /* First signal all threads that it's time to die */ + /* + First signal all threads that it's time to die + This will give the threads some time to gracefully abort their + statements and inform their clients that the server is about to die. + */ THD *tmp; (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list @@ -702,9 +746,13 @@ static void close_connections(void) (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list if (thread_count) - sleep(1); // Give threads time to die + sleep(2); // Give threads time to die - /* Force remaining threads to die by closing the connection to the client */ + /* + Force remaining threads to die by closing the connection to the client + This will ensure that threads that are waiting for a command from the + client on a blocking read call are aborted. + */ for (;;) { @@ -719,8 +767,9 @@ static void close_connections(void) #ifndef __bsdi__ // Bug in BSDI kernel if (tmp->vio_ok()) { - sql_print_error(ER(ER_FORCING_CLOSE),my_progname, - tmp->thread_id,tmp->user ? tmp->user : ""); + if (global_system_variables.log_warnings) + sql_print_warning(ER(ER_FORCING_CLOSE),my_progname, + tmp->thread_id,tmp->user ? tmp->user : ""); close_connection(tmp,0,0); } #endif @@ -882,7 +931,7 @@ static void __cdecl kill_server(int sig_ptr) unireg_end(); #ifdef __NETWARE__ - if(!event_flag) + if (!event_flag) pthread_join(select_thread, NULL); // wait for main thread #endif /* __NETWARE__ */ @@ -1036,7 +1085,6 @@ void clean_up(bool print_message) #ifdef HAVE_OPENSSL if (ssl_acceptor_fd) my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR)); - free_des_key_file(); #endif /* HAVE_OPENSSL */ #ifdef USE_REGEX regex_end(); @@ -1108,6 +1156,9 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); (void) pthread_mutex_destroy(&LOCK_user_conn); +#ifdef HAVE_OPENSSL + (void) pthread_mutex_destroy(&LOCK_des_key_file); +#endif #ifdef HAVE_REPLICATION (void) pthread_mutex_destroy(&LOCK_rpl_status); (void) pthread_cond_destroy(&COND_rpl_status); @@ -2586,6 +2637,50 @@ static int init_common_variables(const char *conf_file_name, int argc, if (my_dbopt_init()) return 1; + /* + Ensure that lower_case_table_names is set on system where we have case + insensitive names. If this is not done the users MyISAM tables will + get corrupted if accesses with names of different case. + */ + DBUG_PRINT("info", ("lower_case_table_names: %d", lower_case_table_names)); + if (!lower_case_table_names && + (lower_case_file_system= + (test_if_case_insensitive(mysql_real_data_home) == 1))) + { + if (lower_case_table_names_used) + { + if (global_system_variables.log_warnings) + sql_print_warning("\ +You have forced lower_case_table_names to 0 through a command-line \ +option, even though your file system '%s' is case insensitive. This means \ +that you can corrupt a MyISAM table by accessing it with different cases. \ +You should consider changing lower_case_table_names to 1 or 2", + mysql_real_data_home); + } + else + { + if (global_system_variables.log_warnings) + sql_print_warning("Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home); + lower_case_table_names= 2; + } + } + else if (lower_case_table_names == 2 && + !(lower_case_file_system= + (test_if_case_insensitive(mysql_real_data_home) == 1))) + { + if (global_system_variables.log_warnings) + sql_print_warning("lower_case_table_names was set to 2, even though your " + "the file system '%s' is case sensitive. Now setting " + "lower_case_table_names to 0 to avoid future problems.", + mysql_real_data_home); + lower_case_table_names= 0; + } + + /* Reset table_alias_charset, now that lower_case_table_names is set. */ + table_alias_charset= (lower_case_table_names ? + files_charset_info : + &my_charset_bin); + return 0; } @@ -2611,6 +2706,9 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); +#ifdef HAVE_OPENSSL + (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST); +#endif (void) my_rwlock_init(&LOCK_sys_init_connect, NULL); (void) my_rwlock_init(&LOCK_sys_init_slave, NULL); (void) my_rwlock_init(&LOCK_grant, NULL); @@ -3060,50 +3158,6 @@ int main(int argc, char **argv) (void) thr_setconcurrency(concurrency); // 10 by default - /* - Ensure that lower_case_table_names is set on system where we have case - insensitive names. If this is not done the users MyISAM tables will - get corrupted if accesses with names of different case. - */ - DBUG_PRINT("info", ("lower_case_table_names: %d", lower_case_table_names)); - if (!lower_case_table_names && - (lower_case_file_system= - (test_if_case_insensitive(mysql_real_data_home) == 1))) - { - if (lower_case_table_names_used) - { - if (global_system_variables.log_warnings) - sql_print_warning("\ -You have forced lower_case_table_names to 0 through a command-line \ -option, even though your file system '%s' is case insensitive. This means \ -that you can corrupt a MyISAM table by accessing it with different cases. \ -You should consider changing lower_case_table_names to 1 or 2", - mysql_real_data_home); - } - else - { - if (global_system_variables.log_warnings) - sql_print_warning("Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home); - lower_case_table_names= 2; - } - } - else if (lower_case_table_names == 2 && - !(lower_case_file_system= - (test_if_case_insensitive(mysql_real_data_home) == 1))) - { - if (global_system_variables.log_warnings) - sql_print_warning("lower_case_table_names was set to 2, even though your " - "the file system '%s' is case sensitive. Now setting " - "lower_case_table_names to 0 to avoid future problems.", - mysql_real_data_home); - lower_case_table_names= 0; - } - - /* Reset table_alias_charset, now that lower_case_table_names is set. */ - table_alias_charset= (lower_case_table_names ? - files_charset_info : - &my_charset_bin); - select_thread=pthread_self(); select_thread_in_use=1; init_ssl(); @@ -4336,7 +4390,8 @@ enum options_mysqld OPT_ENABLE_LARGE_PAGES, OPT_TIMED_MUTEXES, OPT_OLD_STYLE_USER_LIMITS, - OPT_LOG_SLOW_ADMIN_STATEMENTS + OPT_LOG_SLOW_ADMIN_STATEMENTS, + OPT_TABLE_LOCK_WAIT_TIMEOUT }; @@ -5589,6 +5644,11 @@ The minimum value for this variable is 4096.", "The number of open tables for all threads.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, 0, 1, 0}, + {"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT, "Timeout in " + "seconds to wait for a table level lock before returning an error. Used" + " only if the connection has active cursors.", + (gptr*) &table_lock_wait_timeout, (gptr*) &table_lock_wait_timeout, + 0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0}, {"thread_cache_size", OPT_THREAD_CACHE_SIZE, "How many threads we should keep in a cache for reuse.", (gptr*) &thread_cache_size, (gptr*) &thread_cache_size, 0, GET_ULONG, @@ -5722,6 +5782,7 @@ struct show_var_st status_vars[]= { {"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS}, {"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS}, {"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS}, + {"Com_show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS}, {"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS}, {"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS}, {"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, @@ -7077,4 +7138,6 @@ template class I_List_iterator<THD>; template class I_List<i_string>; template class I_List<i_string_pair>; template class I_List<NAMED_LIST>; +template class I_List<Statement>; +template class I_List_iterator<Statement>; #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 676f8d8a33d..c1ebfe105b6 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -630,7 +630,7 @@ int imerge_list_or_tree(PARAM *param, { SEL_IMERGE *imerge; List_iterator<SEL_IMERGE> it(*im1); - while((imerge= it++)) + while ((imerge= it++)) { if (imerge->or_sel_tree_with_checks(param, tree)) it.remove(); @@ -990,7 +990,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler) DBUG_RETURN(1); quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS); } - while((quick= quick_it++)) + while ((quick= quick_it++)) { if (quick->init_ror_merged_scan(FALSE)) DBUG_RETURN(1); @@ -6943,7 +6943,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) List_iterator<Item> select_items_it(join->fields_list); /* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/ - if(join->make_sum_func_list(join->all_fields, join->fields_list, 1)) + if (join->make_sum_func_list(join->all_fields, join->fields_list, 1)) DBUG_RETURN(NULL); if (join->sum_funcs[0]) { @@ -7269,7 +7269,7 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, Item *and_or_arg; while ((and_or_arg= li++)) { - if(!check_group_min_max_predicates(and_or_arg, min_max_arg_item, + if (!check_group_min_max_predicates(and_or_arg, min_max_arg_item, image_type)) DBUG_RETURN(FALSE); } @@ -7351,7 +7351,7 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, } else if (cur_arg->type() == Item::FUNC_ITEM) { - if(!check_group_min_max_predicates(cur_arg, min_max_arg_item, + if (!check_group_min_max_predicates(cur_arg, min_max_arg_item, image_type)) DBUG_RETURN(FALSE); } @@ -7882,19 +7882,19 @@ int QUICK_GROUP_MIN_MAX_SELECT::init() if (min_max_arg_part) { - if(my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) + if (my_init_dynamic_array(&min_max_ranges, sizeof(QUICK_RANGE*), 16, 16)) return 1; if (have_min) { - if(!(min_functions= new List<Item_sum>)) + if (!(min_functions= new List<Item_sum>)) return 1; } else min_functions= NULL; if (have_max) { - if(!(max_functions= new List<Item_sum>)) + if (!(max_functions= new List<Item_sum>)) return 1; } else @@ -7968,7 +7968,7 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range) uint range_flag= sel_range->min_flag | sel_range->max_flag; /* Skip (-inf,+inf) ranges, e.g. (x < 5 or x > 4). */ - if((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) + if ((range_flag & NO_MIN_RANGE) && (range_flag & NO_MAX_RANGE)) return FALSE; if (!(sel_range->min_flag & NO_MIN_RANGE) && diff --git a/sql/parse_file.cc b/sql/parse_file.cc index 7cc563901d2..82ce2f2d7b5 100644 --- a/sql/parse_file.cc +++ b/sql/parse_file.cc @@ -166,6 +166,25 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter, } break; } + case FILE_OPTIONS_ULLLIST: + { + List_iterator_fast<ulonglong> it(*((List<ulonglong>*) + (base + parameter->offset))); + bool first= 1; + ulonglong *val; + while ((val= it++)) + { + num.set(*val, &my_charset_bin); + // We need ' ' after string to detect list continuation + if ((!first && my_b_append(file, (const byte *)" ", 1)) || + my_b_append(file, (const byte *)num.ptr(), num.length())) + { + DBUG_RETURN(TRUE); + } + first= 0; + } + break; + } default: DBUG_ASSERT(0); // never should happened } @@ -615,6 +634,8 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root, char *eol; LEX_STRING *str; List<LEX_STRING> *list; + ulonglong *num; + List<ulonglong> *nlist; DBUG_ENTER("File_parser::parse"); while (ptr < end && found < required) @@ -719,7 +740,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root, case FILE_OPTIONS_STRLIST: { list= (List<LEX_STRING>*)(base + parameter->offset); - + list->empty(); // list parsing while (ptr < end) @@ -728,7 +749,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root, sizeof(LEX_STRING))) || list->push_back(str, mem_root)) goto list_err; - if(!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str))) + if (!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str))) goto list_err_w_message; switch (*ptr) { case '\n': @@ -741,17 +762,56 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root, goto list_err_w_message; } } - end_of_list: + +end_of_list: if (*(ptr++) != '\n') goto list_err; break; - list_err_w_message: +list_err_w_message: my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), parameter->name.str, line); - list_err: +list_err: DBUG_RETURN(TRUE); } + case FILE_OPTIONS_ULLLIST: + { + nlist= (List<ulonglong>*)(base + parameter->offset); + nlist->empty(); + // list parsing + while (ptr < end) + { + int not_used; + char *num_end= end; + if (!(num= (ulonglong*)alloc_root(mem_root, sizeof(ulonglong))) || + nlist->push_back(num, mem_root)) + goto nlist_err; + *num= my_strtoll10(ptr, &num_end, ¬_used); + ptr= num_end; + switch (*ptr) { + case '\n': + goto end_of_nlist; + case ' ': + // we cant go over buffer bounds, because we have \0 at the end + ptr++; + break; + default: + goto nlist_err_w_message; + } + } + +end_of_nlist: + if (*(ptr++) != '\n') + goto nlist_err; + break; + +nlist_err_w_message: + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); +nlist_err: + DBUG_RETURN(TRUE); + + } default: DBUG_ASSERT(0); // never should happened } diff --git a/sql/parse_file.h b/sql/parse_file.h index 82a89dffd18..cc0aa6556f6 100644 --- a/sql/parse_file.h +++ b/sql/parse_file.h @@ -27,8 +27,10 @@ enum file_opt_type { FILE_OPTIONS_REV, /* Revision version number (ulonglong) */ FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be allocated with length 20 (19+1) */ - FILE_OPTIONS_STRLIST /* list of escaped strings + FILE_OPTIONS_STRLIST, /* list of escaped strings (List<LEX_STRING>) */ + FILE_OPTIONS_ULLLIST /* list of ulonglong values + (List<ulonglong>) */ }; struct File_option diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc index ed2d0b583d0..093a2bf2b90 100644 --- a/sql/protocol_cursor.cc +++ b/sql/protocol_cursor.cc @@ -114,8 +114,7 @@ bool Protocol_cursor::write() for (; cur_field < fields_end; cur_field++, data_tmp++) { - if ((len= net_field_length((uchar **)&cp)) == 0 || - len == NULL_LENGTH) + if ((len= net_field_length((uchar **)&cp)) == NULL_LENGTH) { *data_tmp= 0; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 2d7c3364e41..35f1070c4eb 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -375,6 +375,8 @@ sys_var_thd_ulong sys_sync_replication_timeout( sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_cache_size("table_cache", &table_cache_size); +sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout", + &table_lock_wait_timeout); sys_var_long_ptr sys_thread_cache_size("thread_cache_size", &thread_cache_size); sys_var_thd_enum sys_tx_isolation("tx_isolation", @@ -682,6 +684,7 @@ sys_var *sys_variables[]= #endif &sys_sync_frm, &sys_table_cache_size, + &sys_table_lock_wait_timeout, &sys_table_type, &sys_thread_cache_size, &sys_time_format, @@ -972,6 +975,7 @@ struct show_var_st init_vars[]= { {"system_time_zone", system_time_zone, SHOW_CHAR}, #endif {"table_cache", (char*) &table_cache_size, SHOW_LONG}, + {"table_lock_wait_timeout", (char*) &table_lock_wait_timeout, SHOW_LONG }, {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS}, {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS}, #ifdef HAVE_THR_SETCONCURRENCY @@ -1418,6 +1422,12 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; +#if SIZEOF_LONG != SIZEOF_LONGLONG + /* Avoid overflow on 32-bit platforms. */ + if (tmp > ULONG_MAX) + tmp= ULONG_MAX; +#endif + /* Don't use bigger value than given with --maximum-variable-name=.. */ if ((ulong) tmp > max_system_variables.*offset) tmp= max_system_variables.*offset; @@ -1675,7 +1685,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) pthread_mutex_lock(&LOCK_global_system_variables); value= *(uint*) value_ptr(thd, var_type, base); pthread_mutex_unlock(&LOCK_global_system_variables); - return new Item_uint((int32) value); + return new Item_uint((uint32) value); } case SHOW_LONG: { @@ -1683,7 +1693,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) pthread_mutex_lock(&LOCK_global_system_variables); value= *(ulong*) value_ptr(thd, var_type, base); pthread_mutex_unlock(&LOCK_global_system_variables); - return new Item_uint((int32) value); + return new Item_uint(value); } case SHOW_LONGLONG: { @@ -3192,29 +3202,49 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var) Functions to handle sql_mode ****************************************************************************/ -byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) +/* + Make string representation of mode + + SYNOPSIS + thd in thread handler + val in sql_mode value + len out pointer on length of string + + RETURN + pointer to string with sql_mode representation +*/ + +byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd, ulong val, + ulong *len) { - ulong val; char buff[256]; String tmp(buff, sizeof(buff), &my_charset_latin1); tmp.length(0); - val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : - thd->variables.*offset); for (uint i= 0; val; val>>= 1, i++) { if (val & 1) { - tmp.append(enum_names->type_names[i]); + tmp.append(sql_mode_typelib.type_names[i], + sql_mode_typelib.type_lengths[i]); tmp.append(','); } } if (tmp.length()) tmp.length(tmp.length() - 1); + *len= tmp.length(); return (byte*) thd->strmake(tmp.ptr(), tmp.length()); } +byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + ulong val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : + thd->variables.*offset); + ulong length_unused; + return symbolic_mode_representation(thd, val, &length_unused); +} + void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type) { diff --git a/sql/set_var.h b/sql/set_var.h index a7e680cc7fa..c8b075ddd35 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -361,6 +361,8 @@ public: } void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + static byte *symbolic_mode_representation(THD *thd, ulong sql_mode, + ulong *length); }; diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml index a6bb4bad99b..32fd1618a8b 100644 --- a/sql/share/charsets/Index.xml +++ b/sql/share/charsets/Index.xml @@ -106,7 +106,7 @@ To make maintaining easier please: <charset name="latin1"> <family>Western</family> - <description>ISO 8859-1 West European</description> + <description>cp1252 West European</description> <alias>csisolatin1</alias> <alias>iso-8859-1</alias> <alias>iso-ir-100</alias> diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index f999f17aedf..459560ccac8 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4094,20 +4094,20 @@ ER_ERROR_DURING_CHECKPOINT swe "Fick fel %d vid CHECKPOINT" ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ CHECKPOINT" ER_NEW_ABORTING_CONNECTION 08S01 - cze "Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: `%-.64s' (%-.64s) bylo pøeru¹eno" - dan "Afbrød forbindelsen %ld til databasen '%-.64s' bruger: '%-.32s' vært: `%-.64s' (%-.64s)" - nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.32s' host: `%-.64s' (%-.64s)" - eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)" - est "Ühendus katkestatud %ld andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)" - fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.32s' hôte: `%-.64s' (%-.64s)" - ger "Verbindungsabbruch %ld zur Datenbank '%-.64s'. Benutzer: '%-.32s', Host: `%-.64s' (%-.64s)" + cze "Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: '%-.64s' (%-.64s) bylo pøeru¹eno" + dan "Afbrød forbindelsen %ld til databasen '%-.64s' bruger: '%-.32s' vært: '%-.64s' (%-.64s)" + nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.32s' host: '%-.64s' (%-.64s)" + eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: '%-.64s' (%-.64s)" + est "Ühendus katkestatud %ld andmebaas: '%-.64s' kasutaja: '%-.32s' masin: '%-.64s' (%-.64s)" + fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.32s' hôte: '%-.64s' (%-.64s)" + ger "Verbindungsabbruch %ld zur Datenbank '%-.64s'. Benutzer: '%-.32s', Host: '%-.64s' (%-.64s)" ita "Interrotta la connessione %ld al db: ''%-.64s' utente: '%-.32s' host: '%-.64s' (%-.64s)" - por "Conexão %ld abortada para banco de dados '%-.64s' - usuário '%-.32s' - 'host' `%-.64s' ('%-.64s')" - rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ `%-.64s' (%-.64s)" - serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: `%-.64s' (%-.64s)" - spa "Abortada conexión %ld para db: '%-.64s' usuario: '%-.32s' servidor: `%-.64s' (%-.64s)" + por "Conexão %ld abortada para banco de dados '%-.64s' - usuário '%-.32s' - 'host' '%-.64s' ('%-.64s')" + rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ '%-.64s' (%-.64s)" + serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: '%-.64s' (%-.64s)" + spa "Abortada conexión %ld para db: '%-.64s' usuario: '%-.32s' servidor: '%-.64s' (%-.64s)" swe "Avbröt länken för tråd %ld till db '%-.64s', användare '%-.32s', host '%-.64s' (%-.64s)" - ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞ: '%-.32s' ÈÏÓÔ: `%-.64s' (%-.64s)" + ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞ: '%-.32s' ÈÏÓÔ: '%-.64s' (%-.64s)" ER_DUMP_NOT_IMPLEMENTED cze "Handler tabulky nepodporuje bin-Bární dump" dan "Denne tabeltype unserstøtter ikke binært tabeldump" @@ -5370,3 +5370,19 @@ ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009 eng "Scale may not be larger than the precision (column '%-.64s')." ER_WRONG_LOCK_OF_SYSTEM_TABLE eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables" +ER_CONNECT_TO_FOREIGN_DATA_SOURCE + eng "Unable to connect to foreign data source - database '%s'!" +ER_QUERY_ON_FOREIGN_DATA_SOURCE + eng "There was a problem processing the query on the foreign data source. Data source error: '%-.64s'" +ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST + eng "The foreign data source you are trying to reference does not exist. Data source error : '%-.64s'" +ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE + eng "Can't create federated table. The data source connection string '%-.64s' is not in the correct format" +ER_FOREIGN_DATA_STRING_INVALID + eng "The data source connection string '%-.64s' is not in the correct format" +ER_CANT_CREATE_FEDERATED_TABLE + eng "Can't create federated table. Foreign data src error : '%-.64s'" +ER_TRG_IN_WRONG_SCHEMA + eng "Trigger in wrong schema" +ER_STACK_OVERRUN_NEED_MORE + eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." diff --git a/sql/slave.cc b/sql/slave.cc index a587ac5a118..eed70b01cd2 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3637,6 +3637,7 @@ err: mi->abort_slave = 0; // TODO: check if this is needed DBUG_ASSERT(thd->net.buff != 0); net_end(&thd->net); // destructor will not free it, because net.vio is 0 + close_thread_tables(thd, 0); pthread_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); delete thd; diff --git a/sql/sp.cc b/sql/sp.cc index 55087f47f5e..dec0eee0095 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1442,8 +1442,10 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, { Sroutine_hash_entry **last_cached_routine_ptr= (Sroutine_hash_entry **)lex->sroutines_list.next; - for (int i= 0; i < 3; i++) - for (int j= 0; j < 2; j++) + for (int i= 0; i < (int)TRG_EVENT_MAX; i++) + { + for (int j= 0; j < (int)TRG_ACTION_MAX; j++) + { if (triggers->bodies[i][j]) { (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd, @@ -1451,7 +1453,8 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, sp_update_stmt_used_routines(thd, lex, &triggers->bodies[i][j]->m_sroutines); } - + } + } (void)sp_cache_routines_and_add_tables_aux(thd, lex, *last_cached_routine_ptr); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 02c006d01ee..0c3a6d04598 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -574,6 +574,7 @@ sp_head::execute(THD *thd) sp_rcontext *ctx; int ret= 0; uint ip= 0; + ulong save_sql_mode; Query_arena *old_arena; query_id_t old_query_id; TABLE *old_derived_tables; @@ -626,6 +627,8 @@ sp_head::execute(THD *thd) old_query_id= thd->query_id; old_derived_tables= thd->derived_tables; thd->derived_tables= 0; + save_sql_mode= thd->variables.sql_mode; + thd->variables.sql_mode= m_sql_mode; /* It is also more efficient to save/restore current thd->lex once when do it in each instruction @@ -715,6 +718,7 @@ sp_head::execute(THD *thd) thd->query_id= old_query_id; DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; + thd->variables.sql_mode= save_sql_mode; thd->current_arena= old_arena; state= EXECUTED; @@ -1245,8 +1249,6 @@ sp_head::show_create_procedure(THD *thd) String buffer(buff, sizeof(buff), system_charset_info); int res; List<Item> field_list; - ulong old_sql_mode; - sys_var *sql_mode_var; byte *sql_mode_str; ulong sql_mode_len; bool full_access; @@ -1258,19 +1260,13 @@ sp_head::show_create_procedure(THD *thd) if (check_show_routine_access(thd, this, &full_access)) return 1; - - old_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= m_sql_mode; - sql_mode_var= find_sys_var("SQL_MODE", 8); - if (sql_mode_var) - { - sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0); - sql_mode_len= strlen((char*) sql_mode_str); - } + sql_mode_str= + sys_var_thd_sql_mode::symbolic_mode_representation(thd, + m_sql_mode, + &sql_mode_len); field_list.push_back(new Item_empty_string("Procedure", NAME_LEN)); - if (sql_mode_var) - field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); + field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); // 1024 is for not to confuse old clients field_list.push_back(new Item_empty_string("Create Procedure", max(buffer.length(), 1024))); @@ -1282,15 +1278,13 @@ sp_head::show_create_procedure(THD *thd) } protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); - if (sql_mode_var) - protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); + protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); if (full_access) protocol->store(m_defstr.str, m_defstr.length, system_charset_info); res= protocol->write(); send_eof(thd); done: - thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(res); } @@ -1326,7 +1320,6 @@ sp_head::show_create_function(THD *thd) String buffer(buff, sizeof(buff), system_charset_info); int res; List<Item> field_list; - ulong old_sql_mode; sys_var *sql_mode_var; byte *sql_mode_str; ulong sql_mode_len; @@ -1339,15 +1332,10 @@ sp_head::show_create_function(THD *thd) if (check_show_routine_access(thd, this, &full_access)) return 1; - old_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= m_sql_mode; - sql_mode_var= find_sys_var("SQL_MODE", 8); - if (sql_mode_var) - { - sql_mode_str= sql_mode_var->value_ptr(thd, OPT_SESSION, 0); - sql_mode_len= strlen((char*) sql_mode_str); - } - + sql_mode_str= + sys_var_thd_sql_mode::symbolic_mode_representation(thd, + m_sql_mode, + &sql_mode_len); field_list.push_back(new Item_empty_string("Function",NAME_LEN)); if (sql_mode_var) field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); @@ -1361,15 +1349,13 @@ sp_head::show_create_function(THD *thd) } protocol->prepare_for_resend(); protocol->store(m_name.str, m_name.length, system_charset_info); - if (sql_mode_var) - protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); + protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); if (full_access) protocol->store(m_defstr.str, m_defstr.length, system_charset_info); res= protocol->write(); send_eof(thd); done: - thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(res); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 32dc4449174..09b9c8f47a1 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -121,7 +121,7 @@ public: uchar *m_tmp_query; // Temporary pointer to sub query string uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value st_sp_chistics *m_chistics; - ulong m_sql_mode; // For SHOW CREATE + ulong m_sql_mode; // For SHOW CREATE and execution LEX_STRING m_qname; // db.name LEX_STRING m_db; LEX_STRING m_name; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 04666469e9c..1b3d8cc914a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3547,9 +3547,9 @@ bool check_grant_db(THD *thd,const char *db) { char helping [NAME_LEN+USERNAME_LENGTH+2]; uint len; - bool error=1; + bool error= 1; - len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; + len= (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; rw_rdlock(&LOCK_grant); for (uint idx=0 ; idx < column_priv_hash.records ; idx++) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7021f61a052..45b99bfee1b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -292,7 +292,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, bool found=0; for (TABLE_LIST *table= tables; table; table= table->next_local) { - if (remove_table_from_cache(thd, table->db, table->table_name, 1)) + if (remove_table_from_cache(thd, table->db, table->table_name, + RTFC_OWNED_BY_THD_FLAG)) found=1; } if (!found) @@ -1042,26 +1043,26 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (thd->locked_tables || thd->prelocked_mode) { // Using table locks TABLE *best_table= 0; - int best_distance= INT_MIN, distance; + int best_distance= INT_MIN; for (table=thd->open_tables; table ; table=table->next) { if (table->s->key_length == key_length && !memcmp(table->s->table_cache_key, key, key_length) && !my_strcasecmp(system_charset_info, table->alias, alias) && - table->query_id != thd->query_id && /* skip tables already used by this query */ + table->query_id != thd->query_id && /* skip tables already used */ !(thd->prelocked_mode && table->query_id)) { - distance= ((int) table->reginfo.lock_type - - (int) table_list->lock_type); + int distance= ((int) table->reginfo.lock_type - + (int) table_list->lock_type); /* Find a table that either has the exact lock type requested, or has the best suitable lock. In case there is no locked table that has an equal or higher lock than requested, - we still maitain the best_table to produce an error message - about wrong lock mode on the table. The best_table is changed + we us the closest matching lock to be able to produce an error + message about wrong lock mode on the table. The best_table is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd. - distance < 0 - we have not enough high lock mode + distance < 0 - No suitable lock found distance > 0 - we have lock mode higher then we require distance == 0 - we have lock mode exactly which we need */ @@ -1070,7 +1071,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { best_distance= distance; best_table= table; - if (best_distance == 0) + if (best_distance == 0) // Found perfect lock break; } } @@ -1740,7 +1741,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, !my_strcasecmp(system_charset_info, name, "proc")) entry->s->system_table= 1; - if (Table_triggers_list::check_n_load(thd, db, name, entry)) + if (Table_triggers_list::check_n_load(thd, db, name, entry, 0)) goto err; /* @@ -4081,6 +4082,9 @@ void flush_tables() The table will be closed (not stored in cache) by the current thread when close_thread_tables() is called. + PREREQUISITES + Lock on LOCK_open() + RETURN 0 This thread now have exclusive access to this table and no other thread can access the table until close_thread_tables() is called. @@ -4088,62 +4092,97 @@ void flush_tables() */ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, - bool return_if_owned_by_thd) + uint flags) { char key[MAX_DBKEY_LENGTH]; uint key_length; TABLE *table; - bool result=0; + bool result=0, signalled= 0; DBUG_ENTER("remove_table_from_cache"); + key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; - for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; - table; - table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) + for (;;) { - THD *in_use; - table->s->version= 0L; /* Free when thread is ready */ - if (!(in_use=table->in_use)) - { - DBUG_PRINT("info",("Table was not in use")); - relink_unused(table); - } - else if (in_use != thd) + result= signalled= 0; + + for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; + table; + table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) { - in_use->some_tables_deleted=1; - if (table->db_stat) - result=1; - /* Kill delayed insert threads */ - if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && - ! in_use->killed) + THD *in_use; + table->s->version=0L; /* Free when thread is ready */ + if (!(in_use=table->in_use)) { - in_use->killed= THD::KILL_CONNECTION; - pthread_mutex_lock(&in_use->mysys_var->mutex); - if (in_use->mysys_var->current_cond) - { - pthread_mutex_lock(in_use->mysys_var->current_mutex); - pthread_cond_broadcast(in_use->mysys_var->current_cond); - pthread_mutex_unlock(in_use->mysys_var->current_mutex); - } - pthread_mutex_unlock(&in_use->mysys_var->mutex); + DBUG_PRINT("info",("Table was not in use")); + relink_unused(table); } - /* - Now we must abort all tables locks used by this thread - as the thread may be waiting to get a lock for another table - */ - for (TABLE *thd_table= in_use->open_tables; - thd_table ; - thd_table= thd_table->next) + else if (in_use != thd) + { + in_use->some_tables_deleted=1; + if (table->db_stat) + result=1; + /* Kill delayed insert threads */ + if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && + ! in_use->killed) + { + in_use->killed= THD::KILL_CONNECTION; + pthread_mutex_lock(&in_use->mysys_var->mutex); + if (in_use->mysys_var->current_cond) + { + pthread_mutex_lock(in_use->mysys_var->current_mutex); + signalled= 1; + pthread_cond_broadcast(in_use->mysys_var->current_cond); + pthread_mutex_unlock(in_use->mysys_var->current_mutex); + } + pthread_mutex_unlock(&in_use->mysys_var->mutex); + } + /* + Now we must abort all tables locks used by this thread + as the thread may be waiting to get a lock for another table + */ + for (TABLE *thd_table= in_use->open_tables; + thd_table ; + thd_table= thd_table->next) + { + if (thd_table->db_stat) // If table is open + signalled|= mysql_lock_abort_for_thread(thd, thd_table); + } + } + else + result= result || (flags & RTFC_OWNED_BY_THD_FLAG); + } + while (unused_tables && !unused_tables->s->version) + VOID(hash_delete(&open_cache,(byte*) unused_tables)); + if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG)) + { + if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed) { - if (thd_table->db_stat) // If table is open - mysql_lock_abort_for_thread(thd, thd_table); + dropping_tables++; + if (likely(signalled)) + (void) pthread_cond_wait(&COND_refresh, &LOCK_open); + else + { + struct timespec abstime; + /* + It can happen that another thread has opened the + table but has not yet locked any table at all. Since + it can be locked waiting for a table that our thread + has done LOCK TABLE x WRITE on previously, we need to + ensure that the thread actually hears our signal + before we go to sleep. Thus we wait for a short time + and then we retry another loop in the + remove_table_from_cache routine. + */ + set_timespec(abstime, 10); + pthread_cond_timedwait(&COND_refresh, &LOCK_open, &abstime); + } + dropping_tables--; + continue; } } - else - result= result || return_if_owned_by_thd; + break; } - while (unused_tables && !unused_tables->s->version) - VOID(hash_delete(&open_cache,(byte*) unused_tables)); DBUG_RETURN(result); } diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index bc1484b4fb0..0f5b6dcd35e 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -51,6 +51,14 @@ public: bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0); bitmap_intersect(&map, &map2); } + /* Use highest bit for all bits above sizeof(ulonglong)*8. */ + void intersect_extended(ulonglong map2buff) + { + intersect(map2buff); + if (map.bitmap_size > sizeof(ulonglong)) + bitmap_set_above(&map, sizeof(ulonglong), + test(map2buff & (LL(1) << (sizeof(ulonglong) * 8 - 1)))); + } void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); } void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); } my_bool is_set(uint n) const { return bitmap_is_set(&map, n); } @@ -116,6 +124,7 @@ public: void clear_all() { map=(ulonglong)0; } void intersect(Bitmap<64>& map2) { map&= map2.map; } void intersect(ulonglong map2) { map&= map2; } + void intersect_extended(ulonglong map2) { map&= map2; } void subtract(Bitmap<64>& map2) { map&= ~map2.map; } void merge(Bitmap<64>& map2) { map|= map2.map; } my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index e0a15b7d449..15d4f699bc9 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -774,10 +774,11 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) Query_cache_query_flags flags; // fill all gaps between fields with 0 to get repeatable key bzero(&flags, QUERY_CACHE_FLAGS_SIZE); - flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? - 1 : 0); - flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? - 1 : 0); + flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG); + flags.client_protocol_41= test(thd->client_capabilities & + CLIENT_PROTOCOL_41); + flags.more_results_exists= test(thd->server_status & + SERVER_MORE_RESULTS_EXISTS); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -791,6 +792,20 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ +CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ +sql mode: 0x%lx, sort len: %lu, conncat len: %lu", + (int)flags.client_long_flag, + (int)flags.client_protocol_41, + (int)flags.more_results_exists, + flags.character_set_client_num, + flags.character_set_results_num, + flags.collation_connection_num, + flags.limit, + (ulong)flags.time_zone, + flags.sql_mode, + flags.max_sort_length, + flags.group_concat_max_len)); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size == 0) @@ -973,10 +988,11 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) // fill all gaps between fields with 0 to get repeatable key bzero(&flags, QUERY_CACHE_FLAGS_SIZE); - flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? - 1 : 0); - flags.client_protocol_41= (thd->client_capabilities & CLIENT_PROTOCOL_41 ? - 1 : 0); + flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG); + flags.client_protocol_41= test(thd->client_capabilities & + CLIENT_PROTOCOL_41); + flags.more_results_exists= test(thd->server_status & + SERVER_MORE_RESULTS_EXISTS); flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= (thd->variables.character_set_results ? @@ -988,6 +1004,20 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ +CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ +sql mode: 0x%lx, sort len: %lu, conncat len: %lu", + (int)flags.client_long_flag, + (int)flags.client_protocol_41, + (int)flags.more_results_exists, + flags.character_set_client_num, + flags.character_set_results_num, + flags.collation_connection_num, + flags.limit, + (ulong)flags.time_zone, + flags.sql_mode, + flags.max_sort_length, + flags.group_concat_max_len)); memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)), &flags, QUERY_CACHE_FLAGS_SIZE); query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, @@ -2051,7 +2081,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, */ data_len= len - new_block->length; prev_block= new_block; - } while(1); + } while (1); DBUG_RETURN(TRUE); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d0ac1a16f6b..89d5b543dfc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -173,6 +173,7 @@ Open_tables_state::Open_tables_state() THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), Open_tables_state(), + lock_id(&main_lock_id), user_time(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), @@ -265,6 +266,8 @@ THD::THD() tablespace_op=FALSE; ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); + thr_lock_info_init(&lock_info); /* safety: will be reset after start */ + thr_lock_owner_init(&main_lock_id, &lock_info); } @@ -406,6 +409,8 @@ THD::~THD() net_end(&net); } #endif + stmt_map.destroy(); /* close all prepared statements */ + DBUG_ASSERT(lock_info.n_cursors == 0); if (!cleanup_done) cleanup(); @@ -518,6 +523,7 @@ bool THD::store_globals() if this is the slave SQL thread. */ variables.pseudo_thread_id= thread_id; + thr_lock_info_init(&lock_info); return 0; } @@ -1563,6 +1569,12 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup) } +void Statement::close_cursor() +{ + DBUG_ASSERT("Statement::close_cursor()" == "not implemented"); +} + + void THD::end_statement() { /* Cleanup SQL processing state to resuse this statement in next query. */ @@ -1683,6 +1695,14 @@ int Statement_map::insert(Statement *statement) } +void Statement_map::close_transient_cursors() +{ + Statement *stmt; + while ((stmt= transient_cursor_list.head())) + stmt->close_cursor(); /* deletes itself from the list */ +} + + bool select_dumpvar::send_data(List<Item> &items) { List_iterator_fast<Item_func_set_user_var> li(vars); diff --git a/sql/sql_class.h b/sql/sql_class.h index 6c4315b95fa..90112bd650b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -756,7 +756,7 @@ class Cursor; be used explicitly. */ -class Statement: public Query_arena +class Statement: public ilink, public Query_arena { Statement(const Statement &rhs); /* not implemented: */ Statement &operator=(const Statement &rhs); /* non-copyable */ @@ -833,6 +833,8 @@ public: void restore_backup_statement(Statement *stmt, Statement *backup); /* return class type */ virtual Type type() const; + /* Close the cursor open for this statement, if there is one */ + virtual void close_cursor(); }; @@ -884,15 +886,25 @@ public: } hash_delete(&st_hash, (byte *) statement); } + void add_transient_cursor(Statement *stmt) + { transient_cursor_list.append(stmt); } + void erase_transient_cursor(Statement *stmt) { stmt->unlink(); } + /* + Close all cursors of this connection that use tables of a storage + engine that has transaction-specific state and therefore can not + survive COMMIT or ROLLBACK. Currently all but MyISAM cursors are closed. + */ + void close_transient_cursors(); /* Erase all statements (calls Statement destructor) */ void reset() { my_hash_reset(&names_hash); my_hash_reset(&st_hash); + transient_cursor_list.empty(); last_found_statement= 0; } - ~Statement_map() + void destroy() { hash_free(&names_hash); hash_free(&st_hash); @@ -900,6 +912,7 @@ public: private: HASH st_hash; HASH names_hash; + I_List<Statement> transient_cursor_list; Statement *last_found_statement; }; @@ -1017,8 +1030,7 @@ public: a thread/connection descriptor */ -class THD :public ilink, - public Statement, +class THD :public Statement, public Open_tables_state { public: @@ -1044,6 +1056,10 @@ public: struct rand_struct rand; // used for authentication struct system_variables variables; // Changeable local variables struct system_status_var status_var; // Per thread statistic vars + THR_LOCK_INFO lock_info; // Locking info of this thread + THR_LOCK_OWNER main_lock_id; // To use for conventional queries + THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to + // the lock_id of a cursor. pthread_mutex_t LOCK_delete; // Locked before thd is deleted /* all prepared statements and cursors of this connection */ Statement_map stmt_map; @@ -1689,13 +1705,14 @@ public: bool using_indirect_summary_function; /* If >0 convert all blob fields to varchar(convert_blob_length) */ uint convert_blob_length; + bool need_const; /* <=> const items are saved in tmp table */ CHARSET_INFO *table_charset; bool schema_table; TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0), group_null_parts(0), convert_blob_length(0), - schema_table(0) + need_const(0), schema_table(0) {} ~TMP_TABLE_PARAM() { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 630a7e950f7..ccc0236997f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -563,7 +563,7 @@ int yylex(void *arg, void *yythd) grammatically correct. */ else if (c == '?' && ((THD*) yythd)->command == COM_STMT_PREPARE && - !ident_map[cs, yyPeek()]) + !ident_map[yyPeek()]) return(PARAM_MARKER); return((int) c); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 45c8182a29c..4bba0c432c7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -57,6 +57,7 @@ enum enum_sql_command { SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, + SQLCOM_SHOW_TRIGGERS, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, SQLCOM_GRANT, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2e5cab4bb1c..1c220ccb9f3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -775,29 +775,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", @@ -2104,6 +2094,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, case SCH_TABLE_NAMES: case SCH_TABLES: case SCH_VIEWS: + case SCH_TRIGGERS: #ifdef DONT_ALLOW_SHOW_COMMANDS my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ @@ -2151,7 +2142,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, TABLE_LIST **query_tables_last= lex->query_tables_last; sel= new SELECT_LEX(); sel->init_query(); - if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, + if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, (List<String> *) 0, (List<String> *) 0)) DBUG_RETURN(1); lex->query_tables_last= query_tables_last; @@ -2304,7 +2295,8 @@ mysql_execute_command(THD *thd) Don't reset warnings when executing a stored routine. */ if ((all_tables || &lex->select_lex != lex->all_selects_list || - lex->sroutines.records) && !thd->spcont) + lex->sroutines.records) && !thd->spcont || + lex->time_zone_tables_used) mysql_reset_errors(thd, 0); #ifdef HAVE_REPLICATION @@ -2385,10 +2377,12 @@ mysql_execute_command(THD *thd) select_result *result=lex->result; if (all_tables) { - res= check_table_access(thd, - lex->exchange ? SELECT_ACL | FILE_ACL : - SELECT_ACL, - all_tables, 0); + if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC && + lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC) + res= check_table_access(thd, + lex->exchange ? SELECT_ACL | FILE_ACL : + SELECT_ACL, + all_tables, 0); } else res= check_access(thd, @@ -3651,6 +3645,7 @@ end_with_restore_list: if (!(res = mysql_create_function(thd, &lex->udf))) send_ok(thd); #else + net_printf_error(thd, ER_CANT_OPEN_LIBRARY, lex->udf.dl, 0, "feature disabled"); res= TRUE; #endif break; @@ -5093,8 +5088,9 @@ bool check_stack_overrun(THD *thd, long margin, if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= (long) (thread_stack - margin)) { - sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack); - my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0)); + sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE), + stack_used,thread_stack,margin); + my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0)); thd->fatal_error(); return 1; } @@ -6843,7 +6839,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) /* Is there tables of subqueries? */ - if (&lex->select_lex != lex->all_selects_list) + if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used) { DBUG_PRINT("info",("Checking sub query list")); for (table= tables; table; table= table->next_global) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3e291243e1e..18707cc6c87 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -319,7 +319,7 @@ static void set_param_float(Item_param *param, uchar **pos, ulong len) return; float4get(data,*pos); #else - data= *(float*) *pos; + floatget(data, *pos); #endif param->set_double((double) data); *pos+= 4; @@ -333,7 +333,7 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len) return; float8get(data,*pos); #else - data= *(double*) *pos; + doubleget(data, *pos); #endif param->set_double((double) data); *pos+= 8; @@ -601,10 +601,8 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, Item_param **begin= stmt->param_array; Item_param **end= begin + stmt->param_count; uint32 length= 0; - String str; const String *res; - DBUG_ENTER("insert_params_withlog"); if (query->copy(stmt->query, stmt->query_length, default_charset_info)) @@ -1684,10 +1682,12 @@ static bool init_param_array(Prepared_statement *stmt) static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd) { + DBUG_ENTER("cleanup_stmt_and_thd_after_use"); stmt->lex->unit.cleanup(); cleanup_items(stmt->free_list); thd->rollback_item_tree_changes(); thd->cleanup_after_query(); + DBUG_VOID_RETURN; } /* @@ -1757,6 +1757,10 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, DBUG_RETURN(TRUE); } + /* + alloc_query() uses thd->memroot && thd->query, so we have to call + both of backup_statement() and backup_item_area() here. + */ thd->set_n_backup_statement(stmt, &stmt_backup); thd->set_n_backup_item_arena(stmt, &stmt_backup); @@ -1980,7 +1984,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; - DBUG_PRINT("exec_query:", ("%s", stmt->query)); + DBUG_PRINT("exec_query", ("%s", stmt->query)); + DBUG_PRINT("info",("stmt: %p", stmt)); /* Check if we got an error when sending long data */ if (stmt->state == Query_arena::ERROR) @@ -2016,6 +2021,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) DBUG_VOID_RETURN; /* If lex->result is set, mysql_execute_command will use it */ stmt->lex->result= &cursor->result; + thd->lock_id= &cursor->lock_id; } } #ifndef EMBEDDED_LIBRARY @@ -2065,6 +2071,9 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) Cursor::open is buried deep in JOIN::exec of the top level join. */ cursor->init_from_thd(thd); + + if (cursor->close_at_commit) + thd->stmt_map.add_transient_cursor(stmt); } else { @@ -2073,7 +2082,12 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) reset_stmt_params(stmt); } + log_slow_statement(thd); + /* Prevent from second logging in the end of dispatch_command */ + thd->enable_slow_log= FALSE; + thd->set_statement(&stmt_backup); + thd->lock_id= &thd->main_lock_id; thd->current_arena= thd; DBUG_VOID_RETURN; @@ -2118,6 +2132,8 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) DBUG_VOID_RETURN; } + DBUG_PRINT("info",("stmt: %p", stmt)); + /* Must go before setting variables, as it clears thd->user_var_events */ mysql_reset_thd_for_next_command(thd); thd->set_n_backup_statement(stmt, &stmt_backup); @@ -2244,10 +2260,12 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); /* - Must be the last, as some momory is still needed for + Must be the last, as some memory is still needed for the previous calls. */ free_root(cursor->mem_root, MYF(0)); + if (cursor->close_at_commit) + thd->stmt_map.erase_transient_cursor(stmt); } thd->restore_backup_statement(stmt, &stmt_backup); @@ -2287,14 +2305,6 @@ void mysql_stmt_reset(THD *thd, char *packet) DBUG_VOID_RETURN; stmt->close_cursor(); /* will reset statement params */ - cursor= stmt->cursor; - if (cursor && cursor->is_open()) - { - thd->change_list= cursor->change_list; - cursor->close(FALSE); - cleanup_stmt_and_thd_after_use(stmt, thd); - free_root(cursor->mem_root, MYF(0)); - } stmt->state= Query_arena::PREPARED; @@ -2444,19 +2454,26 @@ void Prepared_statement::setup_set_params() Prepared_statement::~Prepared_statement() { + DBUG_ENTER("Prepared_statement::~Prepared_statement"); + DBUG_PRINT("enter",("stmt: %p cursor: %p", this, cursor)); if (cursor) { if (cursor->is_open()) { cursor->close(FALSE); - free_items(); + cleanup_items(free_list); + thd->rollback_item_tree_changes(); free_root(cursor->mem_root, MYF(0)); } cursor->Cursor::~Cursor(); } - else - free_items(); + /* + We have to call free on the items even if cleanup is called as some items, + like Item_param, don't free everything until free_items() + */ + free_items(); delete lex->result; + DBUG_VOID_RETURN; } @@ -2468,16 +2485,22 @@ Query_arena::Type Prepared_statement::type() const void Prepared_statement::close_cursor() { + DBUG_ENTER("Prepared_statement::close_cursor"); + DBUG_PRINT("enter",("stmt: %p", this)); + if (cursor && cursor->is_open()) { thd->change_list= cursor->change_list; cursor->close(FALSE); cleanup_stmt_and_thd_after_use(this, thd); free_root(cursor->mem_root, MYF(0)); + if (cursor->close_at_commit) + thd->stmt_map.erase_transient_cursor(this); } /* Clear parameters from data which could be set by mysql_stmt_send_long_data() call. */ reset_stmt_params(this); + DBUG_VOID_RETURN; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 87bf5463ffa..32a8378d41d 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1526,7 +1526,7 @@ bool show_binlogs(THD* thd) else { /* this is an old log, open it and find the size */ - if ((file= my_open(fname+dir_len, O_RDONLY | O_SHARE | O_BINARY, + if ((file= my_open(fname, O_RDONLY | O_SHARE | O_BINARY, MYF(0))) >= 0) { file_length= (ulonglong) my_seek(file, 0L, MY_SEEK_END, MYF(0)); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87ce26b24d5..74ac9f21a81 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1198,7 +1198,14 @@ JOIN::exec() { result->send_fields(fields_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); - if (!having || having->val_int()) + /* + We have to test for 'conds' here as the WHERE may not be constant + even if we don't have any tables for prepared statements or if + conds uses something like 'rand()'. + */ + if (cond_value != Item::COND_FALSE && + (!conds || conds->val_int()) && + (!having || having->val_int())) { if (do_send_rows && (procedure ? (procedure->send_row(fields_list) || procedure->end_of_records()) @@ -1207,14 +1214,18 @@ JOIN::exec() else { error= (int) result->send_eof(); - send_records=1; + send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 : + thd->sent_row_count); } } else + { error=(int) result->send_eof(); + send_records= 0; + } } - /* Single select (without union and limit) always returns 1 row */ - thd->limit_found_rows= 1; + /* Single select (without union) always returns 0 or 1 row */ + thd->limit_found_rows= send_records; thd->examined_row_count= 0; DBUG_VOID_RETURN; } @@ -1702,16 +1713,20 @@ JOIN::destroy() Cursor::Cursor(THD *thd) :Query_arena(&main_mem_root, INITIALIZED), - join(0), unit(0) + join(0), unit(0), + close_at_commit(FALSE) { /* We will overwrite it at open anyway. */ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); + thr_lock_owner_init(&lock_id, &thd->lock_info); + bzero((void*) ht_info, sizeof(ht_info)); } void Cursor::init_from_thd(THD *thd) { + Engine_info *info; /* We need to save and reset thd->mem_root, otherwise it'll be freed later in mysql_parse. @@ -1739,6 +1754,22 @@ Cursor::init_from_thd(THD *thd) free_list= thd->free_list; change_list= thd->change_list; reset_thd(thd); + /* Now we have an active cursor and can cause a deadlock */ + thd->lock_info.n_cursors++; + + close_at_commit= FALSE; /* reset in case we're reusing the cursor */ + info= &ht_info[0]; + for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) + { + const handlerton *ht= *pht; + close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); + if (ht->create_cursor_read_view) + { + info->ht= ht; + info->read_view= (ht->create_cursor_read_view)(); + ++info; + } + } /* XXX: thd->locked_tables is not changed. What problems can we have with it if cursor is open? @@ -1832,6 +1863,9 @@ Cursor::fetch(ulong num_rows) /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &backup_arena); + for (Engine_info *info= ht_info; info->read_view ; info++) + (info->ht->set_cursor_read_view)(info->read_view); + join->fetch_limit+= num_rows; error= sub_select(join, join_tab, 0); @@ -1848,6 +1882,9 @@ Cursor::fetch(ulong num_rows) /* Grab free_list here to correctly free it in close */ thd->restore_backup_item_arena(this, &backup_arena); + for (Engine_info *info= ht_info; info->read_view; info++) + (info->ht->set_cursor_read_view)(0); + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ @@ -1888,6 +1925,13 @@ Cursor::close(bool is_active) else (void) join->select_lex->cleanup(); + for (Engine_info *info= ht_info; info->read_view; info++) + { + (info->ht->close_cursor_read_view)(info->read_view); + info->read_view= 0; + info->ht= 0; + } + if (is_active) close_thread_tables(thd); else @@ -1907,6 +1951,7 @@ Cursor::close(bool is_active) thd->derived_tables= tmp_derived_tables; thd->lock= tmp_lock; } + thd->lock_info.n_cursors--; /* Decrease the number of active cursors */ join= 0; unit= 0; free_items(); @@ -2714,7 +2759,9 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, */ (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && - ((Item_field*)*value)->field->maybe_null(); + + (((Item_field*)*value)->field->maybe_null() || + ((Item_field *)*value)->field->table->maybe_null); (*key_fields)++; } @@ -2834,11 +2881,11 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) values--; + DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC || + cond_func->argument_count() != 2); add_key_equal_fields(key_fields, *and_level, cond_func, (Item_field*) (cond_func->key_item()->real_item()), - cond_func->argument_count() == 2 && - cond_func->functype() == Item_func::IN_FUNC, - values, + 0, values, cond_func->argument_count()-1, usable_tables); } @@ -5182,12 +5229,17 @@ static void add_not_null_conds(JOIN *join) if (tab->ref.null_rejecting & (1 << keypart)) { Item *item= tab->ref.items[keypart]; + Item *notnull; DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *not_null_item= (Item_field*)item; JOIN_TAB *referred_tab= not_null_item->field->table->reginfo.join_tab; - if (referred_tab->join != join) + /* + For UPDATE queries such as: + UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); + not_null_item is the t1.f1, but it's referred_tab is 0. + */ + if (!referred_tab || referred_tab->join != join) continue; - Item *notnull; if (!(notnull= new Item_func_isnotnull(not_null_item))) DBUG_VOID_RETURN; /* @@ -6715,7 +6767,7 @@ static COND *build_equal_items_for_cond(COND *cond, of the condition expression. */ li.rewind(); - while((item= li++)) + while ((item= li++)) { Item *new_item; if ((new_item = build_equal_items_for_cond(item, inherited))!= item) @@ -7524,7 +7576,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) /* Flatten nested joins that can be flattened. */ li.rewind(); - while((table= li++)) + while ((table= li++)) { nested_join= table->nested_join; if (nested_join && !table->on_expr) @@ -7983,6 +8035,12 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool table_cant_handle_bit_fields, uint convert_blob_length) { + Item *org_item= item; + if (item->real_item()->type() == Item::FIELD_ITEM) + { + item= item->real_item(); + type= item->type(); + } switch (type) { case Item::SUM_FUNC_ITEM: { @@ -7995,30 +8053,22 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: { - Item_field *field= (Item_field*) item; - if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT) - return 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), - item->name, table, - modify_item ? (Item_field*) item : NULL, - convert_blob_length); - } - case Item::REF_ITEM: - { - Item *tmp_item; - if ((tmp_item= item->real_item())->type() == Item::FIELD_ITEM) + if (org_item->type() != Item::REF_ITEM || + !((Item_ref *)org_item)->depended_from) { - Item_field *field= (Item_field*) tmp_item; - Field *new_field= create_tmp_field_from_field(thd, - (*from_field= field->field), - item->name, table, - NULL, - convert_blob_length); - if (modify_item) - item->set_result_field(new_field); - return new_field; + Item_field *field= (Item_field*) item; + if (table_cant_handle_bit_fields && + field->field->type() == FIELD_TYPE_BIT) + return 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), + item->name, table, + modify_item ? (Item_field*) item : + NULL, + convert_blob_length); } + else + item= org_item; } case Item::FUNC_ITEM: case Item::COND_ITEM: @@ -8031,6 +8081,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::REAL_ITEM: case Item::DECIMAL_ITEM: case Item::STRING_ITEM: + case Item::REF_ITEM: case Item::NULL_ITEM: case Item::VARBIN_ITEM: return create_tmp_field_from_item(thd, item, table, copy_func, modify_item, @@ -8207,7 +8258,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, param->using_indirect_summary_function=1; continue; } - if (item->const_item() && (int) hidden_field_count <= 0) + if (item->const_item() && (int) hidden_field_count <= 0 && + !param->need_const) continue; // We don't have to store this } if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields) @@ -9808,6 +9860,11 @@ join_read_always_key(JOIN_TAB *tab) int error; TABLE *table= tab->table; + for (uint i= 0 ; i < tab->ref.key_parts ; i++) + { + if ((tab->ref.null_rejecting & 1 << i) && tab->ref.items[i]->is_null()) + return -1; + } if (!table->file->inited) table->file->ha_index_init(tab->ref.key); if (cp_buffer_from_ref(tab->join->thd, &tab->ref)) @@ -10861,12 +10918,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, usable_keys.set_all(); for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { - if ((*tmp_order->item)->type() != Item::FIELD_ITEM) + if ((*tmp_order->item)->real_item()->type() != Item::FIELD_ITEM) { usable_keys.clear_all(); DBUG_RETURN(0); } - usable_keys.intersect(((Item_field*) (*tmp_order->item))-> + usable_keys.intersect(((Item_field*) (*tmp_order->item)->real_item())-> field->part_of_sortkey); if (usable_keys.is_clear_all()) DBUG_RETURN(0); // No usable keys @@ -12120,7 +12177,6 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, List_iterator<Item> li(fields); Item *item; ORDER *order,*group,**prev; - uint index= 0; *all_order_by_fields_used= 1; while ((item=li++)) @@ -12157,12 +12213,12 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, simple indexing of ref_pointer_array (order in the array and in the list are same) */ - ord->item= ref_pointer_array + index; + ord->item= ref_pointer_array; ord->asc=1; *prev=ord; prev= &ord->next; } - index++; + ref_pointer_array++; } *prev=0; return group; @@ -12991,7 +13047,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, if (item->eq(*group_tmp->item,0)) { Item *new_item; - if(!(new_item= new Item_ref(context, group_tmp->item, 0, + if (!(new_item= new Item_ref(context, group_tmp->item, 0, item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); @@ -13061,7 +13117,7 @@ bool JOIN::rollup_init() ORDER *group_tmp; for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) { - if (item->eq(*group_tmp->item,0)) + if (*group_tmp->item == item) item->maybe_null= 1; } if (item->type() == Item::FUNC_ITEM) @@ -13181,7 +13237,7 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields, for (group_tmp= start_group, i= pos ; group_tmp ; group_tmp= group_tmp->next, i++) { - if (item->eq(*group_tmp->item,0)) + if (*group_tmp->item == item) { /* This is an element that is used by the GROUP BY and should be diff --git a/sql/sql_select.h b/sql/sql_select.h index 9285e33be33..1fa246370c6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -389,9 +389,17 @@ class Cursor: public Sql_alloc, public Query_arena TABLE *derived_tables; /* List of items created during execution */ query_id_t query_id; + struct Engine_info + { + const handlerton *ht; + void *read_view; + }; + Engine_info ht_info[MAX_HA]; public: Item_change_list change_list; select_send result; + THR_LOCK_OWNER lock_id; + my_bool close_at_commit; /* Temporary implementation as now we replace THD state by value */ /* Save THD state into cursor */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8343f9ec582..7ccf475b65e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -21,6 +21,7 @@ #include "sql_select.h" // For select_describe #include "repl_failsafe.h" #include "sp_head.h" +#include "sql_trigger.h" #include <my_dir.h> #ifdef HAVE_BERKELEY_DB @@ -1696,6 +1697,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) break; case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLE_STATUS: + case SQLCOM_SHOW_TRIGGERS: index_field_values->db_value= lex->current_select->db; index_field_values->table_value= wild; break; @@ -1718,7 +1720,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel, ident_table.length= strlen(table); table_ident= new Table_ident(thd, ident_db, ident_table, 1); sel->init_query(); - if(!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, + if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, (List<String> *) 0, (List<String> *) 0)) return 1; return 0; @@ -2377,6 +2379,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, { const char *tmp_buff; byte *pos; + bool is_blob; uint flags=field->flags; char tmp[MAX_FIELD_WIDTH]; char tmp1[MAX_FIELD_WIDTH]; @@ -2455,12 +2458,14 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, "NO" : "YES"); table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); - if (field->has_charset()) + is_blob= (field->type() == FIELD_TYPE_BLOB); + if (field->has_charset() || is_blob) { - table->field[8]->store((longlong) field->field_length/ - field->charset()->mbmaxlen); + longlong c_octet_len= is_blob ? (longlong) field->max_length() : + (longlong) field->max_length()/field->charset()->mbmaxlen; + table->field[8]->store(c_octet_len); table->field[8]->set_notnull(); - table->field[9]->store((longlong) field->field_length); + table->field[9]->store((longlong) field->max_length()); table->field[9]->set_notnull(); } @@ -2488,6 +2493,17 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, case FIELD_TYPE_LONG: case FIELD_TYPE_LONGLONG: case FIELD_TYPE_INT24: + { + table->field[10]->store((longlong) field->max_length() - 1); + table->field[10]->set_notnull(); + break; + } + case FIELD_TYPE_BIT: + { + table->field[10]->store((longlong) field->max_length()); + table->field[10]->set_notnull(); + break; + } case FIELD_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: { @@ -2963,6 +2979,86 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables, } +static bool store_trigger(THD *thd, TABLE *table, const char *db, + const char *tname, LEX_STRING *trigger_name, + enum trg_event_type event, + enum trg_action_time_type timing, + LEX_STRING *trigger_stmt, + ulong sql_mode) +{ + CHARSET_INFO *cs= system_charset_info; + byte *sql_mode_str; + ulong sql_mode_len; + + restore_record(table, s->default_values); + table->field[1]->store(db, strlen(db), cs); + table->field[2]->store(trigger_name->str, trigger_name->length, cs); + table->field[3]->store(trg_event_type_names[event].str, + trg_event_type_names[event].length, cs); + table->field[5]->store(db, strlen(db), cs); + table->field[6]->store(tname, strlen(tname), cs); + table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs); + table->field[10]->store("ROW", 3, cs); + table->field[11]->store(trg_action_time_type_names[timing].str, + trg_action_time_type_names[timing].length, cs); + table->field[14]->store("OLD", 3, cs); + table->field[15]->store("NEW", 3, cs); + + sql_mode_str= + sys_var_thd_sql_mode::symbolic_mode_representation(thd, + sql_mode, + &sql_mode_len); + table->field[17]->store(sql_mode_str, sql_mode_len, cs); + return schema_table_store_record(thd, table); +} + + +static int get_schema_triggers_record(THD *thd, struct st_table_list *tables, + TABLE *table, bool res, + const char *base_name, + const char *file_name) +{ + DBUG_ENTER("get_schema_triggers_record"); + /* + res can be non zero value when processed table is a view or + error happened during opening of processed table. + */ + if (res) + { + if (!tables->view) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->net.last_errno, thd->net.last_error); + thd->clear_error(); + DBUG_RETURN(0); + } + if (!tables->view && tables->table->triggers) + { + Table_triggers_list *triggers= tables->table->triggers; + int event, timing; + for (event= 0; event < (int)TRG_EVENT_MAX; event++) + { + for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++) + { + LEX_STRING trigger_name; + LEX_STRING trigger_stmt; + ulong sql_mode; + if (triggers->get_trigger_info(thd, (enum trg_event_type) event, + (enum trg_action_time_type)timing, + &trigger_name, &trigger_stmt, + &sql_mode)) + continue; + if (store_trigger(thd, table, base_name, file_name, &trigger_name, + (enum trg_event_type) event, + (enum trg_action_time_type) timing, &trigger_stmt, + sql_mode)) + DBUG_RETURN(1); + } + } + } + DBUG_RETURN(0); +} + + void store_key_column_usage(TABLE *table, const char*db, const char *tname, const char *key_name, uint key_len, const char *con_type, uint con_len, longlong idx) @@ -3460,9 +3556,8 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) if (table_list->schema_table_reformed) // show command { SELECT_LEX *sel= lex->current_select; - uint i= 0; Item *item; - Field_translator *transl; + Field_translator *transl, *org_transl; if (table_list->field_translation) { @@ -3483,16 +3578,17 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { DBUG_RETURN(1); } - while ((item= it++)) + for (org_transl= transl; (item= it++); transl++) { - char *name= item->name; - transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, &transl[i].item)) + transl->item= item; + transl->name= item->name; + if (!item->fixed && item->fix_fields(thd, &transl->item)) + { DBUG_RETURN(1); - transl[i++].name= name; + } } - table_list->field_translation= transl; - table_list->field_translation_end= transl + sel->item_list.elements; + table_list->field_translation= org_transl; + table_list->field_translation_end= transl; } DBUG_RETURN(0); @@ -3847,6 +3943,30 @@ ST_FIELD_INFO open_tables_fields_info[]= }; +ST_FIELD_INFO triggers_fields_info[]= +{ + {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"}, + {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"}, + {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"}, + {"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0}, + {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"}, + {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0}, + {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"}, + {"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0}, + {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0}, + {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"}, + {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + ST_FIELD_INFO variables_fields_info[]= { {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"}, @@ -3897,6 +4017,8 @@ ST_SCHEMA_TABLE schema_tables[]= fill_open_tables, make_old_format, 0, -1, -1, 1}, {"STATUS", variables_fields_info, create_schema_table, fill_status, make_old_format, 0, -1, -1, 1}, + {"TRIGGERS", triggers_fields_info, create_schema_table, + get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0}, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, -1, -1, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0} diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 89282d9fcb9..b5d48f3dc3b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -23,6 +23,8 @@ #include <hash.h> #include <myisam.h> #include <my_dir.h> +#include "sp_head.h" +#include "sql_trigger.h" #ifdef __WIN__ #include <io.h> @@ -237,15 +239,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error=0; if (!drop_temporary) { - abort_locked_tables(thd,db,table->table_name); - while (remove_table_from_cache(thd, db, table->table_name, 0) && - !thd->killed) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } - drop_locked_tables(thd,db,table->table_name); + abort_locked_tables(thd, db, table->table_name); + remove_table_from_cache(thd, db, table->table_name, + RTFC_WAIT_OTHER_THREAD_FLAG | + RTFC_CHECK_KILLED_FLAG); + drop_locked_tables(thd, db, table->table_name); if (thd->killed) { thd->no_warnings_for_error= 0; @@ -290,16 +288,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, if (!(new_error=my_delete(path,MYF(MY_WME)))) { some_tables_deleted=1; - /* - Destroy triggers for this table if there are any. - - We won't need this as soon as we will have new .FRM format, - in which we will store trigger definitions in the same .FRM - files as table descriptions. - */ - strmov(end, triggers_file_ext); - if (!access(path, F_OK)) - new_error= my_delete(path, MYF(MY_WME)); + new_error= Table_triggers_list::drop_all_triggers(thd, db, + table->table_name); } error|= new_error; } @@ -1630,12 +1620,10 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, create_info->data_file_name= create_info->index_file_name= 0; create_info->table_options=db_options; - if (rea_create_table(thd, path, create_info, fields, key_count, + if (rea_create_table(thd, path, db, table_name, + create_info, fields, key_count, key_info_buffer)) - { - /* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */ goto end; - } if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { /* Open table and put in temporary table list */ @@ -1876,12 +1864,8 @@ static void wait_while_table_is_used(THD *thd,TABLE *table, mysql_lock_abort(thd, table); // end threads waiting on lock /* Wait until all there are no other threads that has this table open */ - while (remove_table_from_cache(thd, table->s->db, table->s->table_name, 0)) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } + remove_table_from_cache(thd, table->s->db, + table->s->table_name, RTFC_WAIT_OTHER_THREAD_FLAG); DBUG_VOID_RETURN; } @@ -2268,14 +2252,10 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting to get writelock"); mysql_lock_abort(thd,table->table); - while (remove_table_from_cache(thd, table->table->s->db, - table->table->s->table_name, 0) && - ! thd->killed) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } + remove_table_from_cache(thd, table->table->s->db, + table->table->s->table_name, + RTFC_WAIT_OTHER_THREAD_FLAG | + RTFC_CHECK_KILLED_FLAG); thd->exit_cond(old_message); if (thd->killed) goto err; @@ -2420,7 +2400,7 @@ send_result_message: { pthread_mutex_lock(&LOCK_open); remove_table_from_cache(thd, table->table->s->db, - table->table->s->table_name, 0); + table->table->s->table_name, RTFC_NO_FLAG); pthread_mutex_unlock(&LOCK_open); /* May be something modified consequently we have to invalidate cache */ query_cache_invalidate3(thd, table->table, 0); @@ -2678,8 +2658,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* Create a new table by copying from source table */ - if (my_copy(src_path, dst_path, MYF(MY_WME|MY_DONT_OVERWRITE_FILE))) + if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE))) + { + if (my_errno == ENOENT) + my_error(ER_BAD_DB_ERROR,MYF(0),db); + else + my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno); goto err; + } /* As mysql_truncate don't work on a new table at this stage of @@ -3747,8 +3733,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (table) { VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file - remove_table_from_cache(thd,db,table_name, 0); // Mark in-use copies old - mysql_lock_abort(thd,table); // end threads waiting on lock + /* Mark in-use copies old */ + remove_table_from_cache(thd,db,table_name,RTFC_NO_FLAG); + /* end threads waiting on lock */ + mysql_lock_abort(thd,table); } VOID(quick_rm_table(old_db_type,db,old_name)); if (close_data_tables(thd,db,table_name) || diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index fd79fc8b878..87608eb4c83 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -32,13 +32,56 @@ const char * const triggers_file_ext= ".TRG"; */ static File_option triggers_file_parameters[]= { - {{(char*)"triggers", 8}, offsetof(class Table_triggers_list, definitions_list), - FILE_OPTIONS_STRLIST}, + {{(char*)"triggers", 8}, + offsetof(class Table_triggers_list, definitions_list), + FILE_OPTIONS_STRLIST}, + {{(char*)"sql_modes", 13}, + offsetof(class Table_triggers_list, definition_modes_list), + FILE_OPTIONS_ULLLIST}, {{0, 0}, 0, FILE_OPTIONS_STRING} }; /* + Structure representing contents of .TRN file which are used to support + database wide trigger namespace. +*/ + +struct st_trigname +{ + LEX_STRING trigger_table; +}; + +static const LEX_STRING trigname_file_type= {(char *)"TRIGGERNAME", 11}; + +const char * const trigname_file_ext= ".TRN"; + +static File_option trigname_file_parameters[]= +{ + {{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table), + FILE_OPTIONS_ESTRING}, + {{0, 0}, 0, FILE_OPTIONS_STRING} +}; + + +const LEX_STRING trg_action_time_type_names[]= +{ + { (char *) STRING_WITH_LEN("BEFORE") }, + { (char *) STRING_WITH_LEN("AFTER") } +}; + +const LEX_STRING trg_event_type_names[]= +{ + { (char *) STRING_WITH_LEN("INSERT") }, + { (char *) STRING_WITH_LEN("UPDATE") }, + { (char *) STRING_WITH_LEN("DELETE") } +}; + + +static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); + + +/* Create or drop trigger for table. SYNOPSIS @@ -69,6 +112,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) But do we want this ? */ + if (!create && + !(tables= add_table_for_trigger(thd, thd->lex->spname))) + DBUG_RETURN(TRUE); + /* We should have only one table in table list. */ DBUG_ASSERT(tables->next_global == 0); @@ -84,12 +131,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) DBUG_RETURN(TRUE); /* - We do not allow creation of triggers on views or temporary tables. - We have to do this check here and not in - Table_triggers_list::create_trigger() because we want to avoid messing - with table cash for views and temporary tables. + We do not allow creation of triggers on temporary tables. We also don't + allow creation of triggers on views but fulfilment of this restriction + is guaranteed by open_ltable(). It is better to have this check here + than do it in Table_triggers_list::create_trigger() and mess with table + cache. */ - if (tables->view || table->s->tmp_table != NO_TMP_TABLE) + if (table->s->tmp_table != NO_TMP_TABLE) { my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); DBUG_RETURN(TRUE); @@ -174,28 +222,29 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) { LEX *lex= thd->lex; TABLE *table= tables->table; - char dir_buff[FN_REFLEN], file_buff[FN_REFLEN]; - LEX_STRING dir, file; + char dir_buff[FN_REFLEN], file_buff[FN_REFLEN], trigname_buff[FN_REFLEN], + trigname_path[FN_REFLEN]; + LEX_STRING dir, file, trigname_file; LEX_STRING *trg_def, *name; + ulonglong *trg_sql_mode; Item_trigger_field *trg_field; - List_iterator_fast<LEX_STRING> it(names_list); + struct st_trigname trigname; - /* We don't allow creation of several triggers of the same type yet */ - if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time]) + + /* Trigger must be in the same schema as target table. */ + if (my_strcasecmp(system_charset_info, table->s->db, + lex->spname->m_db.str ? lex->spname->m_db.str : + thd->db)) { - my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0)); + my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); return 1; } - /* Let us check if trigger with the same name exists */ - while ((name= it++)) + /* We don't allow creation of several triggers of the same type yet */ + if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time]) { - if (my_strcasecmp(system_charset_info, lex->ident.str, - name->str) == 0) - { - my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0)); - return 1; - } + my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0)); + return 1; } /* @@ -234,6 +283,25 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name, triggers_file_ext, NullS) - file_buff; file.str= file_buff; + trigname_file.length= strxnmov(trigname_buff, FN_REFLEN, + lex->spname->m_name.str, + trigname_file_ext, NullS) - trigname_buff; + trigname_file.str= trigname_buff; + strxnmov(trigname_path, FN_REFLEN, dir_buff, trigname_buff, NullS); + + /* Use the filesystem to enforce trigger namespace constraints. */ + if (!access(trigname_path, F_OK)) + { + my_error(ER_TRG_ALREADY_EXISTS, MYF(0)); + return 1; + } + + trigname.trigger_table.str= tables->table_name; + trigname.trigger_table.length= tables->table_name_length; + + if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type, + (gptr)&trigname, trigname_file_parameters, 0)) + return 1; /* Soon we will invalidate table object and thus Table_triggers_list object @@ -245,14 +313,71 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) */ if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root, sizeof(LEX_STRING))) || - definitions_list.push_back(trg_def, &table->mem_root)) - return 1; + definitions_list.push_back(trg_def, &table->mem_root) || + !(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root, + sizeof(ulonglong))) || + definition_modes_list.push_back(trg_sql_mode, &table->mem_root)) + goto err_with_cleanup; trg_def->str= thd->query; trg_def->length= thd->query_length; + *trg_sql_mode= thd->variables.sql_mode; + + if (!sql_create_definition_file(&dir, &file, &triggers_file_type, + (gptr)this, triggers_file_parameters, 3)) + return 0; + +err_with_cleanup: + my_delete(trigname_path, MYF(MY_WME)); + return 1; +} - return sql_create_definition_file(&dir, &file, &triggers_file_type, - (gptr)this, triggers_file_parameters, 3); + +/* + Deletes the .TRG file for a table + + SYNOPSIS + rm_trigger_file() + path - char buffer of size FN_REFLEN to be used + for constructing path to .TRG file. + db - table's database name + table_name - table's name + + RETURN VALUE + False - success + True - error +*/ + +static bool rm_trigger_file(char *path, char *db, char *table_name) +{ + strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", table_name, + triggers_file_ext, NullS); + unpack_filename(path, path); + return my_delete(path, MYF(MY_WME)); +} + + +/* + Deletes the .TRN file for a trigger + + SYNOPSIS + rm_trigname_file() + path - char buffer of size FN_REFLEN to be used + for constructing path to .TRN file. + db - trigger's database name + table_name - trigger's name + + RETURN VALUE + False - success + True - error +*/ + +static bool rm_trigname_file(char *path, char *db, char *trigger_name) +{ + strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", trigger_name, + trigname_file_ext, NullS); + unpack_filename(path, path); + return my_delete(path, MYF(MY_WME)); } @@ -275,12 +400,15 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) LEX_STRING *name; List_iterator_fast<LEX_STRING> it_name(names_list); List_iterator<LEX_STRING> it_def(definitions_list); + List_iterator<ulonglong> it_mod(definition_modes_list); + char path[FN_REFLEN]; while ((name= it_name++)) { it_def++; + it_mod++; - if (my_strcasecmp(system_charset_info, lex->ident.str, + if (my_strcasecmp(system_charset_info, lex->spname->m_name.str, name->str) == 0) { /* @@ -288,21 +416,18 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) clean trigger removing since table will be reopened anyway. */ it_def.remove(); + it_mod.remove(); if (definitions_list.is_empty()) { - char path[FN_REFLEN]; - /* TODO: Probably instead of removing .TRG file we should move to archive directory but this should be done as part of parse_file.cc functionality (because we will need it elsewhere). */ - strxnmov(path, FN_REFLEN, mysql_data_home, "/", tables->db, "/", - tables->table_name, triggers_file_ext, NullS); - unpack_filename(path, path); - return my_delete(path, MYF(MY_WME)); + if (rm_trigger_file(path, tables->db, tables->table_name)) + return 1; } else { @@ -317,10 +442,15 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) triggers_file_ext, NullS) - file_buff; file.str= file_buff; - return sql_create_definition_file(&dir, &file, &triggers_file_type, - (gptr)this, - triggers_file_parameters, 3); + if (sql_create_definition_file(&dir, &file, &triggers_file_type, + (gptr)this, triggers_file_parameters, + 3)) + return 1; } + + if (rm_trigname_file(path, tables->db, lex->spname->m_name.str)) + return 1; + return 0; } } @@ -331,8 +461,8 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) Table_triggers_list::~Table_triggers_list() { - for (int i= 0; i < 3; i++) - for (int j= 0; j < 2; j++) + for (int i= 0; i < (int)TRG_EVENT_MAX; i++) + for (int j= 0; j < (int)TRG_ACTION_MAX; j++) delete bodies[i][j]; if (record1_field) @@ -389,17 +519,21 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) db - table's database name table_name - table's name table - pointer to table object + names_only - stop after loading trigger names RETURN VALUE False - success True - error */ + bool Table_triggers_list::check_n_load(THD *thd, const char *db, - const char *table_name, TABLE *table) + const char *table_name, TABLE *table, + bool names_only) { char path_buff[FN_REFLEN]; LEX_STRING path; File_parser *parser; + LEX_STRING save_db; DBUG_ENTER("Table_triggers_list::check_n_load"); @@ -429,10 +563,48 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, if (!triggers) DBUG_RETURN(1); + /* + We don't have sql_modes in old versions of .TRG file, so we should + initialize list for safety. + */ + triggers->definition_modes_list.empty(); + if (parser->parse((gptr)triggers, &table->mem_root, - triggers_file_parameters, 1)) + triggers_file_parameters, 2)) DBUG_RETURN(1); + List_iterator_fast<LEX_STRING> it(triggers->definitions_list); + LEX_STRING *trg_create_str, *trg_name_str; + ulonglong *trg_sql_mode; + + if (triggers->definition_modes_list.is_empty() && + !triggers->definitions_list.is_empty()) + { + /* + It is old file format => we should fill list of sql_modes. + + We use one mode (current) for all triggers, because we have not + information about mode in old format. + */ + if (!(trg_sql_mode= (ulonglong*)alloc_root(&table->mem_root, + sizeof(ulonglong)))) + { + DBUG_RETURN(1); // EOM + } + *trg_sql_mode= global_system_variables.sql_mode; + while ((trg_create_str= it++)) + { + if (triggers->definition_modes_list.push_back(trg_sql_mode, + &table->mem_root)) + { + DBUG_RETURN(1); // EOM + } + } + it.rewind(); + } + + DBUG_ASSERT(triggers->definition_modes_list.elements == + triggers->definitions_list.elements); table->triggers= triggers; /* @@ -444,25 +616,30 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, alloc_root(&table->mem_root, triggers->sroutines_key.length))) DBUG_RETURN(1); triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER; - strmov(strmov(strmov(triggers->sroutines_key.str+1, db), "."), - table_name); + strxmov(triggers->sroutines_key.str+1, db, ".", table_name, NullS); /* TODO: This could be avoided if there is no triggers for UPDATE and DELETE. */ - if (triggers->prepare_record1_accessors(table)) + if (!names_only && triggers->prepare_record1_accessors(table)) DBUG_RETURN(1); - List_iterator_fast<LEX_STRING> it(triggers->definitions_list); - LEX_STRING *trg_create_str, *trg_name_str; char *trg_name_buff; + List_iterator_fast<ulonglong> itm(triggers->definition_modes_list); LEX *old_lex= thd->lex, lex; + ulong save_sql_mode= thd->variables.sql_mode; thd->lex= &lex; + save_db.str= thd->db; + save_db.length= thd->db_length; + thd->db_length= strlen(db); + thd->db= (char *) db; while ((trg_create_str= it++)) { + trg_sql_mode= itm++; + thd->variables.sql_mode= (ulong)*trg_sql_mode; lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length); if (yyparse((void *)thd) || thd->is_fatal_error) @@ -471,40 +648,31 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, Free lex associated resources QQ: Do we really need all this stuff here ? */ - if (lex.sphead) - { - delete lex.sphead; - lex.sphead= 0; - } + delete lex.sphead; goto err_with_lex_cleanup; } + lex.sphead->m_sql_mode= *trg_sql_mode; triggers->bodies[lex.trg_chistics.event] [lex.trg_chistics.action_time]= lex.sphead; - lex.sphead= 0; - - if (!(trg_name_buff= alloc_root(&table->mem_root, - sizeof(LEX_STRING) + - lex.ident.length + 1))) - goto err_with_lex_cleanup; - - trg_name_str= (LEX_STRING *)trg_name_buff; - trg_name_buff+= sizeof(LEX_STRING); - memcpy(trg_name_buff, lex.ident.str, - lex.ident.length + 1); - trg_name_str->str= trg_name_buff; - trg_name_str->length= lex.ident.length; + if (triggers->names_list.push_back(&lex.sphead->m_name, + &table->mem_root)) + goto err_with_lex_cleanup; - if (triggers->names_list.push_back(trg_name_str, &table->mem_root)) - goto err_with_lex_cleanup; + if (names_only) + { + lex_end(&lex); + continue; + } /* Let us bind Item_trigger_field objects representing access to fields in old/new versions of row in trigger to Field objects in table being opened. - We ignore errors here, because if even something is wrong we still will - be willing to open table to perform some operations (e.g. SELECT)... + We ignore errors here, because if even something is wrong we still + will be willing to open table to perform some operations (e.g. + SELECT)... Anyway some things can be checked only during trigger execution. */ for (Item_trigger_field *trg_field= @@ -515,7 +683,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, lex_end(&lex); } + thd->db= save_db.str; + thd->db_length= save_db.length; thd->lex= old_lex; + thd->variables.sql_mode= save_sql_mode; DBUG_RETURN(0); @@ -523,6 +694,9 @@ err_with_lex_cleanup: // QQ: anything else ? lex_end(&lex); thd->lex= old_lex; + thd->variables.sql_mode= save_sql_mode; + thd->db= save_db.str; + thd->db_length= save_db.length; DBUG_RETURN(1); } @@ -537,3 +711,163 @@ err_with_lex_cleanup: DBUG_RETURN(1); } + + +/* + Obtains and returns trigger metadata + + SYNOPSIS + get_trigger_info() + thd - current thread context + event - trigger event type + time_type - trigger action time + name - returns name of trigger + stmt - returns statement of trigger + sql_mode - returns sql_mode of trigger + + RETURN VALUE + False - success + True - error +*/ + +bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, + trg_action_time_type time_type, + LEX_STRING *trigger_name, + LEX_STRING *trigger_stmt, + ulong *sql_mode) +{ + sp_head *body; + DBUG_ENTER("get_trigger_info"); + if ((body= bodies[event][time_type])) + { + *trigger_name= body->m_name; + *trigger_stmt= body->m_body; + *sql_mode= body->m_sql_mode; + DBUG_RETURN(0); + } + DBUG_RETURN(1); +} + + +/* + Find trigger's table from trigger identifier and add it to + the statement table list. + + SYNOPSIS + mysql_table_for_trigger() + thd - current thread context + trig - identifier for trigger + + RETURN VALUE + 0 - error + # - pointer to TABLE_LIST object for the table +*/ + +static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) +{ + const char *db= !trig->m_db.str ? thd->db : trig->m_db.str; + LEX *lex= thd->lex; + char path_buff[FN_REFLEN]; + LEX_STRING path; + File_parser *parser; + struct st_trigname trigname; + DBUG_ENTER("add_table_for_trigger"); + + strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/", + trig->m_name.str, trigname_file_ext, NullS); + path.length= unpack_filename(path_buff, path_buff); + path.str= path_buff; + + if (access(path_buff, F_OK)) + { + my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); + DBUG_RETURN(0); + } + + if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1))) + DBUG_RETURN(0); + + if (strncmp(trigname_file_type.str, parser->type()->str, + parser->type()->length)) + { + my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext, + "TRIGGERNAME"); + DBUG_RETURN(0); + } + + if (parser->parse((gptr)&trigname, thd->mem_root, + trigname_file_parameters, 1)) + DBUG_RETURN(0); + + /* We need to reset statement table list to be PS/SP friendly. */ + lex->query_tables= 0; + lex->query_tables_last= &lex->query_tables; + DBUG_RETURN(sp_add_to_query_tables(thd, lex, db, + trigname.trigger_table.str, TL_WRITE)); +} + + +/* + Drop all triggers for table. + + SYNOPSIS + drop_all_triggers() + thd - current thread context + db - schema for table + name - name for table + + NOTE + The calling thread should hold the LOCK_open mutex; + + RETURN VALUE + False - success + True - error +*/ + +bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name) +{ + TABLE table; + char path[FN_REFLEN]; + bool result= 0; + DBUG_ENTER("drop_all_triggers"); + + bzero(&table, sizeof(table)); + init_alloc_root(&table.mem_root, 8192, 0); + + safe_mutex_assert_owner(&LOCK_open); + + if (Table_triggers_list::check_n_load(thd, db, name, &table, 1)) + { + result= 1; + goto end; + } + if (table.triggers) + { + LEX_STRING *trigger; + List_iterator_fast<LEX_STRING> it_name(table.triggers->names_list); + + while ((trigger= it_name++)) + { + if (rm_trigname_file(path, db, trigger->str)) + { + /* + Instead of immediately bailing out with error if we were unable + to remove .TRN file we will try to drop other files. + */ + result= 1; + continue; + } + } + + if (rm_trigger_file(path, db, name)) + { + result= 1; + goto end; + } + } +end: + if (table.triggers) + delete table.triggers; + free_root(&table.mem_root, MYF(0)); + DBUG_RETURN(result); +} diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 044219d5ac9..ede2cb39f0e 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -23,7 +23,7 @@ class Table_triggers_list: public Sql_alloc { /* Triggers as SPs grouped by event, action_time */ - sp_head *bodies[3][2]; + sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX]; /* Copy of TABLE::Field array with field pointers set to TABLE::record[1] buffer instead of TABLE::record[0] (used for OLD values in on UPDATE @@ -60,6 +60,10 @@ public: It have to be public because we are using it directly from parser. */ List<LEX_STRING> definitions_list; + /* + List of sql modes for triggers + */ + List<ulonglong> definition_modes_list; Table_triggers_list(TABLE *table_arg): record1_field(0), table(table_arg) @@ -121,9 +125,14 @@ public: return res; } + bool get_trigger_info(THD *thd, trg_event_type event, + trg_action_time_type time_type, + LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, + ulong *sql_mode); static bool check_n_load(THD *thd, const char *db, const char *table_name, - TABLE *table); + TABLE *table, bool names_only); + static bool drop_all_triggers(THD *thd, char *db, char *table_name); bool has_delete_triggers() { @@ -143,3 +152,6 @@ public: private: bool prepare_record1_accessors(TABLE *table); }; + +extern const LEX_STRING trg_action_time_type_names[]; +extern const LEX_STRING trg_event_type_names[]; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index a60bf80a6d8..8b9c86a0f08 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -691,7 +691,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) view_select= &lex->select_lex; view_select->select_number= ++thd->select_number; { - ulong options= thd->options; + ulong save_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW - MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing + MODE_PIPES_AS_CONCAT affect expression parsing @@ -716,13 +716,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) ? MODE_NO_AUTO_VALUE_ON_ZERO affect UPDATEs + MODE_NO_BACKSLASH_ESCAPES affect expression parsing */ - thd->options&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | - MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES); + thd->variables.sql_mode&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | + MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES); CHARSET_INFO *save_cs= thd->variables.character_set_client; thd->variables.character_set_client= system_charset_info; res= yyparse((void *)thd); thd->variables.character_set_client= save_cs; - thd->options= options; + thd->variables.sql_mode= save_mode; } if (!res && !thd->is_fatal_error) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2397540deae..b680787b9a3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -45,7 +45,7 @@ int yylex(void *yylval, void *yythd); const LEX_STRING null_lex_str={0,0}; -#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if(my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }} +#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if (my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }} #define WARN_DEPRECATED(A,B) \ push_warning_printf(((THD *)yythd), MYSQL_ERROR::WARN_LEVEL_WARN, \ @@ -599,6 +599,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TRAILING %token TRANSACTION_SYM %token TRIGGER_SYM +%token TRIGGERS_SYM %token TRIM %token TRUE_SYM %token TRUNCATE_SYM @@ -1266,7 +1267,7 @@ create: } opt_view_list AS select_init check_option {} - | CREATE TRIGGER_SYM ident trg_action_time trg_event + | CREATE TRIGGER_SYM sp_name trg_action_time trg_event ON table_ident FOR_SYM EACH_SYM ROW_SYM { LEX *lex= Lex; @@ -1285,6 +1286,7 @@ create: sp->m_type= TYPE_ENUM_TRIGGER; lex->sphead= sp; + lex->spname= $3; /* We have to turn of CLIENT_MULTI_QUERIES while parsing a stored procedure, otherwise yylex will chop it into pieces @@ -1295,7 +1297,7 @@ create: bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->m_body_begin= lex->tok_start; + lex->sphead->m_body_begin= lex->ptr; } sp_proc_stmt { @@ -1303,14 +1305,12 @@ create: sp_head *sp= lex->sphead; lex->sql_command= SQLCOM_CREATE_TRIGGER; - sp->init_strings(YYTHD, lex, NULL); + sp->init_strings(YYTHD, lex, $3); /* Restore flag if it was cleared above */ if (sp->m_old_cmq) YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); - lex->ident= $3; - /* We have to do it after parsing trigger body, because some of sp_proc_stmt alternatives are not saving/restoring LEX, so @@ -4026,7 +4026,7 @@ select_into: select_from: FROM join_table_list where_clause group_clause having_clause opt_order_clause opt_limit_clause procedure_clause - | FROM DUAL_SYM opt_limit_clause + | FROM DUAL_SYM where_clause opt_limit_clause /* oracle compatibility: oracle always requires FROM clause, and DUAL is system table without fields. Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ? @@ -4227,9 +4227,25 @@ bool_pri: predicate: bit_expr IN_SYM '(' expr_list ')' - { $4->push_front($1); $$= new Item_func_in(*$4); } + { + if ($4->elements == 1) + $$= new Item_func_eq($1, $4->head()); + else + { + $4->push_front($1); + $$= new Item_func_in(*$4); + } + } | bit_expr not IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); } + { + if ($5->elements == 1) + $$= new Item_func_ne($1, $5->head()); + else + { + $5->push_front($1); + $$= negate_expression(YYTHD, new Item_func_in(*$5)); + } + } | bit_expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | bit_expr not IN_SYM in_subselect @@ -5903,19 +5919,11 @@ drop: lex->sql_command= SQLCOM_DROP_VIEW; lex->drop_if_exists= $3; } - | DROP TRIGGER_SYM ident '.' ident + | DROP TRIGGER_SYM sp_name { LEX *lex= Lex; - lex->sql_command= SQLCOM_DROP_TRIGGER; - /* QQ: Could we loosen lock type in certain cases ? */ - if (!lex->select_lex.add_table_to_list(YYTHD, - new Table_ident($3), - (LEX_STRING*) 0, - TL_OPTION_UPDATING, - TL_WRITE)) - YYABORT; - lex->ident= $5; + lex->spname= $3; } ; @@ -6280,6 +6288,15 @@ show_param: if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES)) YYABORT; } + | opt_full TRIGGERS_SYM opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SELECT; + lex->orig_sql_command= SQLCOM_SHOW_TRIGGERS; + lex->select_lex.db= $3; + if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS)) + YYABORT; + } | TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; @@ -7574,6 +7591,7 @@ keyword_sp: | TEMPTABLE_SYM {} | TEXT_SYM {} | TRANSACTION_SYM {} + | TRIGGERS_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} | TIMESTAMP_DIFF {} diff --git a/sql/table.cc b/sql/table.cc index 220aba27d5b..0324e29abf3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -702,10 +702,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, key_part->key_part_flag|= HA_BIT_PART; if (i == 0 && key != primary_key) - field->flags |= - ((keyinfo->flags & HA_NOSAME) && - field->key_length() == - keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG); + field->flags |= ((keyinfo->flags & HA_NOSAME) && + (keyinfo->key_parts == 1)) ? + UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG; if (i == 0) field->key_start.set_bit(key); if (field->key_length() == key_part->length && @@ -1343,8 +1342,9 @@ void append_unescaped(String *res, const char *pos, uint length) /* Create a .frm file */ -File create_frm(THD *thd, register my_string name, uint reclength, - uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys) +File create_frm(THD *thd, my_string name, const char *db, + const char *table, uint reclength, uchar *fileinfo, + HA_CREATE_INFO *create_info, uint keys) { register File file; ulong length; @@ -1367,7 +1367,7 @@ File create_frm(THD *thd, register my_string name, uint reclength, */ set_if_smaller(create_info->raid_chunks, 255); - if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0) + if ((file= my_create(name, CREATE_MODE, create_flags, MYF(0))) >= 0) { uint key_length, tmp_key_length; uint tmp; @@ -1414,6 +1414,13 @@ File create_frm(THD *thd, register my_string name, uint reclength, } } } + else + { + if (my_errno == ENOENT) + my_error(ER_BAD_DB_ERROR,MYF(0),db); + else + my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno); + } return (file); } /* create_frm */ diff --git a/sql/table.h b/sql/table.h index e5653a1f213..13d44766804 100644 --- a/sql/table.h +++ b/sql/table.h @@ -282,7 +282,7 @@ enum enum_schema_tables SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_PROCEDURES, SCH_STATISTICS, SCH_VIEWS, SCH_USER_PRIVILEGES, SCH_SCHEMA_PRIVILEGES, SCH_TABLE_PRIVILEGES, SCH_COLUMN_PRIVILEGES, SCH_TABLE_CONSTRAINTS, SCH_KEY_COLUMN_USAGE, - SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_VARIABLES + SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_TRIGGERS, SCH_VARIABLES }; diff --git a/sql/unireg.cc b/sql/unireg.cc index 7f170b3ef87..a89d89426a6 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -55,6 +55,8 @@ static bool make_empty_rec(THD *thd, int file, enum db_type table_type, mysql_create_frm() thd Thread handler file_name Name of file (including database and .frm) + db Name of database + table Name of table create_info create info parameters create_fields Fields to create keys number of keys to create @@ -67,6 +69,7 @@ static bool make_empty_rec(THD *thd, int file, enum db_type table_type, */ bool mysql_create_frm(THD *thd, my_string file_name, + const char *db, const char *table, HA_CREATE_INFO *create_info, List<create_field> &create_fields, uint keys, KEY *key_info, @@ -113,7 +116,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, } reclength=uint2korr(forminfo+266); - if ((file=create_frm(thd, file_name, reclength, fileinfo, + if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo, create_info, keys)) < 0) { my_free((gptr) screen_buff,MYF(0)); @@ -211,9 +214,11 @@ err3: Create a frm (table definition) file and the tables SYNOPSIS - mysql_create_frm() + rea_create_table() thd Thread handler file_name Name of file (including database and .frm) + db Name of database + table Name of table create_info create info parameters create_fields Fields to create keys number of keys to create @@ -226,13 +231,14 @@ err3: */ int rea_create_table(THD *thd, my_string file_name, + const char *db, const char *table, HA_CREATE_INFO *create_info, List<create_field> &create_fields, uint keys, KEY *key_info) { DBUG_ENTER("rea_create_table"); - if (mysql_create_frm(thd, file_name, create_info, + if (mysql_create_frm(thd, file_name, db, table, create_info, create_fields, keys, key_info, NULL)) DBUG_RETURN(1); if (!create_info->frm_only && ha_create_table(file_name,create_info,0)) diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 01ecd63d52b..d311859907f 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -401,9 +401,14 @@ static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end=ptr+ptr_length; + const char *end; char *min_org=min_str; char *min_end=min_str+res_length; + uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + + if (charlen < ptr_length) + ptr_length= charlen; + end= ptr + ptr_length; for (; ptr != end && min_str != min_end ; ptr++) { diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c index 58caac15256..2ab103d65ac 100644 --- a/strings/ctype-eucjpms.c +++ b/strings/ctype-eucjpms.c @@ -1584,7 +1584,7 @@ static uint16 tab_uni_jisx02082[]={ /* page 3 0x00F7-0x00F7 */ static uint16 tab_uni_jisx02083[]={ -0x07}; +0x2160}; /* page 4 0x0391-0x03C9 */ static uint16 tab_uni_jisx02084[]={ diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 4150f198722..7caef07202d 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -2714,9 +2714,14 @@ static my_bool my_like_range_gbk(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end=ptr+ptr_length; + const char *end; char *min_org=min_str; char *min_end=min_str+res_length; + uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + + if (charlen < ptr_length) + ptr_length= charlen; + end= ptr + ptr_length; for (; ptr != end && min_str != min_end ; ptr++) { @@ -9933,6 +9938,43 @@ my_mb_wc_gbk(CHARSET_INFO *cs __attribute__((unused)), } +/* + Returns well formed length of a GBK string. +*/ +static +uint my_well_formed_len_gbk(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, + uint pos, int *error) +{ + const char *b0= b; + const char *emb= e - 1; /* Last possible end of an MB character */ + + *error= 0; + while (pos-- && b < e) + { + if ((uchar) b[0] < 128) + { + /* Single byte ascii character */ + b++; + } + else if ((b < emb) && isgbkcode((uchar)*b, (uchar)b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + *error= 1; + break; + } + } + return (uint) (b - b0); +} + + + + static MY_COLLATION_HANDLER my_collation_ci_handler = { NULL, /* init */ @@ -9955,7 +9997,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_gbk, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_gbk, my_lengthsp_8bit, my_numcells_8bit, my_mb_wc_gbk, diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index afe996d3cda..7d54dd47552 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -108,6 +108,13 @@ static uchar sort_order_latin1[] = { - continue to pretend the latin1 character set is ISO 8859-1 - actually allow the storage of euro etc. so it's actually cp1252 + + Also we'll map these five undefined cp1252 character: + 0x81, 0x8D, 0x8F, 0x90, 0x9D + into corresponding control characters: + U+0081, U+008D, U+008F, U+0090, U+009D. + like ISO-8859-1 does. Otherwise, loading "mysqldump" + output doesn't reproduce these undefined characters. */ unsigned short cs_to_uni[256]={ @@ -127,10 +134,10 @@ unsigned short cs_to_uni[256]={ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F, -0x20AC,0x0000,0x201A,0x0192,0x201E,0x2026,0x2020,0x2021, -0x02C6,0x2030,0x0160,0x2039,0x0152,0x0000,0x017D,0x0000, -0x0000,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014, -0x02DC,0x2122,0x0161,0x203A,0x0153,0x0000,0x017E,0x0178, +0x20AC,0x0081,0x201A,0x0192,0x201E,0x2026,0x2020,0x2021, +0x02C6,0x2030,0x0160,0x2039,0x0152,0x008D,0x017D,0x008F, +0x0090,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014, +0x02DC,0x2122,0x0161,0x203A,0x0153,0x009D,0x017E,0x0178, 0x00A0,0x00A1,0x00A2,0x00A3,0x00A4,0x00A5,0x00A6,0x00A7, 0x00A8,0x00A9,0x00AA,0x00AB,0x00AC,0x00AD,0x00AE,0x00AF, 0x00B0,0x00B1,0x00B2,0x00B3,0x00B4,0x00B5,0x00B6,0x00B7, @@ -161,10 +168,10 @@ unsigned char pl00[256]={ 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, 0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x81,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x8D,0x00,0x8F, +0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x9D,0x00,0x00, 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7, diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index fe514186deb..208c38edd30 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1034,9 +1034,15 @@ my_bool my_like_range_simple(CHARSET_INFO *cs, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end=ptr+ptr_length; + const char *end; char *min_org=min_str; char *min_end=min_str+res_length; +#ifdef USE_MB + uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + if (charlen < ptr_length) + ptr_length= charlen; +#endif + end= ptr + ptr_length; for (; ptr != end && min_str != min_end ; ptr++) { @@ -1084,7 +1090,7 @@ ulong my_scan_8bit(CHARSET_INFO *cs, const char *str, const char *end, int sq) if (*str == '.') { for(str++ ; str != end && *str == '0' ; str++); - return (ulong) (str-str0); + return (ulong) (str - str0); } return 0; @@ -1094,7 +1100,7 @@ ulong my_scan_8bit(CHARSET_INFO *cs, const char *str, const char *end, int sq) if (!my_isspace(cs,*str)) break; } - return (ulong) (str-str0); + return (ulong) (str - str0); default: return 0; } @@ -1111,14 +1117,14 @@ void my_fill_8bit(CHARSET_INFO *cs __attribute__((unused)), uint my_numchars_8bit(CHARSET_INFO *cs __attribute__((unused)), const char *b, const char *e) { - return (uint) (e-b); + return (uint) (e - b); } uint my_numcells_8bit(CHARSET_INFO *cs __attribute__((unused)), const char *b, const char *e) { - return (uint) (e-b); + return (uint) (e - b); } diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 161f75ca936..1c12df08b32 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -213,7 +213,7 @@ static int my_strnncoll_sjis_internal(CHARSET_INFO *cs, uint a_char= sjiscode(*a, *(a+1)); uint b_char= sjiscode(*b, *(b+1)); if (a_char != b_char) - return a_char - b_char; + return (int) a_char - (int) b_char; a += 2; b += 2; } else @@ -330,9 +330,14 @@ static my_bool my_like_range_sjis(CHARSET_INFO *cs __attribute__((unused)), uint res_length, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end=ptr+ptr_length; + const char *end; char *min_org=min_str; char *min_end=min_str+res_length; + uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + + if (charlen < ptr_length) + ptr_length= charlen; + end= ptr + ptr_length; while (ptr < end && min_str < min_end) { if (ismbchar_sjis(cs, ptr, end)) { diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index de08c080b3b..2b5f5883abf 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1739,7 +1739,7 @@ int my_wildcmp_unicode(CHARSET_INFO *cs, } wildstr+= scan; - if (w_wc == (my_wc_t)escape) + if (w_wc == (my_wc_t)escape && wildstr < wildend) { if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <= 0) @@ -1811,13 +1811,17 @@ int my_wildcmp_unicode(CHARSET_INFO *cs, if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <=0) return 1; + wildstr+= scan; if (w_wc == (my_wc_t)escape) { - wildstr+= scan; - if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, - (const uchar*)wildend)) <=0) - return 1; + if (wildstr < wildend) + { + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <=0) + return 1; + wildstr+= scan; + } } while (1) @@ -1843,14 +1847,12 @@ int my_wildcmp_unicode(CHARSET_INFO *cs, if (str == str_end) return -1; + str+= scan; result= my_wildcmp_unicode(cs, str, str_end, wildstr, wildend, escape, w_one, w_many, weights); - if (result <= 0) return result; - - str+= scan; } } } diff --git a/strings/decimal.c b/strings/decimal.c index 1d75502f0da..4dc5fa91e0a 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -351,7 +351,8 @@ int decimal2string(decimal_t *from, char *to, int *to_len, buf0=&tmp; } - intg_len= fixed_precision ? fixed_intg : (intg ? intg : 1); + if (!(intg_len= fixed_precision ? fixed_intg : intg)) + intg_len= 1; frac_len= fixed_precision ? fixed_decimals : frac; len= from->sign + intg_len + test(frac) + frac_len; if (fixed_precision) @@ -745,14 +746,17 @@ int decimal_shift(decimal_t *dec, int shift) new_point= ROUND_UP(new_point) - 1; if (new_point > end) + { do { dec->buf[new_point]=0; - }while (--new_point > end); + } while (--new_point > end); + } else + { for (; new_point < beg; new_point++) dec->buf[new_point]= 0; - + } dec->intg= digits_int; dec->frac= digits_frac; return err; diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am index b521d357022..86773f12339 100644 --- a/support-files/MacOSX/Makefile.am +++ b/support-files/MacOSX/Makefile.am @@ -28,12 +28,6 @@ EXTRA_DIST = Info.plist.sh \ StartupItem.Info.plist \ StartupItem.postinstall -pkgdata_DATA = Info.plist \ - Description.plist \ - StartupParameters.plist \ - postinstall \ - preinstall - CLEANFILES = Info.plist \ Description.plist \ StartupParameters.plist \ diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 5f5a10fc1fc..d83dd8ee74d 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -38,8 +38,7 @@ pkgdata_DATA = my-small.cnf \ my-huge.cnf \ my-innodb-heavy-4G.cnf \ mysql-log-rotate \ - mysql-@VERSION@.spec \ - MySQL-shared-compat.spec \ + binary-configure \ ndb-config-2-node.ini pkgdata_SCRIPTS = mysql.server diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 213530a2581..1f2e71277c0 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -349,6 +349,7 @@ BuildMySQL "--disable-shared \ %if %{STATIC_BUILD} --with-mysqld-ldflags='-all-static' \ --with-client-ldflags='-all-static' \ + --with-zlib-dir=bundled \ $USE_OTHER_LIBC_DIR \ %endif --with-comment=\"MySQL Community Edition - Standard (GPL)\" \ diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 557794ab1f6..53708a7a741 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -55,6 +55,7 @@ static char current_db[]= "client_test_db"; static unsigned int test_count= 0; static unsigned int opt_count= 0; static unsigned int iter_count= 0; +static my_bool have_innodb= FALSE; static const char *opt_basedir= "./"; @@ -220,6 +221,28 @@ static void print_st_error(MYSQL_STMT *stmt, const char *msg) } } +/* Check if the connection has InnoDB tables */ + +static my_bool check_have_innodb(MYSQL *conn) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + my_bool result; + + rc= mysql_query(conn, "show variables like 'have_innodb'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= strcmp(row[1], "YES") == 0; + mysql_free_result(res); + return result; +} + /* This is to be what mysql_query() is for mysql_real_query(), for @@ -290,6 +313,7 @@ static void client_connect(ulong flag) strxmov(query, "USE ", current_db, NullS); rc= mysql_query(mysql, query); myquery(rc); + have_innodb= check_have_innodb(mysql); if (!opt_silent) fprintf(stdout, " OK"); @@ -666,13 +690,20 @@ static void verify_col_data(const char *table, const char *col, /* Utility function to verify the field members */ -static void verify_prepare_field(MYSQL_RES *result, - unsigned int no, const char *name, - const char *org_name, - enum enum_field_types type, - const char *table, - const char *org_table, const char *db, - unsigned long length, const char *def) +#define verify_prepare_field(result,no,name,org_name,type,table,\ + org_table,db,length,def) \ + do_verify_prepare_field((result),(no),(name),(org_name),(type), \ + (table),(org_table),(db),(length),(def), \ + __FILE__, __LINE__) + +static void do_verify_prepare_field(MYSQL_RES *result, + unsigned int no, const char *name, + const char *org_name, + enum enum_field_types type, + const char *table, + const char *org_table, const char *db, + unsigned long length, const char *def, + const char *file, int line) { MYSQL_FIELD *field; CHARSET_INFO *cs; @@ -719,8 +750,9 @@ static void verify_prepare_field(MYSQL_RES *result, { if (field->type != type) { - fprintf(stderr, "Expected field type: %d, got type: %d\n", - (int) type, (int) field->type); + fprintf(stderr, + "Expected field type: %d, got type: %d in file %s, line %d\n", + (int) type, (int) field->type, file, line); DIE_UNLESS(field->type == type); } } @@ -1968,7 +2000,7 @@ static void test_fetch_null() myquery(rc); /* fetch */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < (int) array_elements(bind); i++) { bind[i].buffer_type= MYSQL_TYPE_LONG; @@ -3409,7 +3441,7 @@ static void test_bind_result() /* fetch */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *) &nData; /* integer data */ bind[0].is_null= &is_null[0]; @@ -3502,7 +3534,7 @@ static void test_bind_result_ext() rc= mysql_commit(mysql); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < (int) array_elements(bind); i++) { bind[i].length= &length[i]; @@ -3621,7 +3653,7 @@ static void test_bind_result_ext1() rc= mysql_commit(mysql); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void *) t_data; bind[0].buffer_length= sizeof(t_data); @@ -3914,7 +3946,7 @@ static void test_fetch_date() rc= mysql_commit(mysql); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < array_elements(bind); i++) { bind[i].is_null= &is_null[i]; @@ -5631,7 +5663,7 @@ static void test_store_result() myquery(rc); /* fetch */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *) &nData; /* integer data */ bind[0].length= &length; @@ -6345,7 +6377,7 @@ static void test_buffers() bzero(buffer, sizeof(buffer)); /* Avoid overruns in printf() */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].length= &length; bind[0].is_null= &is_null; bind[0].buffer_length= 1; @@ -6534,7 +6566,7 @@ static void test_fetch_nobuffs() fprintf(stdout, "\n total rows : %d", rc); DIE_UNLESS(rc == 1); - bzero(bind, sizeof(MYSQL_BIND)); + bzero((char*) bind, sizeof(MYSQL_BIND)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void *)str[0]; bind[0].buffer_length= sizeof(str[0]); @@ -6604,7 +6636,7 @@ static void test_ushort_bug() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_SHORT; bind[0].buffer= (void *)&short_value; bind[0].is_unsigned= TRUE; @@ -6692,7 +6724,7 @@ static void test_sshort_bug() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_SHORT; bind[0].buffer= (void *)&short_value; bind[0].length= &s_length; @@ -6779,7 +6811,7 @@ static void test_stiny_bug() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_SHORT; bind[0].buffer= (void *)&short_value; bind[0].length= &s_length; @@ -6887,7 +6919,7 @@ static void test_field_misc() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= table_type; bind[0].length= &type_length; @@ -7198,7 +7230,7 @@ static void test_frm_bug() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= data_dir; bind[0].buffer_length= FN_REFLEN; @@ -7402,8 +7434,8 @@ static void test_explain_bug() MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, 0, 0, "", 64, 0); - verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", - MYSQL_TYPE_BLOB, 0, 0, "", 0, 0); + verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB, + 0, 0, "", 0, 0); verify_prepare_field(result, 2, "Null", "IS_NULLABLE", mysql_get_server_version(mysql) <= 50000 ? @@ -7936,7 +7968,7 @@ static void test_fetch_seek() stmt= mysql_simple_prepare(mysql, "select * from t1"); check_stmt(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *)&c1; @@ -8032,7 +8064,7 @@ static void test_fetch_offset() stmt= mysql_simple_prepare(mysql, "select * from t1"); check_stmt(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void *)data; bind[0].buffer_length= 11; @@ -8119,7 +8151,7 @@ static void test_fetch_column() stmt= mysql_simple_prepare(mysql, "select * from t1 order by c2 desc"); check_stmt(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *)&bc1; bind[0].buffer_length= 0; @@ -8367,7 +8399,7 @@ static void test_free_result() stmt= mysql_simple_prepare(mysql, "select * from test_free_result"); check_stmt(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *)&bc1; bind[0].length= &bl1; @@ -8447,7 +8479,7 @@ static void test_free_store_result() stmt= mysql_simple_prepare(mysql, "select * from test_free_result"); check_stmt(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *)&bc1; bind[0].buffer_length= 0; @@ -9908,7 +9940,7 @@ static void test_bug3035() rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); myquery(rc); - bzero(bind_array, sizeof(bind_array)); + bzero((char*) bind_array, sizeof(bind_array)); for (bind= bind_array; bind < bind_end; bind++) bind->error= &bind->error_value; @@ -10117,7 +10149,7 @@ static void test_bug1664() verify_param_count(stmt, 2); - bzero(&bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void *)str_data; @@ -10357,7 +10389,7 @@ static void test_ps_i18n() rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); myquery(rc); - bzero(bind_array, sizeof(bind_array)); + bzero((char*) bind_array, sizeof(bind_array)); bind_array[0].buffer_type= MYSQL_TYPE_STRING; bind_array[0].buffer= (void *) koi8; @@ -10541,7 +10573,7 @@ static void test_bug3796() check_execute(stmt, rc); /* Bind input buffers */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void *) concat_arg0; @@ -10608,11 +10640,11 @@ static void test_bug4026() check_execute(stmt, rc); /* Bind input buffers */ - bzero(bind, sizeof(bind)); - bzero(&time_in, sizeof(time_in)); - bzero(&time_out, sizeof(time_out)); - bzero(&datetime_in, sizeof(datetime_in)); - bzero(&datetime_out, sizeof(datetime_out)); + bzero((char*) bind, sizeof(bind)); + bzero((char*) &time_in, sizeof(time_in)); + bzero((char*) &time_out, sizeof(time_out)); + bzero((char*) &datetime_in, sizeof(datetime_in)); + bzero((char*) &datetime_out, sizeof(datetime_out)); bind[0].buffer_type= MYSQL_TYPE_TIME; bind[0].buffer= (void *) &time_in; @@ -10690,7 +10722,7 @@ static void test_bug4079() check_execute(stmt, rc); /* Bind input buffers */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void *) &res; @@ -10759,13 +10791,13 @@ static void test_bug4030() check_execute(stmt, rc); /* Bind output buffers */ - bzero(bind, sizeof(bind)); - bzero(&time_canonical, sizeof(time_canonical)); - bzero(&time_out, sizeof(time_out)); - bzero(&date_canonical, sizeof(date_canonical)); - bzero(&date_out, sizeof(date_out)); - bzero(&datetime_canonical, sizeof(datetime_canonical)); - bzero(&datetime_out, sizeof(datetime_out)); + bzero((char*) bind, sizeof(bind)); + bzero((char*) &time_canonical, sizeof(time_canonical)); + bzero((char*) &time_out, sizeof(time_out)); + bzero((char*) &date_canonical, sizeof(date_canonical)); + bzero((char*) &date_out, sizeof(date_out)); + bzero((char*) &datetime_canonical, sizeof(datetime_canonical)); + bzero((char*) &datetime_out, sizeof(datetime_out)); bind[0].buffer_type= MYSQL_TYPE_TIME; bind[0].buffer= (void *) &time_out; @@ -10868,7 +10900,7 @@ static void test_view() check_execute(stmt, rc); strmov(str_data, "TEST"); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= FIELD_TYPE_STRING; bind[0].buffer= (char *)&str_data; bind[0].buffer_length= 50; @@ -10987,7 +11019,7 @@ static void test_view_2where() " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS " " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)"); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i=0; i < 8; i++) { strmov(parms[i], "1"); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -11036,7 +11068,7 @@ static void test_view_star() myquery(rc); rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1"); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < 2; i++) { sprintf((char *)&parms[i], "%d", i); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -11102,7 +11134,7 @@ static void test_view_insert() rc= mysql_stmt_prepare(select_stmt, query, strlen(query)); check_execute(select_stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type = FIELD_TYPE_LONG; bind[0].buffer = (char *)&my_val; bind[0].length = &my_length; @@ -11206,7 +11238,7 @@ static void test_view_insert_fields() " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8" " from t1 T0001"); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < 11; i++) { l[i]= 20; @@ -11274,7 +11306,7 @@ static void test_bug5126() check_execute(stmt, rc); /* Bind output buffers */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= &c1; @@ -11320,8 +11352,8 @@ static void test_bug4231() check_execute(stmt, rc); /* Bind input buffers */ - bzero(bind, sizeof(bind)); - bzero(tm, sizeof(tm)); + bzero((char*) bind, sizeof(bind)); + bzero((char*) tm, sizeof(tm)); bind[0].buffer_type= MYSQL_TYPE_DATE; bind[0].buffer= &tm[0]; @@ -11381,7 +11413,7 @@ static void test_bug5399() myheader("test_bug5399"); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= &no; @@ -11541,7 +11573,7 @@ static void test_bug5194() param_str_length= strlen(param_str); /* setup bind array */ - bzero(bind, MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); + bzero((char*) bind, MAX_PARAM_COUNT * sizeof(MYSQL_BIND)); for (i= 0; i < MAX_PARAM_COUNT; ++i) { bind[i].buffer_type= MYSQL_TYPE_FLOAT; @@ -11659,7 +11691,7 @@ static void test_bug6049() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type = MYSQL_TYPE_STRING; bind[0].buffer = &buffer; bind[0].buffer_length = sizeof(buffer); @@ -11708,7 +11740,7 @@ static void test_bug6058() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type = MYSQL_TYPE_STRING; bind[0].buffer = &buffer; bind[0].buffer_length = sizeof(buffer); @@ -11776,7 +11808,7 @@ static void test_bug6046() check_execute(stmt, rc); b= 1; - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer= &b; bind[0].buffer_type= MYSQL_TYPE_SHORT; @@ -11955,7 +11987,7 @@ static void test_bug6096() /* Bind and fetch the data */ - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < stmt_field_count; ++i) { bind[i].buffer_type= MYSQL_TYPE_STRING; @@ -12010,7 +12042,7 @@ static void test_datetime_ranges() check_stmt(stmt); verify_param_count(stmt, 6); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i= 0; i < 6; i++) { bind[i].buffer_type= MYSQL_TYPE_DATETIME; @@ -12141,7 +12173,7 @@ static void test_bug4172() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= f; bind[0].buffer_length= sizeof(f); @@ -12208,7 +12240,7 @@ static void test_conversion() rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer= buff; bind[0].length= &length; bind[0].buffer_type= MYSQL_TYPE_STRING; @@ -12271,7 +12303,7 @@ static void test_rewind(void) rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(&bind,sizeof(MYSQL_BIND)); + bzero((char*) &bind, sizeof(MYSQL_BIND)); bind.buffer_type= MYSQL_TYPE_LONG; bind.buffer= (void *)&Data; /* this buffer won't be altered */ bind.length= &length; @@ -12367,7 +12399,7 @@ static void test_truncation() /*************** Fill in the bind structure and bind it **************/ bind_array= malloc(sizeof(MYSQL_BIND) * bind_count); - bzero(bind_array, sizeof(MYSQL_BIND) * bind_count); + bzero((char*) bind_array, sizeof(MYSQL_BIND) * bind_count); for (bind= bind_array; bind < bind_array + bind_count; bind++) bind->error= &bind->error_value; bind= bind_array; @@ -12572,7 +12604,7 @@ static void test_truncation_option() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(&bind, sizeof(MYSQL_BIND)); + bzero((char*) &bind, sizeof(MYSQL_BIND)); bind.buffer= (void*) &buf; bind.buffer_type= MYSQL_TYPE_TINY; @@ -12647,7 +12679,7 @@ static void test_bug8330() rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); myquery(rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i=0; i < 2; i++) { stmt[i]= mysql_stmt_init(mysql); @@ -12921,7 +12953,7 @@ static void test_bug9520() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (char*) a; bind[0].buffer_length= sizeof(a); @@ -12970,7 +13002,7 @@ static void test_bug9478() stmt= open_cursor("select name from t1 where id=2"); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (char*) a; bind[0].buffer_length= sizeof(a); @@ -13127,7 +13159,7 @@ static void test_bug9643() rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void*) &a; bind[0].buffer_length= sizeof(a); @@ -13183,7 +13215,7 @@ static void test_bug11111() mysql_stmt_prepare(stmt, query, strlen(query)); mysql_stmt_execute(stmt); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); for (i=0; i < 2; i++) { bind[i].buffer_type= MYSQL_TYPE_STRING; @@ -13220,7 +13252,7 @@ static void test_bug10729() int rc; const char *stmt_text; int i= 0; - char *name_array[3]= { "aaa", "bbb", "ccc" }; + const char *name_array[3]= { "aaa", "bbb", "ccc" }; ulong type; myheader("test_bug10729"); @@ -13241,7 +13273,7 @@ static void test_bug10729() rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void*) a; bind[0].buffer_length= sizeof(a); @@ -13351,7 +13383,7 @@ static void test_bug10736() rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void*) a; bind[0].buffer_length= sizeof(a); @@ -13400,7 +13432,7 @@ static void test_bug10794() stmt_text= "insert into t1 (id, name) values (?, ?)"; rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void*) &id_val; bind[1].buffer_type= MYSQL_TYPE_STRING; @@ -13422,7 +13454,7 @@ static void test_bug10794() mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); stmt1= mysql_stmt_init(mysql); mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); - bzero(bind, sizeof(bind)); + bzero((char*) bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].buffer= (void*) a; bind[0].buffer_length= sizeof(a); @@ -13495,9 +13527,9 @@ static void test_bug11172() type= (ulong) CURSOR_TYPE_READ_ONLY; mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); - bzero(bind_in, sizeof(bind_in)); - bzero(bind_out, sizeof(bind_out)); - bzero(&hired, sizeof(hired)); + bzero((char*) bind_in, sizeof(bind_in)); + bzero((char*) bind_out, sizeof(bind_out)); + bzero((char*) &hired, sizeof(hired)); hired.year= 1965; hired.month= 1; hired.day= 1; @@ -13565,9 +13597,9 @@ static void test_bug11656() type= (ulong) CURSOR_TYPE_READ_ONLY; mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); - bzero(bind, sizeof(bind)); - strcpy(buf[0], "pcint502_MY2"); - strcpy(buf[1], "*"); + bzero((char*) bind, sizeof(bind)); + strmov(buf[0], "pcint502_MY2"); + strmov(buf[1], "*"); for (i=0; i < 2; i++) { bind[i].buffer_type= MYSQL_TYPE_STRING; @@ -13749,6 +13781,156 @@ static void test_bug11037() myquery(rc); } +/* Bug#10760: cursors, crash in a fetch after rollback. */ + +static void test_bug10760() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + int rc; + const char *stmt_text; + char id_buf[20]; + ulong id_len; + int i= 0; + ulong type; + + myheader("test_bug10760"); + + mysql_query(mysql, "drop table if exists t1, t2"); + + /* create tables */ + rc= mysql_query(mysql, "create table t1 (id integer not null primary key)" + " engine=MyISAM"); + myquery(rc); + for (; i < 42; ++i) + { + char buf[100]; + sprintf(buf, "insert into t1 (id) values (%d)", i+1); + rc= mysql_query(mysql, buf); + myquery(rc); + } + mysql_autocommit(mysql, FALSE); + /* create statement */ + stmt= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + /* + 1: check that a deadlock within the same connection + is resolved and an error is returned. The deadlock is modelled + as follows: + con1: open cursor for select * from t1; + con1: insert into t1 (id) values (1) + */ + stmt_text= "select id from t1 order by 1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_query(mysql, "update t1 set id=id+100"); + DIE_UNLESS(rc); + if (!opt_silent) + printf("Got error (as expected): %s\n", mysql_error(mysql)); + /* + 2: check that MyISAM tables used in cursors survive + COMMIT/ROLLBACK. + */ + rc= mysql_rollback(mysql); /* should not close the cursor */ + myquery(rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + /* + 3: check that cursors to InnoDB tables are closed (for now) by + COMMIT/ROLLBACK. + */ + if (! have_innodb) + { + if (!opt_silent) + printf("Testing that cursors are closed at COMMIT/ROLLBACK requires " + "InnoDB.\n"); + } + else + { + stmt_text= "select id from t1 order by 1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_query(mysql, "alter table t1 engine=InnoDB"); + myquery(rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) id_buf; + bind[0].buffer_length= sizeof(id_buf); + bind[0].length= &id_len; + check_execute(stmt, rc); + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_execute(stmt); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == 0); + if (!opt_silent) + printf("Fetched row %s\n", id_buf); + rc= mysql_rollback(mysql); /* should close the cursor */ + myquery(rc); +#if 0 + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc); + if (!opt_silent) + printf("Got error (as expected): %s\n", mysql_error(mysql)); +#endif + } + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + mysql_autocommit(mysql, TRUE); /* restore default */ +} + +static void test_bug12001() +{ + MYSQL *mysql_local; + MYSQL_RES *result; + const char *query= "DROP TABLE IF EXISTS test_table;" + "CREATE TABLE test_table(id INT);" + "INSERT INTO test_table VALUES(10);" + "UPDATE test_table SET id=20 WHERE id=10;" + "SELECT * FROM test_table;" + "INSERT INTO non_existent_table VALUES(11);"; + int rc, res; + + myheader("test_bug12001"); + + if (!(mysql_local= mysql_init(NULL))) + { + fprintf(stdout, "\n mysql_init() failed"); + exit(1); + } + + /* Create connection that supports multi statements */ + if (!mysql_real_connect(mysql_local, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS)) { + fprintf(stdout, "\n mysql_real_connect() failed"); + exit(1); + } + + rc= mysql_query(mysql_local, query); + myquery(rc); + + do { + if (mysql_field_count(mysql_local) && (result= mysql_use_result(mysql_local))) { + mysql_free_result(result); + } + } while (!(res= mysql_next_result(mysql_local))); + + rc= mysql_query(mysql_local, "DROP TABLE IF EXISTS test_table"); + myquery(rc); + + mysql_close(mysql_local); + DIE_UNLESS(res==1); +} /* Read and parse arguments and MySQL options from my.cnf @@ -13994,6 +14176,8 @@ static struct my_tests_st my_tests[]= { { "test_bug9735", test_bug9735 }, { "test_bug11183", test_bug11183 }, { "test_bug11037", test_bug11037 }, + { "test_bug10760", test_bug10760 }, + { "test_bug12001", test_bug12001 }, { 0, 0 } }; diff --git a/zlib/inftrees.h b/zlib/inftrees.h index 82d365a7e90..b1104c87e76 100644 --- a/zlib/inftrees.h +++ b/zlib/inftrees.h @@ -1,5 +1,5 @@ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -36,12 +36,12 @@ typedef struct { */ /* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 code structures (850 for length/literals - and 154 for distances, the latter actually the result of an + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an exhaustive search). The true maximum is not known, but the value below is more than safe. */ -#define ENOUGH 1440 -#define MAXD 154 +#define ENOUGH 2048 +#define MAXD 592 /* Type of code to build for inftable() */ typedef enum { |