summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore2
-rwxr-xr-xBUILD/SETUP.sh7
-rwxr-xr-xBUILD/autorun.sh18
-rwxr-xr-xBUILD/compile-pentium-debug-max-no-embedded2
-rw-r--r--VC++Files/client/mysqlclient.dsp4
-rw-r--r--VC++Files/client/mysqlclient_ia64.dsp4
-rw-r--r--VC++Files/libmysql/libmysql.dsp4
-rw-r--r--VC++Files/libmysql/libmysql_ia64.dsp4
-rw-r--r--VC++Files/mysys/mysys.dsp4
-rw-r--r--VC++Files/mysys/mysys_ia64.dsp4
-rw-r--r--client/mysql.cc26
-rw-r--r--client/mysqldump.c13
-rw-r--r--client/mysqltest.c4
-rw-r--r--cmd-line-utils/libedit/read.c2
-rw-r--r--cmd-line-utils/readline/INSTALL2
-rw-r--r--cmd-line-utils/readline/Makefile.am3
-rw-r--r--cmd-line-utils/readline/README2
-rw-r--r--cmd-line-utils/readline/bind.c152
-rw-r--r--cmd-line-utils/readline/callback.c2
-rw-r--r--cmd-line-utils/readline/chardefs.h6
-rw-r--r--cmd-line-utils/readline/compat.c111
-rw-r--r--cmd-line-utils/readline/complete.c300
-rw-r--r--cmd-line-utils/readline/configure.in15
-rw-r--r--cmd-line-utils/readline/display.c234
-rw-r--r--cmd-line-utils/readline/funmap.c1
-rw-r--r--cmd-line-utils/readline/histexpand.c336
-rw-r--r--cmd-line-utils/readline/histfile.c133
-rw-r--r--cmd-line-utils/readline/history.c90
-rw-r--r--cmd-line-utils/readline/history.h28
-rw-r--r--cmd-line-utils/readline/histsearch.c6
-rw-r--r--cmd-line-utils/readline/input.c26
-rw-r--r--cmd-line-utils/readline/isearch.c8
-rw-r--r--cmd-line-utils/readline/keymaps.c13
-rw-r--r--cmd-line-utils/readline/kill.c57
-rw-r--r--cmd-line-utils/readline/macro.c6
-rw-r--r--cmd-line-utils/readline/mbutil.c53
-rw-r--r--cmd-line-utils/readline/misc.c34
-rw-r--r--cmd-line-utils/readline/nls.c37
-rw-r--r--cmd-line-utils/readline/parens.c4
-rw-r--r--cmd-line-utils/readline/posixdir.h10
-rw-r--r--cmd-line-utils/readline/readline.c69
-rw-r--r--cmd-line-utils/readline/readline.h63
-rw-r--r--cmd-line-utils/readline/rldefs.h6
-rw-r--r--cmd-line-utils/readline/rlmbutil.h19
-rw-r--r--cmd-line-utils/readline/rlprivate.h32
-rw-r--r--cmd-line-utils/readline/rlstdc.h2
-rw-r--r--cmd-line-utils/readline/rltty.c153
-rw-r--r--cmd-line-utils/readline/rltty.h32
-rw-r--r--cmd-line-utils/readline/rltypedefs.h8
-rw-r--r--cmd-line-utils/readline/savestring.c38
-rw-r--r--cmd-line-utils/readline/search.c20
-rw-r--r--cmd-line-utils/readline/shell.c4
-rw-r--r--cmd-line-utils/readline/signals.c8
-rw-r--r--cmd-line-utils/readline/terminal.c93
-rw-r--r--cmd-line-utils/readline/text.c67
-rw-r--r--cmd-line-utils/readline/tilde.c4
-rw-r--r--cmd-line-utils/readline/undo.c7
-rw-r--r--cmd-line-utils/readline/util.c8
-rw-r--r--cmd-line-utils/readline/vi_mode.c132
-rw-r--r--configure.in10
-rw-r--r--extra/my_print_defaults.c46
-rw-r--r--extra/replace.c21
-rw-r--r--include/config-win.h3
-rw-r--r--include/my_bitmap.h1
-rw-r--r--include/my_sys.h8
-rw-r--r--include/myisam.h81
-rw-r--r--include/mysql.h2
-rw-r--r--include/thr_lock.h41
-rw-r--r--libmysql/Makefile.shared1
-rw-r--r--libmysql/libmysql.c33
-rw-r--r--libmysql/libmysql.def2
-rw-r--r--libmysqld/libmysqld.def2
-rw-r--r--mysql-test/include/federated.inc21
-rw-r--r--mysql-test/include/federated_cleanup.inc11
-rwxr-xr-xmysql-test/r/ctype_eucjpms.result14
-rw-r--r--mysql-test/r/federated.result618
-rw-r--r--mysql-test/r/func_in.result25
-rw-r--r--mysql-test/r/information_schema.result107
-rw-r--r--mysql-test/r/information_schema_db.result2
-rw-r--r--mysql-test/r/olap.result12
-rw-r--r--mysql-test/r/ps.result25
-rw-r--r--mysql-test/r/range.result24
-rw-r--r--mysql-test/r/rpl_log.result4
-rw-r--r--mysql-test/r/rpl_rotate_logs.result12
-rw-r--r--mysql-test/r/rpl_sp.result4
-rw-r--r--mysql-test/r/select.result39
-rw-r--r--mysql-test/r/sp-security.result24
-rw-r--r--mysql-test/r/sp.result40
-rw-r--r--mysql-test/r/timezone_grant.result7
-rw-r--r--mysql-test/r/trigger.result53
-rw-r--r--mysql-test/r/update.result11
-rw-r--r--mysql-test/r/view.result27
-rw-r--r--mysql-test/t/ctype_eucjpms.test12
-rw-r--r--mysql-test/t/federated.test376
-rw-r--r--mysql-test/t/func_in.test18
-rw-r--r--mysql-test/t/information_schema.test53
-rw-r--r--mysql-test/t/olap.test10
-rw-r--r--mysql-test/t/ps.test17
-rw-r--r--mysql-test/t/range.test23
-rw-r--r--mysql-test/t/rpl_sp.test2
-rw-r--r--mysql-test/t/select.test39
-rw-r--r--mysql-test/t/sp-security.test30
-rw-r--r--mysql-test/t/sp.test39
-rw-r--r--mysql-test/t/timezone_grant.test12
-rw-r--r--mysql-test/t/trigger.test59
-rw-r--r--mysql-test/t/update.test13
-rw-r--r--mysql-test/t/view.test23
-rw-r--r--mysys/Makefile.am3
-rw-r--r--mysys/default.c190
-rw-r--r--mysys/default_modify.c65
-rw-r--r--mysys/my_bitmap.c33
-rw-r--r--mysys/my_tempnam.c173
-rw-r--r--mysys/thr_lock.c184
-rw-r--r--sql-common/client.c44
-rw-r--r--sql/examples/ha_archive.cc12
-rw-r--r--sql/examples/ha_archive.h9
-rw-r--r--sql/examples/ha_example.cc22
-rw-r--r--sql/examples/ha_example.h4
-rw-r--r--sql/examples/ha_tina.cc31
-rw-r--r--sql/examples/ha_tina.h14
-rw-r--r--sql/ha_berkeley.cc14
-rw-r--r--sql/ha_berkeley.h7
-rw-r--r--sql/ha_blackhole.cc28
-rw-r--r--sql/ha_blackhole.h4
-rw-r--r--sql/ha_federated.cc1611
-rw-r--r--sql/ha_federated.h173
-rw-r--r--sql/ha_heap.cc24
-rw-r--r--sql/ha_heap.h3
-rw-r--r--sql/ha_innodb.cc33
-rw-r--r--sql/ha_innodb.h14
-rw-r--r--sql/ha_myisam.cc44
-rw-r--r--sql/ha_myisam.h8
-rw-r--r--sql/ha_myisammrg.cc24
-rw-r--r--sql/ha_myisammrg.h2
-rw-r--r--sql/ha_ndbcluster.cc9
-rw-r--r--sql/handler.cc20
-rw-r--r--sql/handler.h9
-rw-r--r--sql/item.cc59
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_cmpfunc.cc52
-rw-r--r--sql/item_create.cc12
-rw-r--r--sql/item_func.cc68
-rw-r--r--sql/item_func.h25
-rw-r--r--sql/item_strfunc.cc30
-rw-r--r--sql/item_strfunc.h26
-rw-r--r--sql/lex.h1
-rw-r--r--sql/lock.cc19
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/mysql_priv.h11
-rw-r--r--sql/mysqld.cc21
-rw-r--r--sql/opt_range.cc21
-rw-r--r--sql/parse_file.cc2
-rw-r--r--sql/set_var.cc12
-rw-r--r--sql/set_var.h5
-rw-r--r--sql/share/errmsg.txt14
-rw-r--r--sql/sp.cc4
-rw-r--r--sql/sp_head.cc6
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_bitmap.h9
-rw-r--r--sql/sql_cache.cc2
-rw-r--r--sql/sql_class.cc20
-rw-r--r--sql/sql_class.h26
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc18
-rw-r--r--sql/sql_prepare.cc23
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc68
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc118
-rw-r--r--sql/sql_table.cc14
-rw-r--r--sql/sql_trigger.cc367
-rw-r--r--sql/sql_trigger.h11
-rw-r--r--sql/sql_yacc.yy58
-rw-r--r--sql/table.h2
-rw-r--r--storage/myisam/mi_check.c33
-rw-r--r--storage/myisam/mi_create.c2
-rw-r--r--storage/myisam/mi_delete.c2
-rw-r--r--storage/myisam/mi_extra.c4
-rw-r--r--storage/myisam/mi_open.c16
-rw-r--r--storage/myisam/mi_preload.c2
-rw-r--r--storage/myisam/mi_rsame.c2
-rw-r--r--storage/myisam/mi_rsamepos.c2
-rw-r--r--storage/myisam/mi_search.c2
-rw-r--r--storage/myisam/mi_update.c2
-rw-r--r--storage/myisam/mi_write.c15
-rw-r--r--storage/myisam/myisamchk.c16
-rw-r--r--storage/myisam/myisamdef.h4
-rw-r--r--storage/myisam/myisamlog.c2
-rw-r--r--storage/myisam/myisampack.c12
-rw-r--r--storage/myisam/sort.c2
-rw-r--r--storage/ndb/src/common/portlib/NdbMutex.c4
-rw-r--r--storage/ndb/src/common/portlib/NdbThread.c2
-rw-r--r--strings/ctype-eucjpms.c2
-rw-r--r--tests/mysql_client_test.c285
195 files changed, 6588 insertions, 2365 deletions
diff --git a/.bzrignore b/.bzrignore
index 9c6cf2c965c..ca4cade7f09 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1117,3 +1117,5 @@ vio/test-sslclient
vio/test-sslserver
vio/viotest-ssl
ndb/src/dummy.cpp
+innobase/mkinstalldirs
+mkinstalldirs
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index a507d30e518..1603cfadbed 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -48,10 +48,9 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch
c_warnings="$global_warnings -Wunused"
cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor"
-base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-big-tables"
-max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-embedded-server --with-big-tables"
-max_no_es_configs="$max_leave_isam_configs --without-isam"
-max_configs="$max_no_es_configs --with-embedded-server"
+base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine"
+max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-openssl --with-embedded-server --with-big-tables"
+max_configs="$base_max_configs --with-embedded-server"
path=`dirname $0`
. "$path/check-cpu"
diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh
index 8e4ef85657e..82fd1722bd0 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 storage/bdb/dist && sh s_all)
(cd storage/innobase && aclocal && autoheader && aclocal && automake && autoconf)
diff --git a/BUILD/compile-pentium-debug-max-no-embedded b/BUILD/compile-pentium-debug-max-no-embedded
index 803a6a9d6d3..dfdf7d0a5e1 100755
--- a/BUILD/compile-pentium-debug-max-no-embedded
+++ b/BUILD/compile-pentium-debug-max-no-embedded
@@ -6,6 +6,6 @@ path=`dirname $0`
extra_flags="$pentium_cflags $debug_cflags $max_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
-extra_configs="$pentium_configs $debug_configs $max_no_es_configs"
+extra_configs="$pentium_configs $debug_configs $base_max_configs"
. "$path/FINISH.sh"
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..b982b3b281c 100644
--- a/VC++Files/client/mysqlclient_ia64.dsp
+++ b/VC++Files/client/mysqlclient_ia64.dsp
@@ -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/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/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..4186c19db4d 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -1212,7 +1212,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 +1272,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))
{
@@ -1391,7 +1391,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 +2782,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 +2819,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;
}
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, &quote_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 a519bd2228c..684e6331c27 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
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
@@ -13,7 +13,7 @@ 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
@@ -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/replace.c b/extra/replace.c
index d92355359d3..0b7d9600232 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,25 @@ 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];
+ File temp_file;
DBUG_ENTER("convert_file");
if (!(in=my_fopen(name,O_RDONLY,MYF(MY_WME))))
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 ((temp_file= create_temp_file(tempname, dir_buff, "PR", O_WRONLY,
+ MYF(MY_WME))) < 0)
+ {
+ my_fclose(in,MYF(0));
+ DBUG_RETURN(1);
+ }
+ if (!(out= my_fdopen(temp_file, tempname, O_WRONLY, MYF(MY_WME))))
{
- (*free)(tempname);
my_fclose(in,MYF(0));
DBUG_RETURN(1);
}
@@ -1076,7 +1078,6 @@ my_string name;
my_redel(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-win.h b/include/config-win.h
index 2559b3b74fd..6e0740497b0 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -353,6 +353,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 e0cc929bce6..98dd49a1228 100644
--- a/include/my_bitmap.h
+++ b/include/my_bitmap.h
@@ -53,6 +53,7 @@ extern uint bitmap_get_first(const MY_BITMAP *map);
extern uint bitmap_get_first_set(const MY_BITMAP *map);
extern uint bitmap_bits_set(const MY_BITMAP *map);
extern void bitmap_free(MY_BITMAP *map);
+extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit);
extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size);
extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2);
extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2);
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/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/mysql.h b/include/mysql.h
index daa29f70e16..2ba41e6d367 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -396,7 +396,7 @@ unsigned int STDCALL mysql_warning_count(MYSQL *mysql);
const char * STDCALL mysql_info(MYSQL *mysql);
unsigned long STDCALL mysql_thread_id(MYSQL *mysql);
const char * STDCALL mysql_character_set_name(MYSQL *mysql);
-int STDCALL mysql_set_character_set(MYSQL *mysql, char *csname);
+int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname);
MYSQL * STDCALL mysql_init(MYSQL *mysql);
my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
diff --git a/include/thr_lock.h b/include/thr_lock.h
index dc4f9968cb7..8c6540d83e2 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,13 +130,18 @@ 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);
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 097983cbbd3..f9ddf7fa665 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1511,39 +1511,6 @@ void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo)
csinfo->dir = charsets_dir;
}
-int STDCALL mysql_set_character_set(MYSQL *mysql, char *cs_name)
-{
- struct charset_info_st *cs;
- const char *save_csdir= charsets_dir;
-
- if (mysql->options.charset_dir)
- charsets_dir= mysql->options.charset_dir;
-
- if ((cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
- {
- char buff[MY_CS_NAME_SIZE + 10];
- charsets_dir= save_csdir;
- sprintf(buff, "SET NAMES %s", cs_name);
- if (!mysql_query(mysql, buff))
- {
- mysql->charset= cs;
- }
- }
- else
- {
- char cs_dir_name[FN_REFLEN];
- get_charsets_dir(cs_dir_name);
- mysql->net.last_errno= CR_CANT_READ_CHARSET;
- strmov(mysql->net.sqlstate, unknown_sqlstate);
- my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
- ER(mysql->net.last_errno), cs_name, cs_dir_name);
-
- }
- charsets_dir= save_csdir;
- return mysql->net.last_errno;
-}
-
-
uint STDCALL mysql_thread_safe(void)
{
#ifdef THREAD
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
index 0688ea5732b..a469c67c466 100644
--- a/libmysql/libmysql.def
+++ b/libmysql/libmysql.def
@@ -150,5 +150,5 @@ EXPORTS
mysql_server_end
mysql_set_character_set
mysql_get_character_set_info
- get_defaults_files
+ get_defaults_options
modify_defaults_file
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/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/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/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_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/information_schema.result b/mysql-test/r/information_schema.result
index 98f3d59485f..01abd791881 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
@@ -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
@@ -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,8 @@ 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
select table_name, column_name, data_type from information_schema.columns
where data_type = 'datetime';
table_name column_name data_type
@@ -709,6 +721,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 +768,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
+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
+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 +917,26 @@ 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;
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/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.result b/mysql-test/r/ps.result
index 81d85306e93..0050dfc0841 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -775,3 +775,28 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
select ? from t1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1
drop table t1;
+prepare stmt from "select @@time_zone";
+execute stmt;
+@@time_zone
+SYSTEM
+set @@time_zone:='Japan';
+execute stmt;
+@@time_zone
+Japan
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+set transaction isolation level read committed;
+execute stmt;
+@@tx_isolation
+READ-COMMITTED
+set transaction isolation level serializable;
+execute stmt;
+@@tx_isolation
+SERIALIZABLE
+set @@tx_isolation=default;
+execute stmt;
+@@tx_isolation
+REPEATABLE-READ
+deallocate prepare stmt;
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index 6f9b4e41b22..e8e30b3653a 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -744,3 +744,27 @@ a b
1 3
DROP VIEW v1;
DROP TABLE t1;
+CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name));
+INSERT INTO t1 VALUES ('Betty'), ('Anna');
+SELECT * FROM t1;
+name
+Anna
+Betty
+DELETE FROM t1 WHERE name NOT LIKE 'A%a';
+SELECT * FROM t1;
+name
+Anna
+DROP TABLE t1;
+CREATE TABLE t1 (a int, KEY idx(a));
+INSERT INTO t1 VALUES (NULL), (1), (2), (3);
+SELECT * FROM t1;
+a
+NULL
+1
+2
+3
+DELETE FROM t1 WHERE NOT(a <=> 2);
+SELECT * FROM t1;
+a
+2
+DROP TABLE t1;
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 d0503d1b83b..2a38c5fc86f 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2746,3 +2746,42 @@ WHERE
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 * FROM t1;
+a b c
+50 3 3
+DROP TABLE t1;
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index 3a0d2aa5f36..184978e4a0d 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -212,3 +212,27 @@ REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop function bug_9503;
use test;
drop database mysqltest;
+use test;
+select current_user();
+current_user()
+root@localhost
+select user();
+user()
+root@localhost
+create procedure bug7291_0 () sql security invoker select current_user(), user();
+create procedure bug7291_1 () sql security definer call bug7291_0();
+create procedure bug7291_2 () sql security invoker call bug7291_0();
+grant execute on procedure bug7291_0 to user1@localhost;
+grant execute on procedure bug7291_1 to user1@localhost;
+grant execute on procedure bug7291_2 to user1@localhost;
+call bug7291_2();
+current_user() user()
+user1@localhost user1@localhost
+call bug7291_1();
+current_user() user()
+root@localhost user1@localhost
+drop procedure bug7291_1;
+drop procedure bug7291_2;
+drop procedure bug7291_0;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop user user1@localhost;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 345de49c21d..fd63204e32f 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -2657,16 +2657,22 @@ end|
call avg ()|
drop procedure avg|
drop procedure if exists bug6129|
-set @@sql_mode = 'traditional'|
-create procedure bug6129(mode text)
-select @@sql_mode = mode|
-call bug6129(@@sql_mode)|
-@@sql_mode = mode
-1
-set @@sql_mode = ''|
-call bug6129(@@sql_mode)|
-@@sql_mode = mode
-0
+set @old_mode= @@sql_mode;
+set @@sql_mode= "";
+create procedure bug6129()
+select @@sql_mode|
+call bug6129()|
+@@sql_mode
+
+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
+set @@sql_mode= "NO_ZERO_IN_DATE"|
+call bug6129()|
+@@sql_mode
+NO_ZERO_IN_DATE
+set @@sql_mode=@old_mode;
drop procedure bug6129|
drop procedure if exists bug9856|
create procedure bug9856()
@@ -3079,4 +3085,18 @@ one 1
delete from t1|
drop procedure bug9565_sub|
drop procedure bug9565|
+drop procedure if exists bug9538|
+create procedure bug9538()
+set @@sort_buffer_size = 1000000|
+set @x = @@sort_buffer_size|
+set @@sort_buffer_size = 2000000|
+select @@sort_buffer_size|
+@@sort_buffer_size
+2000000
+call bug9538()|
+select @@sort_buffer_size|
+@@sort_buffer_size
+1000000
+set @@sort_buffer_size = @x|
+drop procedure bug9538|
drop table t1,t2;
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..7e3a6fa65d4 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,5 @@ 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;
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/view.result b/mysql-test/r/view.result
index 684c4950acd..624fae4d728 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);
@@ -1831,6 +1831,31 @@ select * from v1;
t
01:00
drop view v1;
+create table t1 (a timestamp default now());
+create table t2 (b timestamp default now());
+create view v1 as select a,b,t1.a < now() from t1,t2 where t1.a < now();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a`,`test`.`t2`.`b` AS `b`,(`test`.`t1`.`a` < now()) AS `t1.a < now()` from (`test`.`t1` join `test`.`t2`) where (`test`.`t1`.`a` < now())
+drop view v1;
+drop table t1, t2;
+CREATE TABLE t1 ( a varchar(50) );
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = CURRENT_USER();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = current_user())
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = VERSION();
+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` = version())
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = DATABASE();
+SHOW CREATE VIEW v1;
+View Create View
+v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select sql_no_cache `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = database())
+DROP VIEW v1;
+DROP TABLE t1;
CREATE TABLE t1 (col1 time);
CREATE TABLE t2 (col1 time);
CREATE VIEW v1 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1;
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/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/func_in.test b/mysql-test/t/func_in.test
index 6e0883b821f..3a6b6653098 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -101,3 +101,21 @@ 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;
+
+#
+# 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/information_schema.test b/mysql-test/t/information_schema.test
index 7c0624b67fd..f13a29f07ad 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,19 @@ 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;
diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test
index 26fcc7463d6..f3017978588 100644
--- a/mysql-test/t/olap.test
+++ b/mysql-test/t/olap.test
@@ -266,3 +266,13 @@ 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;
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index e8ea1dc373b..de92c67518e 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -811,3 +811,20 @@ select ??;
select ? from t1;
--enable_ps_protocol
drop table t1;
+#
+# Bug#9359 "Prepared statements take snapshot of system vars at PREPARE
+# time"
+#
+prepare stmt from "select @@time_zone";
+execute stmt;
+set @@time_zone:='Japan';
+execute stmt;
+prepare stmt from "select @@tx_isolation";
+execute stmt;
+set transaction isolation level read committed;
+execute stmt;
+set transaction isolation level serializable;
+execute stmt;
+set @@tx_isolation=default;
+execute stmt;
+deallocate prepare stmt;
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index 3d2285b1633..065cef659b8 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -553,3 +553,26 @@ SELECT a,b FROM v1 WHERE a < 2 and b=3;
DROP VIEW v1;
DROP TABLE t1;
+
+#
+# Bug #11853: DELETE statement with a NOT (LIKE/<=>) where condition
+# for an indexed attribute
+#
+
+CREATE TABLE t1 (name varchar(15) NOT NULL, KEY idx(name));
+INSERT INTO t1 VALUES ('Betty'), ('Anna');
+
+SELECT * FROM t1;
+DELETE FROM t1 WHERE name NOT LIKE 'A%a';
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+CREATE TABLE t1 (a int, KEY idx(a));
+INSERT INTO t1 VALUES (NULL), (1), (2), (3);
+
+SELECT * FROM t1;
+DELETE FROM t1 WHERE NOT(a <=> 2);
+SELECT * FROM t1;
+
+DROP TABLE t1;
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/select.test b/mysql-test/t/select.test
index 712658a19a6..90f42f3896e 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -2330,3 +2330,42 @@ WHERE
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 * FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index 3dc6b9d07ab..15fcba5ebe9 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -341,3 +341,33 @@ REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop function bug_9503;
use test;
drop database mysqltest;
+
+#
+# correct value from current_user() in function run from "security definer"
+# (BUG#7291)
+#
+connection con1root;
+use test;
+
+select current_user();
+select user();
+create procedure bug7291_0 () sql security invoker select current_user(), user();
+create procedure bug7291_1 () sql security definer call bug7291_0();
+create procedure bug7291_2 () sql security invoker call bug7291_0();
+grant execute on procedure bug7291_0 to user1@localhost;
+grant execute on procedure bug7291_1 to user1@localhost;
+grant execute on procedure bug7291_2 to user1@localhost;
+
+connect (user1,localhost,user1,,);
+connection user1;
+
+call bug7291_2();
+call bug7291_1();
+
+connection con1root;
+drop procedure bug7291_1;
+drop procedure bug7291_2;
+drop procedure bug7291_0;
+disconnect user1;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
+drop user user1@localhost;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 13de2090a84..d9e6163cbc7 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -3377,15 +3377,16 @@ drop procedure avg|
--disable_warnings
drop procedure if exists bug6129|
--enable_warnings
-set @@sql_mode = 'traditional'|
-create procedure bug6129(mode text)
- select @@sql_mode = mode|
-
-# 1
-call bug6129(@@sql_mode)|
-set @@sql_mode = ''|
-# 0
-call bug6129(@@sql_mode)|
+set @old_mode= @@sql_mode;
+set @@sql_mode= "";
+create procedure bug6129()
+ select @@sql_mode|
+call bug6129()|
+set @@sql_mode= "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO"|
+call bug6129()|
+set @@sql_mode= "NO_ZERO_IN_DATE"|
+call bug6129()|
+set @@sql_mode=@old_mode;
drop procedure bug6129|
@@ -3856,6 +3857,26 @@ drop procedure bug9565|
#
+# BUG#9538: SProc: Creation fails if we try to SET system variable
+# using @@var_name in proc
+#
+--disable_warnings
+drop procedure if exists bug9538|
+--enable_warnings
+create procedure bug9538()
+ set @@sort_buffer_size = 1000000|
+
+set @x = @@sort_buffer_size|
+set @@sort_buffer_size = 2000000|
+select @@sort_buffer_size|
+call bug9538()|
+select @@sort_buffer_size|
+set @@sort_buffer_size = @x|
+
+drop procedure bug9538|
+
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/timezone_grant.test b/mysql-test/t/timezone_grant.test
index f586ba0c5fe..5dbf457e1f1 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\_%';
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 8a27636ed84..f6b3c714d28 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,5 @@ 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;
diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test
index 21789a550b9..66b3a2886b6 100644
--- a/mysql-test/t/update.test
+++ b/mysql-test/t/update.test
@@ -201,3 +201,16 @@ 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;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 8eeac41efcd..449bca63f0d 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;
@@ -1674,6 +1674,27 @@ select * from v1;
drop view v1;
#
+# evaluation constant functions in WHERE (BUG#4663)
+#
+create table t1 (a timestamp default now());
+create table t2 (b timestamp default now());
+create view v1 as select a,b,t1.a < now() from t1,t2 where t1.a < now();
+SHOW CREATE VIEW v1;
+drop view v1;
+drop table t1, t2;
+CREATE TABLE t1 ( a varchar(50) );
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = CURRENT_USER();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = VERSION();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+CREATE VIEW v1 AS SELECT * FROM t1 WHERE a = DATABASE();
+SHOW CREATE VIEW v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+#
# checking views after some view with error (BUG#11337)
#
CREATE TABLE t1 (col1 time);
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index ad075f3324a..6b983dc38dd 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 trie.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/default.c b/mysys/default.c
index 15c92e816a6..6b78d031291 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\
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 b5f928fee1e..ec03e345109 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -202,6 +202,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)
@@ -327,10 +328,40 @@ 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)
{
uint32 *to= map->bitmap, *from= map2->bitmap, *end;
-
DBUG_ASSERT(map->bitmap && map2->bitmap &&
map->n_bits==map2->n_bits);
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..b12f8234c26 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,16 @@ 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 timeval now;
+ 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 +403,56 @@ 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)
+ {
+ gettimeofday(&now, 0);
+ wait_timeout.tv_sec= now.tv_sec + table_lock_wait_timeout;
+ wait_timeout.tv_nsec= now.tv_usec * 1000;
+ }
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 +469,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 +504,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 +526,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 +546,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 +560,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 +594,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 +603,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 +626,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 +662,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 +724,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 +742,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 +802,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 +910,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 +921,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 +979,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 +1002,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 +1022,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 */
}
@@ -985,10 +1056,11 @@ void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t 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. */
pthread_cond_signal(data->cond);
data->cond= 0; /* Removed from list */
@@ -1000,7 +1072,7 @@ 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;
@@ -1117,7 +1189,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 +1323,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 +1342,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/sql-common/client.c b/sql-common/client.c
index c736acae857..4ecc8d26fc7 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -2206,7 +2206,8 @@ 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->client_flag | CLIENT_REMEMBER_OPTIONS) ||
+ mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
{
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
@@ -2778,8 +2779,49 @@ uint STDCALL mysql_errno(MYSQL *mysql)
return mysql->net.last_errno;
}
+
const char * STDCALL mysql_error(MYSQL *mysql)
{
return mysql->net.last_error;
}
+/*
+ mysql_set_character_set function sends SET NAMES cs_name to
+ the server (which changes character_set_client, character_set_result
+ and character_set_connection) and updates mysql->charset so other
+ functions like mysql_real_escape will work correctly.
+*/
+int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
+{
+ struct charset_info_st *cs;
+ const char *save_csdir= charsets_dir;
+
+ if (mysql->options.charset_dir)
+ charsets_dir= mysql->options.charset_dir;
+
+ if (strlen(cs_name) < MY_CS_NAME_SIZE &&
+ (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
+ {
+ char buff[MY_CS_NAME_SIZE + 10];
+ charsets_dir= save_csdir;
+ sprintf(buff, "SET NAMES %s", cs_name);
+ if (!mysql_real_query(mysql, buff, strlen(buff)))
+ {
+ mysql->charset= cs;
+ }
+ }
+ else
+ {
+ char cs_dir_name[FN_REFLEN];
+ get_charsets_dir(cs_dir_name);
+ mysql->net.last_errno= CR_CANT_READ_CHARSET;
+ strmov(mysql->net.sqlstate, unknown_sqlstate);
+ my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
+ ER(mysql->net.last_errno), cs_name, cs_dir_name);
+
+ }
+ charsets_dir= save_csdir;
+ return mysql->net.last_errno;
+}
+
+
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index c362985f565..e5c35ae019d 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -149,7 +149,8 @@ static handlerton archive_hton = {
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
- 0 /* rollback_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
};
@@ -208,6 +209,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..2818c176cd3 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -72,6 +72,24 @@
#ifdef HAVE_EXAMPLE_DB
#include "ha_example.h"
+
+static handlerton example_hton= {
+ "CSV",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ 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 +197,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 8680d683a2f..50fec4e2883 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -54,6 +54,23 @@ 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. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
/*****************************************************************************
** TINA tables
*****************************************************************************/
@@ -229,6 +246,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/ha_berkeley.cc b/sql/ha_berkeley.cc
index 6b283079072..3b9cdbe29f7 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -120,7 +120,8 @@ static handlerton berkeley_hton = {
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
- NULL /* rollback_by_xid */
+ NULL, /* rollback_by_xid */
+ HTON_CLOSE_CURSORS_AT_COMMIT
};
typedef struct st_berkeley_trx_data {
@@ -372,6 +373,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 596a59b4d43..9c0668b967c 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..856a053db9e 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -24,6 +24,34 @@
#include "ha_blackhole.h"
+/* Blackhole storage engine handlerton */
+
+static handlerton myisam_hton= {
+ "BLACKHOLE",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ 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 1cec6faea04..63454bf88ed 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,51 @@ 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. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ 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,24 +731,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_DUMP("record", record, table->s->reclength);
+ 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 +854,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 +866,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
-bool ha_federated::create_where_from_key(String *to, KEY *key_info,
- const byte *key, uint key_length)
+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
+
+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);
+ 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);
- res= field->val_str(&str, (char*) (key));
+ 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 +1272,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 +1321,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 +1343,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 +1359,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 +1377,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 +1424,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 +1433,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 +1441,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 +1472,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,61 +1543,71 @@ inline uint field_in_record_is_null(TABLE *table,
int ha_federated::write_row(byte *buf)
{
- uint x, num_fields;
+ bool has_fields= FALSE;
+ 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;
- char insert_buffer[IO_SIZE];
- char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE];
-
/* 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)
table->timestamp_field->set_time();
- /* 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);
+
/*
loop through the field pointer array, add any fields to both the values
list and the fields list that is part of the write set
+
+ You might ask "Why an index variable (has_fields) ?" My answer is that
+ we need to count how many fields we actually need
*/
- for (num_fields= 0, field= table->field; *field; field++)
+ for (field= table->field; *field; field++)
{
/* if there is a query id and if it's equal to the current query id */
if (ha_get_bit_in_write_set((*field)->fieldnr))
{
- 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 field is_null", num_fields-1));
- insert_field_value_string.append("NULL");
- }
+ insert_field_value_string.append(FEDERATED_NULL);
else
{
- DBUG_PRINT("info", ("column %d field is not null", num_fields-1));
(*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);
@@ -1149,34 +1617,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);
@@ -1185,8 +1654,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);
@@ -1212,39 +1742,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
@@ -1256,104 +1804,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
@@ -1369,49 +1886,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);
}
@@ -1425,12 +1953,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);
}
@@ -1444,17 +1972,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");
@@ -1463,10 +1997,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",
@@ -1478,42 +2016,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, bool sorted)
{
+ int error;
DBUG_ENTER("ha_federated::index_init");
DBUG_PRINT("info",
("table: '%s' key: %d", table->s->table_name, keynr));
@@ -1521,14 +2067,90 @@ int ha_federated::index_init(uint keynr, bool sorted)
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.
@@ -1544,12 +2166,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
@@ -1584,40 +2209,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)
@@ -1639,10 +2272,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),
@@ -1653,12 +2287,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);
}
@@ -1705,13 +2340,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(&current_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);
}
@@ -1760,12 +2397,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;
}
@@ -1786,22 +2502,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);
}
@@ -1849,7 +2573,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;
/*
@@ -1879,28 +2603,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 5908fe5afba..ecaa59d1268 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, bool sorted);
- 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..92a5fe0ea09 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -23,9 +23,33 @@
#include <myisampack.h>
#include "ha_heap.h"
+static handlerton heap_hton= {
+ "MEMORY",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ 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 1dfc64c9137..3f86399aacd 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -215,7 +215,14 @@ 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 */
+ /*
+ For now when one opens a cursor, MySQL does not create an own
+ InnoDB consistent read view for it, and uses the view of the
+ currently active transaction. Therefore, cursors can not
+ survive COMMIT or ROLLBACK statements, which free this view.
+ */
+ HTON_CLOSE_CURSORS_AT_COMMIT
};
/*********************************************************************
@@ -765,6 +772,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
@@ -5486,7 +5511,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 */
}
@@ -5524,7 +5549,7 @@ ha_innobase::update_table_comment(
if (str) {
char* pos = str + length;
- if(length) {
+ if (length) {
memcpy(str, comment, length);
*pos++ = ';';
*pos++ = ' ';
@@ -5582,7 +5607,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;
}
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 150eae63730..acfe8b950eb 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
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 27023ba4c64..2595a1cca26 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -44,6 +44,29 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
** MyISAM tables
*****************************************************************************/
+/* MyISAM handlerton */
+
+static handlerton myisam_hton= {
+ "MyISAM",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ /*
+ 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 +146,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 +636,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, 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 +937,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 +1036,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 +1290,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 &param, 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 794f1c62dd7..ae17b60b7e1 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -32,6 +32,30 @@
** MyISAM MERGE tables
*****************************************************************************/
+/* MyISAM MERGE handlerton */
+
+static handlerton myisammrg_hton= {
+ "MRG_MyISAM",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ 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 1f830342b73..c3882436149 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -63,7 +63,8 @@ static handlerton ndbcluster_hton = {
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
- NULL /* rollback_by_xid */
+ NULL, /* rollback_by_xid */
+ HTON_NO_FLAGS
};
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
@@ -4091,7 +4092,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),
@@ -5372,7 +5373,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;
@@ -5400,7 +5401,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);
diff --git a/sql/handler.cc b/sql/handler.cc
index 512363f71d7..c2a138e7013 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -217,19 +217,11 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
#ifndef NO_HASH
case DB_TYPE_HASH:
file= new ha_hash(table);
-#endif
-#ifdef HAVE_ISAM
- case DB_TYPE_MRG_ISAM:
- file= new ha_isammrg(table);
break;
- case DB_TYPE_ISAM:
- file= new ha_isam(table);
- break;
-#else
+#endif
case DB_TYPE_MRG_ISAM:
file= new ha_myisammrg(table);
break;
-#endif
#ifdef HAVE_BERKELEY_DB
case DB_TYPE_BERKELEY_DB:
file= new ha_berkeley(table);
@@ -697,6 +689,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++)
@@ -798,6 +795,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;
@@ -2602,6 +2603,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 d06ae062fb3..39da4f65272 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -355,8 +355,13 @@ typedef struct
int (*recover)(XID *xid_list, uint len);
int (*commit_by_xid)(XID *xid);
int (*rollback_by_xid)(XID *xid);
+ 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[] */
@@ -683,6 +688,7 @@ class handler :public Sql_alloc
private:
virtual int reset() { return extra(HA_EXTRA_RESET); }
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 */
@@ -726,7 +732,8 @@ public:
MY_BITMAP *read_set;
MY_BITMAP *write_set;
- 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/item.cc b/sql/item.cc
index c04d7c346d1..593708688f1 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -638,6 +638,38 @@ Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
}
+Item *Item_static_int_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ char buf[64];
+ String *s, tmp(buf, sizeof(buf), &my_charset_bin);
+ s= val_str(&tmp);
+ if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
+ s->charset())))
+ {
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ }
+ return conv;
+}
+
+
+Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ char buf[64];
+ String *s, tmp(buf, sizeof(buf), &my_charset_bin);
+ s= val_str(&tmp);
+ if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
+ s->charset())))
+ {
+ conv->str_value.copy();
+ conv->str_value.mark_as_const();
+ }
+ return conv;
+}
+
+
Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
@@ -663,6 +695,33 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
}
+Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs)
+{
+ Item_string *conv;
+ uint conv_errors;
+ String tmp, cstr, *ostr= val_str(&tmp);
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
+ if (conv_errors ||
+ !(conv= new Item_static_string_func(func_name,
+ cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
+ {
+ /*
+ Safe conversion is not possible (or EOM).
+ We could not convert a string into the requested character set
+ without data loss. The target charset does not cover all the
+ characters from the string. Operation cannot be done correctly.
+ */
+ return NULL;
+ }
+ conv->str_value.copy();
+ /* Ensure that no one is going to change the result string */
+ conv->str_value.mark_as_const();
+ return conv;
+}
+
+
bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (type() == item->type() && item->basic_const_item())
diff --git a/sql/item.h b/sql/item.h
index a10934e40fb..5a1cf193806 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1132,6 +1132,7 @@ public:
Item_static_int_func(const char *str_arg, longlong i, uint length)
:Item_int(NullS, i, length), func_name(str_arg)
{}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
};
@@ -1242,6 +1243,7 @@ public:
:Item_float(NullS, val_arg, decimal_par, length), func_name(str)
{}
void print(String *str) { str->append(func_name); }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -1314,6 +1316,7 @@ public:
Derivation dv= DERIVATION_COERCIBLE)
:Item_string(NullS, str, length, cs, dv), func_name(name_par)
{}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
};
@@ -1778,7 +1781,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
};
/*
@@ -1786,7 +1789,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_cmpfunc.cc b/sql/item_cmpfunc.cc
index 5ed857319be..d430d0d3c23 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -237,32 +237,35 @@ void Item_bool_func2::fix_length_and_dec()
set_cmp_func();
return;
}
-
- Item *real_item= args[0]->real_item();
- if (real_item->type() == FIELD_ITEM)
+
+ if (!thd->is_context_analysis_only())
{
- Field *field= ((Item_field*) real_item)->field;
- if (field->can_be_compared_as_longlong())
+ Item *real_item= args[0]->real_item();
+ if (real_item->type() == FIELD_ITEM)
{
- if (convert_constant_item(thd, field,&args[1]))
+ Field *field=((Item_field*) real_item)->field;
+ if (field->can_be_compared_as_longlong())
{
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- return;
+ if (convert_constant_item(thd, field,&args[1]))
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
+ return;
+ }
}
}
- }
- real_item= args[1]->real_item();
- if (real_item->type() == FIELD_ITEM)
- {
- Field *field= ((Item_field*) real_item)->field;
- if (field->can_be_compared_as_longlong())
+ real_item= args[1]->real_item();
+ if (real_item->type() == FIELD_ITEM /* && !real_item->const_item() */)
{
- if (convert_constant_item(thd, field,&args[0]))
+ Field *field=((Item_field*) real_item)->field;
+ if (field->can_be_compared_as_longlong())
{
- cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
- INT_RESULT); // Works for all types.
- return;
+ if (convert_constant_item(thd, field,&args[0]))
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
+ return;
+ }
}
}
}
@@ -990,7 +993,8 @@ void Item_func_between::fix_length_and_dec()
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
- if (field->can_be_compared_as_longlong())
+ if (!thd->is_context_analysis_only() &&
+ field->can_be_compared_as_longlong())
{
/*
The following can't be recoded with || as convert_constant_item
@@ -2180,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_create.cc b/sql/item_create.cc
index b9073a6c0b3..b7d8d50f9b3 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -299,16 +299,8 @@ Item *create_func_pow(Item* a, Item *b)
Item *create_func_current_user()
{
- THD *thd=current_thd;
- char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
- uint length;
-
- thd->lex->safe_to_cache_query= 0;
- length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) -
- buff);
- return new Item_static_string_func("current_user()",
- thd->memdup(buff, length), length,
- system_charset_info);
+ current_thd->lex->safe_to_cache_query= 0;
+ return new Item_func_user(TRUE);
}
Item *create_func_radians(Item *a)
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0817282b673..c3bdb11418f 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4217,6 +4217,36 @@ void Item_user_var_as_out_param::print(String *str)
}
+Item_func_get_system_var::
+Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+ LEX_STRING *component_arg, const char *name_arg,
+ size_t name_len_arg)
+ :var(var_arg), var_type(var_type_arg), component(*component_arg)
+{
+ /* set_name() will allocate the name */
+ set_name(name_arg, name_len_arg, system_charset_info);
+}
+
+
+bool
+Item_func_get_system_var::fix_fields(THD *thd, Item **ref)
+{
+ Item *item= var->item(thd, var_type, &component);
+ 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)
+ DBUG_RETURN(1); // Impossible
+ item->set_name(name, 0, system_charset_info); // don't allocate a new name
+ thd->change_item_tree(ref, item);
+
+ DBUG_RETURN(0);
+}
+
+
longlong Item_func_inet_aton::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -4563,22 +4593,21 @@ longlong Item_func_bit_xor::val_int()
0 error
# constant item
*/
-
+
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component)
{
+ sys_var *var;
+ char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
+ LEX_STRING *base_name, *component_name;
+
if (component.str == 0 &&
!my_strcasecmp(system_charset_info, name.str, "VERSION"))
return new Item_string("@@VERSION", server_version,
(uint) strlen(server_version),
system_charset_info, DERIVATION_SYSCONST);
- Item *item;
- sys_var *var;
- char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos;
- LEX_STRING *base_name, *component_name;
-
if (component.str)
{
base_name= &component;
@@ -4600,9 +4629,8 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
return 0;
}
}
- if (!(item=var->item(thd, var_type, component_name)))
- return 0; // Impossible
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+
buff[0]='@';
buff[1]='@';
pos=buff+2;
@@ -4623,28 +4651,8 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
memcpy(pos, base_name->str, base_name->length);
pos+= base_name->length;
- // set_name() will allocate the name
- item->set_name(buff,(uint) (pos-buff), system_charset_info);
- return item;
-}
-
-
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
- uint length, const char *item_name)
-{
- Item *item;
- sys_var *var;
- LEX_STRING null_lex_string;
-
- null_lex_string.str= 0;
-
- var= find_sys_var(var_name, length);
- DBUG_ASSERT(var != 0);
- if (!(item=var->item(thd, var_type, &null_lex_string)))
- return 0; // Impossible
- thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- item->set_name(item_name, 0, system_charset_info); // Will use original name
- return item;
+ return new Item_func_get_system_var(var, var_type, component_name,
+ buff, pos - buff);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 3ca37b1961f..43a85e6aa0b 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1199,6 +1199,31 @@ public:
};
+/* A system variable */
+
+class Item_func_get_system_var :public Item_func
+{
+ sys_var *var;
+ enum_var_type var_type;
+ LEX_STRING component;
+public:
+ Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
+ LEX_STRING *component_arg, const char *name_arg,
+ size_t name_len_arg);
+ bool fix_fields(THD *thd, Item **ref);
+ /*
+ Stubs for pure virtual methods. Should never be called: this
+ item is always substituted with a constant in fix_fields().
+ */
+ double val_real() { DBUG_ASSERT(0); return 0.0; }
+ longlong val_int() { DBUG_ASSERT(0); return 0; }
+ String* val_str(String*) { DBUG_ASSERT(0); return 0; }
+ void fix_length_and_dec() { DBUG_ASSERT(0); }
+ /* TODO: fix to support views */
+ const char *func_name() const { return "get_system_var"; }
+};
+
+
class Item_func_inet_aton : public Item_int_func
{
public:
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2fd0f25e699..6d519c73b13 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1552,9 +1552,11 @@ Item *Item_func_sysconst::safe_charset_converter(CHARSET_INFO *tocs)
uint conv_errors;
String tmp, cstr, *ostr= val_str(&tmp);
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
+ if (conv_errors ||
+ !(conv= new Item_static_string_func(fully_qualified_func_name(),
+ cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
{
return NULL;
}
@@ -1584,13 +1586,24 @@ String *Item_func_user::val_str(String *str)
DBUG_ASSERT(fixed == 1);
THD *thd=current_thd;
CHARSET_INFO *cs= system_charset_info;
- const char *host= thd->host_or_ip;
+ const char *host, *user;
uint res_length;
+ if (is_current)
+ {
+ user= thd->priv_user;
+ host= thd->priv_host;
+ }
+ else
+ {
+ user= thd->user;
+ host= thd->host_or_ip;
+ }
+
// For system threads (e.g. replication SQL thread) user may be empty
- if (!thd->user)
+ if (!user)
return &my_empty_string;
- res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
+ res_length= (strlen(user)+strlen(host)+2) * cs->mbmaxlen;
if (str->alloc(res_length))
{
@@ -1598,12 +1611,13 @@ String *Item_func_user::val_str(String *str)
return 0;
}
res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",
- thd->user, host);
+ user, host);
str->length(res_length);
str->set_charset(cs);
return str;
}
+
void Item_func_soundex::fix_length_and_dec()
{
collation.set(args[0]->collation);
@@ -2104,7 +2118,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)))
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index d85210984d9..fa098849a43 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -357,8 +357,15 @@ public:
Item_func_sysconst()
{ collation.set(system_charset_info,DERIVATION_SYSCONST); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
+ /*
+ Used to create correct Item name in new converted item in
+ safe_charset_converter, return string representation of this function
+ call
+ */
+ virtual const char *fully_qualified_func_name() const = 0;
};
+
class Item_func_database :public Item_func_sysconst
{
public:
@@ -370,18 +377,27 @@ public:
maybe_null=1;
}
const char *func_name() const { return "database"; }
+ const char *fully_qualified_func_name() const { return "database()"; }
};
+
class Item_func_user :public Item_func_sysconst
{
+ bool is_current;
+
public:
- Item_func_user() :Item_func_sysconst() {}
+ Item_func_user(bool is_current_arg)
+ :Item_func_sysconst(), is_current(is_current_arg) {}
String *val_str(String *);
- void fix_length_and_dec()
- {
- max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen;
+ void fix_length_and_dec()
+ {
+ max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
+ system_charset_info->mbmaxlen);
}
- const char *func_name() const { return "user"; }
+ const char *func_name() const
+ { return is_current ? "current_user" : "user"; }
+ const char *fully_qualified_func_name() const
+ { return is_current ? "current_user()" : "user()"; }
};
diff --git a/sql/lex.h b/sql/lex.h
index 59ba6a8e15b..c0e91527f45 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -510,6 +510,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 a666c6da17a..dff863ccf56 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -103,6 +103,10 @@ 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 */
+ const static int thr_lock_errno_to_mysql[]=
+ { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
DBUG_ENTER("mysql_lock_tables");
for (;;)
@@ -135,15 +139,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))
{
diff --git a/sql/log.cc b/sql/log.cc
index 7d7ba90509d..1ef522588ff 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2652,7 +2652,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 1519cfb6630..9b30989278e 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -243,7 +243,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;
}
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 91287a8bd40..933b2f8efad 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -475,6 +475,11 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "protocol.h"
#include "sql_udf.h"
class user_var_entry;
+enum enum_var_type
+{
+ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
+};
+class sys_var;
#include "item.h"
extern my_decimal decimal_zero;
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
@@ -1093,6 +1098,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;
@@ -1345,12 +1351,9 @@ extern bool sql_cache_init();
extern void sql_cache_free();
extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
-/* item.cc */
+/* item_func.cc */
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component);
-Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
- uint length, const char *item_name);
-/* item_func.cc */
int get_var_with_binlog(THD *thd, LEX_STRING &name,
user_var_entry **out_entry);
/* log.cc */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 80670f2a445..412d6175e10 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -686,7 +686,13 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
- tmp->killed= THD::KILL_CONNECTION;
+ /*
+ Re: bug 7403 - close_connection will be called mulitple times
+ a wholesale clean up of our network code is a very large project.
+ This will wake up the socket on Windows and prevent the printing of
+ the error message that we are force closing a connection.
+ */
+ close_connection(tmp, 0, 0);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -883,7 +889,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__ */
@@ -4343,7 +4349,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
};
@@ -5606,6 +5613,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,
@@ -5739,6 +5751,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},
@@ -7073,4 +7086,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 c3e73632c6f..25fcdfc51fd 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();
@@ -993,7 +993,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);
@@ -3536,7 +3536,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
if (arg->type() != Item::FUNC_ITEM)
DBUG_RETURN(0);
cond_func= (Item_func*) arg;
- if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
+ if (cond_func->functype() != Item_func::BETWEEN &&
+ cond_func->functype() != Item_func::IN_FUNC)
DBUG_RETURN(0);
inv= TRUE;
}
@@ -6947,7 +6948,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])
{
@@ -7273,7 +7274,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);
}
@@ -7355,7 +7356,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);
}
@@ -7886,19 +7887,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
@@ -7972,7 +7973,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..abca8736916 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -728,7 +728,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':
diff --git a/sql/set_var.cc b/sql/set_var.cc
index eb6cdfa37d0..f1ac90ea113 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,
@@ -973,6 +976,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
@@ -1653,15 +1657,7 @@ err:
/*
Return an Item for a variable. Used with @@[global.]variable_name
-
If type is not given, return local value if exists, else global
-
- We have to use netprintf() instead of my_error() here as this is
- called on the parsing stage.
-
- TODO:
- With prepared statements/stored procedures this has to be fixed
- to create an item that gets the current value at fix_fields() stage.
*/
Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
diff --git a/sql/set_var.h b/sql/set_var.h
index a6532323b34..a7e680cc7fa 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -30,11 +30,6 @@ class set_var;
typedef struct system_variables SV;
extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
-enum enum_var_type
-{
- OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
-};
-
typedef int (*sys_check_func)(THD *, set_var *);
typedef bool (*sys_update_func)(THD *, set_var *);
typedef void (*sys_after_update_func)(THD *,enum_var_type);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 466f1049dc5..b3784b6421d 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5370,6 +5370,20 @@ 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_PARTITION_REQUIRES_VALUES_ERROR
eng "%s PARTITIONING requires definition of VALUES %s for each partition"
swe "%s PARTITIONering kräver definition av VALUES %s för varje partition"
diff --git a/sql/sp.cc b/sql/sp.cc
index cf381762bac..0c9af895fb6 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1442,8 +1442,8 @@ 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,
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 272456d8c8e..02c006d01ee 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1023,6 +1023,7 @@ sp_head::reset_lex(THD *thd)
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
+ my_lex_states state= oldlex->next_state; // Keep original next_state
(void)m_lex.push_front(oldlex);
thd->lex= sublex= new st_lex;
@@ -1030,6 +1031,11 @@ sp_head::reset_lex(THD *thd)
/* Reset most stuff. The length arguments doesn't matter here. */
lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
+ /*
+ * next_state is normally the same (0), but it happens that we swap lex in
+ * "mid-sentence", so we must restore it.
+ */
+ sublex->next_state= state;
/* We must reset ptr and end_of_query again */
sublex->ptr= oldlex->ptr;
sublex->end_of_query= oldlex->end_of_query;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 5d6dd29b998..eed7d749b2c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1740,7 +1740,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;
/*
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index 00f38895fd6..b2994da71f7 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -51,6 +51,14 @@ public:
bitmap_init(&map2, (uint32 *)&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 cbee80a8695..e70ab38ee43 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -2051,7 +2051,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 37bfd1656a8..283ae96eebc 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -757,7 +757,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 */
@@ -841,6 +841,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();
};
@@ -892,15 +894,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);
@@ -908,6 +920,7 @@ public:
private:
HASH st_hash;
HASH names_hash;
+ I_List<Statement> transient_cursor_list;
Statement *last_found_statement;
};
@@ -1025,8 +1038,7 @@ public:
a thread/connection descriptor
*/
-class THD :public ilink,
- public Statement,
+class THD :public Statement,
public Open_tables_state
{
public:
@@ -1052,6 +1064,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;
@@ -1475,6 +1491,8 @@ public:
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
}
void set_status_var_init();
+ bool is_context_analysis_only()
+ { return current_arena->is_stmt_prepare() || lex->view_prepare_mode; }
bool push_open_tables_state();
void pop_open_tables_state();
};
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index edcf4db09a4..ec982703116 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -58,6 +58,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 e0c5338a952..58af959888e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2108,6 +2108,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 */
@@ -2155,7 +2156,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;
@@ -2308,7 +2309,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
@@ -2389,10 +2391,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,
@@ -6847,7 +6851,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 b4293ef7836..9ec2cff71a1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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);
@@ -2016,6 +2020,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 +2070,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
{
@@ -2074,6 +2082,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
}
thd->set_statement(&stmt_backup);
+ thd->lock_id= &thd->main_lock_id;
thd->current_arena= thd;
DBUG_VOID_RETURN;
@@ -2244,10 +2253,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 +2298,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;
@@ -2474,6 +2477,8 @@ void Prepared_statement::close_cursor()
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
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index dbefbb34b4a..d376423e990 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1527,7 +1527,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 c54efe531ad..45460d0da01 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1194,7 +1194,7 @@ JOIN::exec()
{
result->send_fields(fields_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
- if (!having || having->val_int())
+ if (cond_value != Item::COND_FALSE && (!having || having->val_int()))
{
if (do_send_rows && (procedure ? (procedure->send_row(fields_list) ||
procedure->end_of_records())
@@ -1714,10 +1714,12 @@ 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);
}
@@ -1751,6 +1753,21 @@ 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 */
+ for (TABLE *table= open_tables; table; table= table->next)
+ {
+ const handlerton *ht= table->file->ht;
+ if (ht)
+ close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
+ else
+ {
+ close_at_commit= TRUE; /* handler status is unknown */
+ break;
+ }
+ }
/*
XXX: thd->locked_tables is not changed.
What problems can we have with it if cursor is open?
@@ -1919,6 +1936,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();
@@ -2846,11 +2864,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);
}
@@ -5150,7 +5168,23 @@ inline void add_cond_and_fix(Item **e1, Item *e2)
(where othertbl is a non-const table and othertbl.field may be NULL)
and add them to conditions on correspoding tables (othertbl in this
example).
-
+
+ Exception from that is the case when referred_tab->join != join.
+ I.e. don't add NOT NULL constraints from any embedded subquery.
+ Consider this query:
+ 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;
+ Here condition A.f3 IS NOT NULL is going to be added to the WHERE
+ condition of the embedding query.
+ Another example:
+ SELECT * FROM t10, t11 WHERE (t10.a < 10 OR t10.a IS NULL)
+ AND t11.b <=> t10.b AND (t11.a = (SELECT MAX(a) FROM t12
+ WHERE t12.b = t10.a ));
+ Here condition t10.a IS NOT NULL is going to be added.
+ In both cases addition of NOT NULL condition will erroneously reject
+ some rows of the result set.
+ referred_tab->join != join constraint would disallow such additions.
+
This optimization doesn't affect the choices that ref, range, or join
optimizer make. This was intentional because this was added after 4.1
was GA.
@@ -5181,6 +5215,13 @@ static void add_not_null_conds(JOIN *join)
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;
+ /*
+ 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;
@@ -6712,7 +6753,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)
@@ -7521,7 +7562,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)
@@ -12134,7 +12175,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++))
@@ -12171,12 +12211,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;
@@ -13005,7 +13045,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);
@@ -13075,7 +13115,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)
@@ -13195,7 +13235,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 ec424c48366..2b2557de180 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -393,6 +393,8 @@ class Cursor: public Sql_alloc, public Query_arena
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 e786b70114d..d56c14e2836 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
@@ -1718,6 +1719,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;
@@ -1740,7 +1742,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;
@@ -2399,6 +2401,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];
@@ -2477,12 +2480,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();
}
@@ -2510,6 +2515,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:
{
@@ -2985,6 +3001,73 @@ 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)
+{
+ CHARSET_INFO *cs= system_charset_info;
+ 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);
+ 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;
+ if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
+ (enum trg_action_time_type)timing,
+ &trigger_name, &trigger_stmt))
+ 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))
+ 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)
@@ -3869,6 +3952,29 @@ 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"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
ST_FIELD_INFO variables_fields_info[]=
{
{"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
@@ -3919,6 +4025,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 21348908bf3..7d0691455a0 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>
@@ -291,16 +293,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;
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index fd79fc8b878..a7aee95197e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -39,6 +39,45 @@ static File_option triggers_file_parameters[]=
/*
+ 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 +108,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);
@@ -174,28 +217,28 @@ 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;
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 +277,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
@@ -246,13 +308,66 @@ 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;
+ goto err_with_cleanup;
trg_def->str= thd->query;
trg_def->length= thd->query_length;
- 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 0;
+
+err_with_cleanup:
+ my_delete(trigname_path, MYF(MY_WME));
+ return 1;
+}
+
+
+/*
+ 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 +390,13 @@ 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);
+ char path[FN_REFLEN];
while ((name= it_name++))
{
it_def++;
- if (my_strcasecmp(system_charset_info, lex->ident.str,
+ if (my_strcasecmp(system_charset_info, lex->spname->m_name.str,
name->str) == 0)
{
/*
@@ -291,18 +407,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
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 +429,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 +448,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,13 +506,16 @@ 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;
@@ -451,7 +571,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
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);
@@ -471,32 +591,20 @@ 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;
}
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
@@ -537,3 +645,160 @@ 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
+
+ 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)
+{
+ sp_head *body;
+ DBUG_ENTER("get_trigger_info");
+ if ((body= bodies[event][time_type]))
+ {
+ *trigger_name= body->m_name;
+ *trigger_stmt= body->m_body;
+ 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..e751741fa34 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
@@ -121,9 +121,13 @@ 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);
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 +147,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_yacc.yy b/sql/sql_yacc.yy
index e4259197292..d4cd2bd6600 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, \
@@ -610,6 +610,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
@@ -1277,7 +1278,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;
@@ -1296,6 +1297,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
@@ -1306,7 +1308,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
{
@@ -1314,14 +1316,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
@@ -4455,7 +4455,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" ?
@@ -4656,9 +4656,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
@@ -5235,7 +5251,7 @@ simple_expr:
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
+ { $$= new Item_func_user(FALSE); Lex->safe_to_cache_query=0; }
| UTC_DATE_SYM optional_braces
{ $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
| UTC_TIME_SYM optional_braces
@@ -6332,19 +6348,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;
}
;
@@ -6709,6 +6717,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;
@@ -8012,6 +8029,7 @@ keyword_sp:
| TEXT_SYM {}
| THAN_SYM {}
| TRANSACTION_SYM {}
+ | TRIGGERS_SYM {}
| TIMESTAMP {}
| TIMESTAMP_ADD {}
| TIMESTAMP_DIFF {}
diff --git a/sql/table.h b/sql/table.h
index 6ba9453b2f0..8c0040b0fa4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -289,7 +289,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/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index 9e003a18dac..1db829808a9 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/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/storage/myisam/mi_create.c b/storage/myisam/mi_create.c
index 33b344405ec..560535f2933 100644
--- a/storage/myisam/mi_create.c
+++ b/storage/myisam/mi_create.c
@@ -508,7 +508,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/storage/myisam/mi_delete.c b/storage/myisam/mi_delete.c
index cc4a17182f7..60a07254e82 100644
--- a/storage/myisam/mi_delete.c
+++ b/storage/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/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c
index ba32bb9115a..bfe1748af01 100644
--- a/storage/myisam/mi_extra.c
+++ b/storage/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/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index 74b97a65609..82663e0c318 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/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/storage/myisam/mi_preload.c b/storage/myisam/mi_preload.c
index 317ab4ad7fe..d63399b519d 100644
--- a/storage/myisam/mi_preload.c
+++ b/storage/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/storage/myisam/mi_rsame.c b/storage/myisam/mi_rsame.c
index 56c8d1226ca..321097744b9 100644
--- a/storage/myisam/mi_rsame.c
+++ b/storage/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/storage/myisam/mi_rsamepos.c b/storage/myisam/mi_rsamepos.c
index a1d96fb7104..35cdd41e297 100644
--- a/storage/myisam/mi_rsamepos.c
+++ b/storage/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/storage/myisam/mi_search.c b/storage/myisam/mi_search.c
index c669a8be8f8..ed61bbfe41a 100644
--- a/storage/myisam/mi_search.c
+++ b/storage/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/storage/myisam/mi_update.c b/storage/myisam/mi_update.c
index cda60694008..ab23f2e6da9 100644
--- a/storage/myisam/mi_update.c
+++ b/storage/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/storage/myisam/mi_write.c b/storage/myisam/mi_write.c
index dd062b79769..c8f9aa84a41 100644
--- a/storage/myisam/mi_write.c
+++ b/storage/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/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c
index 519e123e9da..4856d93b320 100644
--- a/storage/myisam/myisamchk.c
+++ b/storage/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/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index 5688b377d3d..74463ec065a 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/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/storage/myisam/myisamlog.c b/storage/myisam/myisamlog.c
index dc98d813266..de55b86252c 100644
--- a/storage/myisam/myisamlog.c
+++ b/storage/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/storage/myisam/myisampack.c b/storage/myisam/myisampack.c
index daf2bbdf85c..ba48cbf1b62 100644
--- a/storage/myisam/myisampack.c
+++ b/storage/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/storage/myisam/sort.c b/storage/myisam/sort.c
index 9d2af2e8c70..f2f8c8ef7ec 100644
--- a/storage/myisam/sort.c
+++ b/storage/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/storage/ndb/src/common/portlib/NdbMutex.c b/storage/ndb/src/common/portlib/NdbMutex.c
index 18f8548e4e6..4a170d87e5c 100644
--- a/storage/ndb/src/common/portlib/NdbMutex.c
+++ b/storage/ndb/src/common/portlib/NdbMutex.c
@@ -23,9 +23,9 @@
NdbMutex* NdbMutex_Create(void)
{
- DBUG_ENTER("NdbMutex_Create");
NdbMutex* pNdbMutex;
int result;
+ DBUG_ENTER("NdbMutex_Create");
pNdbMutex = (NdbMutex*)NdbMem_Allocate(sizeof(NdbMutex));
DBUG_PRINT("info",("NdbMem_Allocate 0x%lx",pNdbMutex));
@@ -42,8 +42,8 @@ NdbMutex* NdbMutex_Create(void)
int NdbMutex_Destroy(NdbMutex* p_mutex)
{
- DBUG_ENTER("NdbMutex_Destroy");
int result;
+ DBUG_ENTER("NdbMutex_Destroy");
if (p_mutex == NULL)
DBUG_RETURN(-1);
diff --git a/storage/ndb/src/common/portlib/NdbThread.c b/storage/ndb/src/common/portlib/NdbThread.c
index cee4ec018a0..55ebc4c8111 100644
--- a/storage/ndb/src/common/portlib/NdbThread.c
+++ b/storage/ndb/src/common/portlib/NdbThread.c
@@ -71,10 +71,10 @@ struct NdbThread* NdbThread_Create(NDB_THREAD_FUNC *p_thread_func,
const char* p_thread_name,
NDB_THREAD_PRIO thread_prio)
{
- DBUG_ENTER("NdbThread_Create");
struct NdbThread* tmpThread;
int result;
pthread_attr_t thread_attr;
+ DBUG_ENTER("NdbThread_Create");
(void)thread_prio; /* remove warning for unused parameter */
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/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 010f467c4ad..ffd99915168 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");
@@ -1968,7 +1992,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 +3433,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 +3526,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 +3645,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 +3938,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 +5655,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 +6369,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 +6558,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 +6628,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 +6716,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 +6803,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 +6911,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 +7222,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;
@@ -7936,7 +7960,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 +8056,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 +8143,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 +8391,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 +8471,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 +9932,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 +10141,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 +10381,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 +10565,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 +10632,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 +10714,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 +10783,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 +10892,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 +11011,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 +11060,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 +11126,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 +11230,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 +11298,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 +11344,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 +11405,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 +11565,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 +11683,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 +11732,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 +11800,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 +11979,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 +12034,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 +12165,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 +12232,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 +12295,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 +12391,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 +12596,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 +12671,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 +12945,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 +12994,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 +13151,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 +13207,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 +13244,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 +13265,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 +13375,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 +13424,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 +13446,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 +13519,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 +13589,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;
@@ -13617,12 +13641,12 @@ static void test_bug10214()
static void test_client_character_set()
{
MY_CHARSET_INFO cs;
- char *csname;
+ char *csname= (char*) "utf8";
+ char *csdefault= (char*)mysql_character_set_name(mysql);
int rc;
myheader("test_client_character_set");
- csname= (char*) "utf8";
rc= mysql_set_character_set(mysql, csname);
DIE_UNLESS(rc == 0);
@@ -13630,7 +13654,7 @@ static void test_client_character_set()
DIE_UNLESS(!strcmp(cs.csname, "utf8"));
DIE_UNLESS(!strcmp(cs.name, "utf8_general_ci"));
/* Restore the default character set */
- rc= mysql_query(mysql, "set names default");
+ rc= mysql_set_character_set(mysql, csdefault);
myquery(rc);
}
@@ -13732,16 +13756,16 @@ static void test_bug11037()
fprintf(stdout, "Got error, as expected:\n [%d] %s\n",
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
- rc = mysql_stmt_execute(stmt);
+ rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
- rc = mysql_stmt_fetch(stmt);
+ rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc==0);
- rc = mysql_stmt_fetch(stmt);
+ rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc==MYSQL_NO_DATA);
- rc = mysql_stmt_fetch(stmt);
+ rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc==MYSQL_NO_DATA);
mysql_stmt_close(stmt);
@@ -13749,6 +13773,110 @@ 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);
+ rc= mysql_stmt_fetch(stmt);
+ DIE_UNLESS(rc);
+ if (!opt_silent)
+ printf("Got error (as expected): %s\n", mysql_error(mysql));
+ }
+
+ mysql_stmt_close(stmt);
+ rc= mysql_query(mysql, "drop table t1");
+ myquery(rc);
+ mysql_autocommit(mysql, TRUE); /* restore default */
+}
/*
Read and parse arguments and MySQL options from my.cnf
@@ -13994,6 +14122,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug9735", test_bug9735 },
{ "test_bug11183", test_bug11183 },
{ "test_bug11037", test_bug11037 },
+ { "test_bug10760", test_bug10760 },
{ 0, 0 }
};