summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/SETUP.sh4
-rw-r--r--BUILD/compile-pentium64-valgrind-max2
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--config/ac-macros/misc.m423
-rw-r--r--config/ac-macros/openssl.m43
-rw-r--r--include/config-win.h2
-rw-r--r--include/my_global.h3
-rw-r--r--include/my_sys.h2
-rw-r--r--include/violite.h20
-rw-r--r--innobase/btr/btr0cur.c36
-rw-r--r--innobase/dict/dict0crea.c43
-rw-r--r--innobase/include/dict0crea.h7
-rw-r--r--innobase/include/page0cur.h7
-rw-r--r--innobase/include/page0page.h2
-rw-r--r--innobase/include/page0page.ic15
-rw-r--r--innobase/include/rem0rec.h9
-rw-r--r--innobase/include/srv0srv.h6
-rw-r--r--innobase/log/log0log.c26
-rw-r--r--innobase/log/log0recv.c2
-rw-r--r--innobase/page/page0cur.c17
-rw-r--r--innobase/page/page0page.c29
-rw-r--r--innobase/rem/rem0rec.c31
-rw-r--r--innobase/row/row0mysql.c27
-rw-r--r--innobase/row/row0sel.c2
-rw-r--r--innobase/srv/srv0srv.c18
-rw-r--r--innobase/srv/srv0start.c18
-rw-r--r--innobase/sync/sync0sync.c4
-rw-r--r--innobase/trx/trx0roll.c12
-rw-r--r--innobase/trx/trx0trx.c45
-rw-r--r--innobase/trx/trx0undo.c14
-rw-r--r--innobase/ut/ut0mem.c36
-rw-r--r--libmysql/libmysql.c19
-rw-r--r--myisam/mi_create.c29
-rw-r--r--myisam/mi_open.c2
-rw-r--r--myisam/myisamdef.h1
-rw-r--r--myisammrg/myrg_create.c2
-rw-r--r--mysql-test/Makefile.am5
-rw-r--r--mysql-test/include/have_cp1250_ch.inc4
-rw-r--r--mysql-test/r/bigint.result39
-rw-r--r--mysql-test/r/ctype_collate.result4
-rw-r--r--mysql-test/r/ctype_cp1250_ch.result9
-rw-r--r--mysql-test/r/ctype_cp1251.result16
-rw-r--r--mysql-test/r/drop_temp_table.result1
-rw-r--r--mysql-test/r/federated.result507
-rw-r--r--mysql-test/r/func_group.result51
-rw-r--r--mysql-test/r/func_str.result62
-rw-r--r--mysql-test/r/func_system.result8
-rw-r--r--mysql-test/r/grant2.result17
-rw-r--r--mysql-test/r/have_cp1250_ch.require2
-rw-r--r--mysql-test/r/information_schema.result52
-rw-r--r--mysql-test/r/innodb.result8
-rw-r--r--mysql-test/r/lock.result2
-rw-r--r--mysql-test/r/mix_innodb_myisam_binlog.result1
-rw-r--r--mysql-test/r/myisam.result18
-rw-r--r--mysql-test/r/mysqldump.result22
-rw-r--r--mysql-test/r/ps.result39
-rw-r--r--mysql-test/r/rpl000001.result19
-rw-r--r--mysql-test/r/rpl_change_master.result18
-rw-r--r--mysql-test/r/rpl_deadlock.result81
-rw-r--r--mysql-test/r/select_found.result25
-rw-r--r--mysql-test/r/select_safe.result15
-rw-r--r--mysql-test/r/show_check.result2
-rw-r--r--mysql-test/r/sp.result302
-rw-r--r--mysql-test/r/symlink.result12
-rw-r--r--mysql-test/r/type_blob.result2
-rw-r--r--mysql-test/r/type_newdecimal.result10
-rw-r--r--mysql-test/t/bigint.test33
-rw-r--r--mysql-test/t/ctype_cp1250_ch.test12
-rw-r--r--mysql-test/t/ctype_cp1251.test14
-rw-r--r--mysql-test/t/federated.disabled1
-rw-r--r--mysql-test/t/federated.test588
-rw-r--r--mysql-test/t/func_group.test42
-rw-r--r--mysql-test/t/func_system.test9
-rw-r--r--mysql-test/t/grant2.test15
-rw-r--r--mysql-test/t/information_schema.test46
-rw-r--r--mysql-test/t/innodb.test2
-rw-r--r--mysql-test/t/lock.test2
-rw-r--r--mysql-test/t/myisam.test26
-rw-r--r--mysql-test/t/mysqldump.test10
-rw-r--r--mysql-test/t/ps.test43
-rw-r--r--mysql-test/t/rpl000001.test23
-rw-r--r--mysql-test/t/rpl_change_master.test19
-rw-r--r--mysql-test/t/rpl_deadlock-slave.opt1
-rw-r--r--mysql-test/t/rpl_deadlock.test107
-rw-r--r--mysql-test/t/rpl_get_lock.test7
-rw-r--r--mysql-test/t/select_found.test15
-rw-r--r--mysql-test/t/select_safe.test20
-rw-r--r--mysql-test/t/sp.test391
-rw-r--r--mysql-test/t/symlink.test17
-rw-r--r--mysql-test/t/type_newdecimal.test2
-rw-r--r--mysys/mf_tempfile.c8
-rw-r--r--mysys/my_mmap.c9
-rw-r--r--mysys/my_symlink2.c7
-rw-r--r--ndb/src/kernel/blocks/dbdict/Dbdict.cpp2
-rw-r--r--ndb/src/kernel/blocks/dbtc/DbtcMain.cpp14
-rw-r--r--ndb/test/ndbapi/Makefile.am4
-rw-r--r--ndb/test/ndbapi/testNodeRestart.cpp71
-rw-r--r--ndb/test/run-test/daily-devel-tests.txt4
-rw-r--r--scripts/mysqlhotcopy.sh15
-rw-r--r--server-tools/instance-manager/Makefile.am4
-rw-r--r--sql-common/client.c24
-rw-r--r--sql/ha_federated.cc1049
-rw-r--r--[-rwxr-xr-x]sql/ha_federated.h33
-rw-r--r--sql/ha_innodb.cc233
-rw-r--r--sql/ha_innodb.h1
-rw-r--r--sql/ha_myisam.cc18
-rw-r--r--sql/handler.cc31
-rw-r--r--sql/item.cc263
-rw-r--r--sql/item.h30
-rw-r--r--sql/item_cmpfunc.cc28
-rw-r--r--sql/item_cmpfunc.h14
-rw-r--r--sql/item_create.cc2
-rw-r--r--sql/item_func.cc131
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_strfunc.cc17
-rw-r--r--sql/item_strfunc.h16
-rw-r--r--sql/item_sum.cc18
-rw-r--r--sql/item_sum.h3
-rw-r--r--sql/log.cc55
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/mysql_priv.h8
-rw-r--r--sql/mysqld.cc43
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/share/errmsg.txt4
-rw-r--r--sql/slave.cc50
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sp.cc199
-rw-r--r--sql/sp.h8
-rw-r--r--sql/sp_head.cc725
-rw-r--r--sql/sp_head.h221
-rw-r--r--sql/sp_rcontext.cc8
-rw-r--r--sql/sp_rcontext.h11
-rw-r--r--sql/sql_acl.cc126
-rw-r--r--sql/sql_acl.h4
-rw-r--r--sql/sql_base.cc377
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_class.h52
-rw-r--r--sql/sql_handler.cc2
-rw-r--r--sql/sql_lex.cc9
-rw-r--r--sql/sql_lex.h40
-rw-r--r--sql/sql_parse.cc204
-rw-r--r--sql/sql_prepare.cc62
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc53
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc56
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/sql_trigger.h13
-rw-r--r--sql/sql_udf.cc123
-rw-r--r--sql/sql_union.cc33
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_view.cc73
-rw-r--r--sql/sql_yacc.yy230
-rw-r--r--sql/table.cc6
-rw-r--r--sql/table.h14
-rw-r--r--sql/tztime.cc4
-rw-r--r--strings/ctype-bin.c9
-rw-r--r--strings/ctype-win1250ch.c2
-rw-r--r--vio/vio.c45
-rw-r--r--vio/viosocket.c46
161 files changed, 5580 insertions, 2747 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 403857f403f..fbb0936c4b5 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -48,8 +48,8 @@ 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-vio"
-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-vio --with-embedded-server"
+base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid"
+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"
max_no_es_configs="$max_leave_isam_configs --without-isam"
max_configs="$max_no_es_configs --with-embedded-server"
diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max
index 7f78089c3e8..2e4ff8e0082 100644
--- a/BUILD/compile-pentium64-valgrind-max
+++ b/BUILD/compile-pentium64-valgrind-max
@@ -9,7 +9,7 @@ cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs"
# We want to test isam when building with valgrind
-extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-vio --with-raid --with-ndbcluster"
+extra_configs="$extra_configs --with-berkeley-db --with-innodb --with-isam --with-embedded-server --with-openssl --with-raid --with-ndbcluster"
. "$path/FINISH.sh"
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 89e1ff4bd48..ec66e9ef2eb 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -71,6 +71,7 @@ hf@deer.(none)
hf@deer.mysql.r18.ru
hf@genie.(none)
igor@hundin.mysql.fi
+igor@linux.local
igor@rurik.mysql.com
ingo@mysql.com
jan@hundin.mysql.fi
diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4
index ec0c296a8b2..556cc7625cc 100644
--- a/config/ac-macros/misc.m4
+++ b/config/ac-macros/misc.m4
@@ -594,22 +594,13 @@ AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
])
AC_DEFUN([MYSQL_CHECK_VIO], [
- AC_ARG_WITH([vio],
- [ --with-vio Include the Virtual IO support],
- [vio="$withval"],
- [vio=no])
-
- if test "$vio" = "yes"
- then
- vio_dir="vio"
- vio_libs="../vio/libvio.la"
- AC_DEFINE(HAVE_VIO, 1)
- else
- vio_dir=""
- vio_libs=""
- fi
- AC_SUBST([vio_dir])
- AC_SUBST([vio_libs])
+dnl
+dnl we always use vio: no need for special defines
+dnl
+ AC_DEFINE([HAVE_VIO_READ_BUFF], [1],
+ [Define to enable buffered read. This works only if syscalls
+ read/recv return as soon as there is some data in the kernel
+ buffer, no matter how big the given buffer is.])
])
# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not
diff --git a/config/ac-macros/openssl.m4 b/config/ac-macros/openssl.m4
index 9da0e38f2ba..6541a492247 100644
--- a/config/ac-macros/openssl.m4
+++ b/config/ac-macros/openssl.m4
@@ -89,9 +89,6 @@ AC_MSG_CHECKING(for OpenSSL)
fi
MYSQL_FIND_OPENSSL([$openssl_includes], [$openssl_libs])
#force VIO use
- vio_dir="vio"
- vio_libs="../vio/libvio.la"
- AC_DEFINE([HAVE_VIO], [1], [Virtual IO])
AC_MSG_RESULT(yes)
openssl_libs="-L$OPENSSL_LIB -lssl -lcrypto"
# Don't set openssl_includes to /usr/include as this gives us a lot of
diff --git a/include/config-win.h b/include/config-win.h
index e86e0f08596..4ef5c9323e7 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -308,7 +308,7 @@ inline double ulonglong2double(ulonglong value)
#define HAVE_QUERY_CACHE
#define SPRINTF_RETURNS_INT
#define HAVE_SETFILEPOINTER
-#define HAVE_VIO
+#define HAVE_VIO_READ_BUFF
#ifdef NOT_USED
#define HAVE_SNPRINTF /* Gave link error */
diff --git a/include/my_global.h b/include/my_global.h
index 30b98b9fbeb..e9470ac48aa 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -523,6 +523,9 @@ typedef SOCKET_SIZE_TYPE size_socket;
#ifndef O_SHORT_LIVED
#define O_SHORT_LIVED 0
#endif
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
+#endif
/* #define USE_RECORD_LOCK */
diff --git a/include/my_sys.h b/include/my_sys.h
index 7c69a626366..ce785b58da4 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -206,11 +206,13 @@ void __CDECL hfree(void *ptr);
#endif
#endif /* MSDOS */
+#ifndef errno /* did we already get it? */
#ifdef HAVE_ERRNO_AS_DEFINE
#include <errno.h> /* errno is a define */
#else
extern int errno; /* declare errno */
#endif
+#endif /* #ifndef errno */
extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
extern char *home_dir; /* Home directory for user */
extern char *my_progname; /* program-name (printed in errors) */
diff --git a/include/violite.h b/include/violite.h
index 855d8a3d490..a62fe37f45d 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -37,7 +37,12 @@ enum enum_vio_type
VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY
};
-Vio* vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost);
+
+#define VIO_LOCALHOST 1 /* a localhost connection */
+#define VIO_BUFFERED_READ 2 /* use buffered read */
+#define VIO_READ_BUFFER_SIZE 16384 /* size of read buffer */
+
+Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
#ifdef __WIN__
Vio* vio_new_win32pipe(HANDLE hPipe);
Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map,
@@ -57,8 +62,9 @@ int vio_close_pipe(Vio * vio);
void vio_delete(Vio* vio);
int vio_close(Vio* vio);
void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe, my_bool localhost);
+ my_socket sd, HANDLE hPipe, uint flags);
int vio_read(Vio *vio, gptr buf, int size);
+int vio_read_buff(Vio *vio, gptr buf, int size);
int vio_write(Vio *vio, const gptr buf, int size);
int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode);
my_bool vio_is_blocking(Vio *vio);
@@ -135,7 +141,7 @@ int vio_close_shared_memory(Vio * vio);
}
#endif
-#if defined(HAVE_VIO) && !defined(DONT_MAP_VIO)
+#if !defined(DONT_MAP_VIO)
#define vio_delete(vio) (vio)->viodelete(vio)
#define vio_errno(vio) (vio)->vioerrno(vio)
#define vio_read(vio, buf, size) (vio)->read(vio,buf,size)
@@ -150,7 +156,7 @@ int vio_close_shared_memory(Vio * vio);
#define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt)
#define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
#define vio_timeout(vio, seconds) (vio)->timeout(vio, seconds)
-#endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */
+#endif /* !defined(DONT_MAP_VIO) */
/* This enumerator is used in parser - should be always visible */
enum SSL_type
@@ -175,7 +181,10 @@ struct st_vio
struct sockaddr_in remote; /* Remote internet address */
enum enum_vio_type type; /* Type of connection */
char desc[30]; /* String description */
-#ifdef HAVE_VIO
+ char *read_buffer; /* buffer for vio_read_buff */
+ char *read_pos; /* start of unfetched data in the
+ read buffer */
+ char *read_end; /* end of unfetched data */
/* function pointers. They are similar for socket/SSL/whatever */
void (*viodelete)(Vio*);
int (*vioerrno)(Vio*);
@@ -203,6 +212,5 @@ struct st_vio
char *shared_memory_pos;
NET *net;
#endif /* HAVE_SMEM */
-#endif /* HAVE_VIO */
};
#endif /* vio_violite_h_ */
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index 8559df16d08..91ba47224ef 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -1642,7 +1642,7 @@ btr_cur_optimistic_update(
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(page_cursor, index, mtr);
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
page_cur_move_to_prev(page_cursor);
@@ -1885,7 +1885,7 @@ btr_cur_pessimistic_update(
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(page_cursor, index, mtr);
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
page_cur_move_to_prev(page_cursor);
@@ -2401,6 +2401,7 @@ btr_cur_optimistic_delete(
mem_heap_t* heap = NULL;
ulint offsets_[100] = { 100, };
ulint* offsets = offsets_;
+ ibool no_compress_needed;
ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)),
MTR_MEMO_PAGE_X_FIX));
@@ -2414,9 +2415,11 @@ btr_cur_optimistic_delete(
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
- if (!rec_offs_any_extern(offsets)
+ no_compress_needed = !rec_offs_any_extern(offsets)
&& btr_cur_can_delete_without_compress(
- cursor, rec_offs_size(offsets), mtr)) {
+ cursor, rec_offs_size(offsets), mtr);
+
+ if (no_compress_needed) {
lock_update_delete(rec);
@@ -2425,20 +2428,17 @@ btr_cur_optimistic_delete(
max_ins_size = page_get_max_insert_size_after_reorganize(page,
1);
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- cursor->index, mtr);
+ cursor->index, offsets, mtr);
ibuf_update_free_bits_low(cursor->index, page, max_ins_size,
mtr);
- if (heap) {
- mem_heap_free(heap);
- }
- return(TRUE);
}
if (heap) {
mem_heap_free(heap);
}
- return(FALSE);
+
+ return(no_compress_needed);
}
/*****************************************************************
@@ -2478,6 +2478,7 @@ btr_cur_pessimistic_delete(
ibool success;
ibool ret = FALSE;
mem_heap_t* heap;
+ ulint* offsets;
page = btr_cur_get_page(cursor);
tree = btr_cur_get_tree(cursor);
@@ -2503,20 +2504,20 @@ btr_cur_pessimistic_delete(
}
}
- heap = mem_heap_create(256);
+ heap = mem_heap_create(1024);
rec = btr_cur_get_rec(cursor);
+ offsets = rec_get_offsets(rec, cursor->index,
+ NULL, ULINT_UNDEFINED, &heap);
+
/* Free externally stored fields if the record is neither
a node pointer nor in two-byte format.
- This avoids unnecessary calls to rec_get_offsets(). */
+ This avoids an unnecessary loop. */
if (cursor->index->table->comp
? !rec_get_node_ptr_flag(rec)
: !rec_get_1byte_offs_flag(rec)) {
btr_rec_free_externally_stored_fields(cursor->index,
- rec, rec_get_offsets(rec, cursor->index,
- NULL, ULINT_UNDEFINED, &heap),
- in_rollback, mtr);
- mem_heap_empty(heap);
+ rec, offsets, in_rollback, mtr);
}
if ((page_get_n_recs(page) < 2)
@@ -2568,7 +2569,8 @@ btr_cur_pessimistic_delete(
btr_search_update_hash_on_delete(cursor);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor), cursor->index, mtr);
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor), cursor->index,
+ offsets, mtr);
ut_ad(btr_check_node_ptr(tree, page, mtr));
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 4926797721c..fda09feca6f 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -729,14 +729,17 @@ dict_drop_index_tree(
/***********************************************************************
Truncates the index tree associated with a row in SYS_INDEXES table. */
-void
+ulint
dict_truncate_index_tree(
/*=====================*/
+ /* out: new root page number, or
+ FIL_NULL on failure */
dict_table_t* table, /* in: the table the index belongs to */
rec_t* rec, /* in: record in the clustered index of
SYS_INDEXES table */
mtr_t* mtr) /* in: mtr having the latch
- on the record page */
+ on the record page. The mtr may be
+ committed and restarted in this call. */
{
ulint root_page_no;
ulint space;
@@ -761,7 +764,10 @@ dict_truncate_index_tree(
if (root_page_no == FIL_NULL) {
/* The tree has been freed. */
- return;
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Trying to TRUNCATE"
+ " a missing index of table %s!\n", table->name);
+ return(FIL_NULL);
}
ptr = rec_get_nth_field_old(rec,
@@ -775,7 +781,10 @@ dict_truncate_index_tree(
/* It is a single table tablespace and the .ibd file is
missing: do nothing */
- return;
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Trying to TRUNCATE"
+ " a missing .ibd file of table %s!\n", table->name);
+ return(FIL_NULL);
}
ptr = rec_get_nth_field_old(rec,
@@ -801,6 +810,20 @@ dict_truncate_index_tree(
space, root_page_no, RW_X_LATCH, mtr));
btr_free_root(space, root_page_no, mtr);
+ /* We will temporarily write FIL_NULL to the PAGE_NO field
+ in SYS_INDEXES, so that the database will not get into an
+ inconsistent state in case it crashes between the mtr_commit()
+ below and the following mtr_commit() call. */
+ page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
+ FIL_NULL, mtr);
+
+ /* We will need to commit the mini-transaction in order to avoid
+ deadlocks in the btr_create() call, because otherwise we would
+ be freeing and allocating pages in the same mini-transaction. */
+ mtr_commit(mtr);
+ /* mtr_commit() will invalidate rec. */
+ rec = NULL;
+ mtr_start(mtr);
/* Find the index corresponding to this SYS_INDEXES record. */
for (index = UT_LIST_GET_FIRST(table->indexes);
@@ -814,11 +837,17 @@ dict_truncate_index_tree(
root_page_no = btr_create(type, space, index_id, comp, mtr);
if (index) {
index->tree->page = root_page_no;
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Index %lu %lu of table %s is missing\n"
+ "InnoDB: from the data dictionary during TRUNCATE!\n",
+ ut_dulint_get_high(index_id),
+ ut_dulint_get_low(index_id),
+ table->name);
}
- page_rec_write_index_page_no(rec,
- DICT_SYS_INDEXES_PAGE_NO_FIELD,
- root_page_no, mtr);
+ return(root_page_no);
}
/*************************************************************************
diff --git a/innobase/include/dict0crea.h b/innobase/include/dict0crea.h
index 7164e53bceb..5dd571be59c 100644
--- a/innobase/include/dict0crea.h
+++ b/innobase/include/dict0crea.h
@@ -56,14 +56,17 @@ dict_create_index_step(
/***********************************************************************
Truncates the index tree associated with a row in SYS_INDEXES table. */
-void
+ulint
dict_truncate_index_tree(
/*=====================*/
+ /* out: new root page number, or
+ FIL_NULL on failure */
dict_table_t* table, /* in: the table the index belongs to */
rec_t* rec, /* in: record in the clustered index of
SYS_INDEXES table */
mtr_t* mtr); /* in: mtr having the latch
- on the record page */
+ on the record page. The mtr may be
+ committed and restarted in this call. */
/***********************************************************************
Drops the index tree associated with a row in SYS_INDEXES table. */
diff --git a/innobase/include/page0cur.h b/innobase/include/page0cur.h
index 7c6ff081c6d..4fc62f37db7 100644
--- a/innobase/include/page0cur.h
+++ b/innobase/include/page0cur.h
@@ -182,9 +182,10 @@ next record after the deleted one. */
void
page_cur_delete_rec(
/*================*/
- page_cur_t* cursor, /* in: a page cursor */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mini-transaction handle */
+ page_cur_t* cursor, /* in: a page cursor */
+ dict_index_t* index, /* in: record descriptor */
+ const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
+ mtr_t* mtr); /* in: mini-transaction handle */
/********************************************************************
Searches the right position for a page cursor. */
UNIV_INLINE
diff --git a/innobase/include/page0page.h b/innobase/include/page0page.h
index d3ef8214eb6..144c297b811 100644
--- a/innobase/include/page0page.h
+++ b/innobase/include/page0page.h
@@ -528,7 +528,7 @@ page_mem_free(
/*==========*/
page_t* page, /* in: index page */
rec_t* rec, /* in: pointer to the (origin of) record */
- dict_index_t* index); /* in: record descriptor */
+ const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**************************************************************
The index page creation function. */
diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic
index a63b5ca4238..ac6b0263a7d 100644
--- a/innobase/include/page0page.ic
+++ b/innobase/include/page0page.ic
@@ -777,20 +777,31 @@ page_mem_free(
/*==========*/
page_t* page, /* in: index page */
rec_t* rec, /* in: pointer to the (origin of) record */
- dict_index_t* index) /* in: record descriptor */
+ const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
rec_t* free;
ulint garbage;
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
free = page_header_get_ptr(page, PAGE_FREE);
page_rec_set_next(rec, free);
page_header_set_ptr(page, PAGE_FREE, rec);
+#if 0 /* It's better not to destroy the user's data. */
+
+ /* Clear the data bytes of the deleted record in order to improve
+ the compression ratio of the page and to make it easier to read
+ page dumps in corruption reports. The extra bytes of the record
+ cannot be cleared, because page_mem_alloc() needs them in order
+ to determine the size of the deleted record. */
+ memset(rec, 0, rec_offs_data_size(offsets));
+#endif
+
garbage = page_header_get_field(page, PAGE_GARBAGE);
page_header_set_field(page, PAGE_GARBAGE,
- garbage + rec_get_size(rec, index));
+ garbage + rec_offs_size(offsets));
}
#ifdef UNIV_MATERIALIZE
diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h
index c430def684a..6721fa85f16 100644
--- a/innobase/include/rem0rec.h
+++ b/innobase/include/rem0rec.h
@@ -435,15 +435,6 @@ rec_offs_size(
/* out: size */
const ulint* offsets);/* in: array returned by rec_get_offsets() */
/**************************************************************
-Returns the total size of a physical record. */
-
-ulint
-rec_get_size(
-/*=========*/
- /* out: size */
- rec_t* rec, /* in: physical record */
- dict_index_t* index); /* in: record descriptor */
-/**************************************************************
Returns a pointer to the start of the record. */
UNIV_INLINE
byte*
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 27cdaf2e505..5d76ac3d775 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -52,7 +52,7 @@ extern ulint* srv_data_file_is_raw_partition;
extern ibool srv_auto_extend_last_data_file;
extern ulint srv_last_file_size_max;
-extern ulint srv_auto_extend_increment;
+extern ulong srv_auto_extend_increment;
extern ibool srv_created_new_raw;
@@ -112,11 +112,9 @@ extern ibool srv_use_checksums;
extern ibool srv_set_thread_priorities;
extern int srv_query_thread_priority;
-extern ulint srv_max_purge_lag;
+extern ulong srv_max_purge_lag;
extern ibool srv_use_awe;
extern ibool srv_use_adaptive_hash_indexes;
-
-extern ulint srv_max_purge_lag;
/*-------------------------------------------*/
extern ulint srv_n_rows_inserted;
diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c
index 1ab91b71e8f..5915146b466 100644
--- a/innobase/log/log0log.c
+++ b/innobase/log/log0log.c
@@ -24,6 +24,32 @@ Created 12/9/1995 Heikki Tuuri
#include "trx0sys.h"
#include "trx0trx.h"
+/*
+General philosophy of InnoDB redo-logs:
+
+1) Every change to a contents of a data page must be done
+through mtr, which in mtr_commit() writes log records
+to the InnoDB redo log.
+
+2) Normally these changes are performed using a mlog_write_ulint()
+or similar function.
+
+3) In some page level operations only a code number of a
+c-function and its parameters are written to the log to
+reduce the size of the log.
+
+ 3a) You should not add parameters to these kind of functions
+ (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
+
+ 3b) You should not add such functionality which either change
+ working when compared with the old or are dependent on data
+ outside of the page. These kind of functions should implement
+ self-contained page transformation and it should be unchanged
+ if you don't have very essential reasons to change log
+ semantics or format.
+
+*/
+
/* Current free limit of space 0; protected by the log sys mutex; 0 means
uninitialized */
ulint log_fsp_current_free_limit = 0;
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index 40a7deee604..ac230f6461b 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -1437,7 +1437,7 @@ loop:
/* This page is allocated from the buffer pool and used in the function
below */
-page_t* recv_backup_application_page = NULL;
+static page_t* recv_backup_application_page = NULL;
/***********************************************************************
Applies log records in the hash table to a backup. */
diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c
index 488d2757115..d083cc26069 100644
--- a/innobase/page/page0cur.c
+++ b/innobase/page/page0cur.c
@@ -1267,9 +1267,18 @@ page_cur_parse_delete_rec(
ut_a(offset <= UNIV_PAGE_SIZE);
if (page) {
- page_cur_position(page + offset, &cursor);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ rec_t* rec = page + offset;
+
+ page_cur_position(rec, &cursor);
- page_cur_delete_rec(&cursor, index, mtr);
+ page_cur_delete_rec(&cursor, index,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap), mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
return(ptr);
@@ -1284,6 +1293,7 @@ page_cur_delete_rec(
/*================*/
page_cur_t* cursor, /* in: a page cursor */
dict_index_t* index, /* in: record descriptor */
+ const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
mtr_t* mtr) /* in: mini-transaction handle */
{
page_dir_slot_t* cur_dir_slot;
@@ -1300,6 +1310,7 @@ page_cur_delete_rec(
page = page_cur_get_page(cursor);
current_rec = cursor->rec;
+ ut_ad(rec_offs_validate(current_rec, index, offsets));
/* The record must not be the supremum or infimum record. */
ut_ad(current_rec != page_get_supremum_rec(page));
@@ -1365,7 +1376,7 @@ page_cur_delete_rec(
page_dir_slot_set_n_owned(cur_dir_slot, cur_n_owned - 1);
/* 6. Free the memory occupied by the record */
- page_mem_free(page, current_rec, index);
+ page_mem_free(page, current_rec, offsets);
/* 7. Now we have decremented the number of owned records of the slot.
If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index 901c8cd0831..b393f0c0ad7 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -416,7 +416,7 @@ page_create(
mem_heap_free(heap);
- /* 4. INITIALIZE THE PAGE HEADER */
+ /* 4. INITIALIZE THE PAGE */
page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
@@ -428,7 +428,9 @@ page_create(
page_header_set_field(page, PAGE_N_DIRECTION, 0);
page_header_set_field(page, PAGE_N_RECS, 0);
page_set_max_trx_id(page, ut_dulint_zero);
-
+ memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
+ - (heap_top - page));
+
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
/* Set the slots to point to infimum and supremum. */
@@ -829,12 +831,18 @@ page_delete_rec_list_start(
{
page_cur_t cur1;
ulint log_mode;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+ mem_heap_t* heap = NULL;
+ byte type;
- page_delete_rec_list_write_log(page, rec, index,
- index->table->comp
- ? MLOG_COMP_LIST_START_DELETE
- : MLOG_LIST_START_DELETE,
- mtr);
+ if (index->table->comp) {
+ type = MLOG_COMP_LIST_START_DELETE;
+ } else {
+ type = MLOG_LIST_START_DELETE;
+ }
+
+ page_delete_rec_list_write_log(page, rec, index, type, mtr);
page_cur_set_before_first(page, &cur1);
@@ -850,8 +858,13 @@ page_delete_rec_list_start(
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
while (page_cur_get_rec(&cur1) != rec) {
+ offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
+ offsets, ULINT_UNDEFINED, &heap);
+ page_cur_delete_rec(&cur1, index, offsets, mtr);
+ }
- page_cur_delete_rec(&cur1, index, mtr);
+ if (heap) {
+ mem_heap_free(heap);
}
/* Restore log mode */
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index 30f98f457ea..904f91b8945 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -620,7 +620,7 @@ rec_set_nth_field_extern_bit_new(
mlog_write_ulint(lens + 1, len,
MLOG_1BYTE, mtr);
} else {
- lens[1] = len;
+ lens[1] = (byte) len;
}
return;
}
@@ -658,29 +658,6 @@ rec_set_field_extern_bits(
}
}
-/**************************************************************
-Returns the total size of a physical record. */
-
-ulint
-rec_get_size(
-/*=========*/
- /* out: size */
- rec_t* rec, /* in: physical record */
- dict_index_t* index) /* in: record descriptor */
-{
- mem_heap_t* heap = NULL;
- ulint offsets_[100 + REC_OFFS_HEADER_SIZE]
- = { 100, };
- ulint* offsets = rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap);
- ulint size = rec_offs_size(offsets);
-
- if (heap) {
- mem_heap_free(heap);
- }
- return(size);
-}
-
/***************************************************************
Sets an old-style record field to SQL null.
The physical size of the field is not changed. */
@@ -935,13 +912,13 @@ init:
|| dtype_get_mtype(type) == DATA_BLOB);
if (len < 128 || (dtype_get_len(type) < 256
&& dtype_get_mtype(type) != DATA_BLOB)) {
- *lens-- = len;
+ *lens-- = (byte) len;
}
else {
/* the extern bits will be set later */
ut_ad(len < 16384);
- *lens-- = len >> 8 | 0x80;
- *lens-- = len;
+ *lens-- = (byte) (len >> 8) | 0x80;
+ *lens-- = (byte) len;
}
}
copy:
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 39c4b76f814..4c014d39f7a 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -2615,6 +2615,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
rec_t* rec;
const byte* field;
ulint len;
+ ulint root_page_no;
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
/* The end of SYS_INDEXES has been reached. */
@@ -2633,11 +2634,33 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
if (rec_get_deleted_flag(rec, FALSE)) {
/* The index has been dropped. */
- continue;
+ goto next_rec;
}
- dict_truncate_index_tree(table, rec, &mtr);
+ btr_pcur_store_position(&pcur, &mtr);
+ /* This call may commit and restart mtr. */
+ root_page_no = dict_truncate_index_tree(table, rec, &mtr);
+
+ btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (root_page_no != FIL_NULL) {
+ page_rec_write_index_page_no(rec,
+ DICT_SYS_INDEXES_PAGE_NO_FIELD,
+ root_page_no, &mtr);
+ /* We will need to commit and restart the
+ mini-transaction in order to avoid deadlocks.
+ The dict_truncate_index_tree() call has allocated
+ a page in this mini-transaction, and the rest of
+ this loop could latch another index page. */
+ mtr_commit(&mtr);
+ mtr_start(&mtr);
+ btr_pcur_restore_position(BTR_MODIFY_LEAF,
+ &pcur, &mtr);
+ }
+
+ next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index a2c91ae5ffc..e478376e67b 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -2501,7 +2501,7 @@ row_sel_store_mysql_rec(
}
/* Handle UCS2 strings differently. */
- if (templ->mbminlen == 2) {
+ if (pad_char != '\0' && templ->mbminlen == 2) {
/* There are two bytes per char, so the length
has to be an even number. */
ut_a(!(templ->mysql_col_len & 1));
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index 55ce452772d..538fd6ffc08 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -97,7 +97,7 @@ ulint srv_last_file_size_max = 0; /* if != 0, this tells
the max size auto-extending
may increase the last data
file size */
-ulint srv_auto_extend_increment = 8; /* If the last data file is
+ulong srv_auto_extend_increment = 8; /* If the last data file is
auto-extended, we add this
many pages to it at a time */
ulint* srv_data_file_is_raw_partition = NULL;
@@ -323,9 +323,6 @@ disable adaptive hash indexes */
ibool srv_use_awe = FALSE;
ibool srv_use_adaptive_hash_indexes = TRUE;
-/* Maximum allowable purge history length. <=0 means 'infinite'. */
-ulint srv_max_purge_lag = 0;
-
/*-------------------------------------------*/
ulint srv_n_spin_wait_rounds = 20;
ulint srv_n_free_tickets_to_enter = 500;
@@ -972,6 +969,8 @@ srv_general_init(void)
/*======================= InnoDB Server FIFO queue =======================*/
+/* Maximum allowable purge history length. <=0 means 'infinite'. */
+ulong srv_max_purge_lag = 0;
/*************************************************************************
Puts an OS thread to wait if there are too many concurrent threads
@@ -1501,7 +1500,7 @@ srv_suspend_mysql_thread(
ut_usectime(&sec, &ms);
finish_time = (ib_longlong)sec * 1000000 + ms;
- diff_time = finish_time - start_time;
+ diff_time = (ulint) (finish_time - start_time);
srv_n_lock_wait_current_count--;
srv_n_lock_wait_time = srv_n_lock_wait_time + diff_time;
@@ -1799,9 +1798,12 @@ srv_export_innodb_status(void)
export_vars.innodb_row_lock_waits= srv_n_lock_wait_count;
export_vars.innodb_row_lock_current_waits= srv_n_lock_wait_current_count;
export_vars.innodb_row_lock_time= srv_n_lock_wait_time / 10000;
- export_vars.innodb_row_lock_time_avg=
- (srv_n_lock_wait_count > 0) ?
- (srv_n_lock_wait_time / 10000 / srv_n_lock_wait_count) : 0;
+ if (srv_n_lock_wait_count > 0) {
+ export_vars.innodb_row_lock_time_avg = (ulint)
+ (srv_n_lock_wait_time / 10000 / srv_n_lock_wait_count);
+ } else {
+ export_vars.innodb_row_lock_time_avg = 0;
+ }
export_vars.innodb_row_lock_time_max= srv_n_lock_max_wait_time / 10000;
export_vars.innodb_rows_read= srv_n_rows_read;
export_vars.innodb_rows_inserted= srv_n_rows_inserted;
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index b2f97492e70..210739b26fd 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -568,7 +568,14 @@ open_or_create_log_file(
files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL,
OS_LOG_FILE, &ret);
if (ret == FALSE) {
- if (os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS) {
+ if (os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS
+#ifdef UNIV_AIX
+ /* AIX 5.1 after security patch ML7 may have errno set
+ to 0 here, which causes our function to return 100;
+ work around that AIX problem */
+ && os_file_get_last_error(FALSE) != 100
+#endif
+ ) {
fprintf(stderr,
"InnoDB: Error in creating or opening %s\n", name);
@@ -728,7 +735,14 @@ open_or_create_data_files(
OS_FILE_NORMAL, OS_DATA_FILE, &ret);
if (ret == FALSE && os_file_get_last_error(FALSE) !=
- OS_FILE_ALREADY_EXISTS) {
+ OS_FILE_ALREADY_EXISTS
+#ifdef UNIV_AIX
+ /* AIX 5.1 after security patch ML7 may have
+ errno set to 0 here, which causes our function
+ to return 100; work around that AIX problem */
+ && os_file_get_last_error(FALSE) != 100
+#endif
+ ) {
fprintf(stderr,
"InnoDB: Error in creating or opening %s\n",
name);
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index 98b91ed5211..e604912e996 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -369,11 +369,11 @@ mutex_spin_wait(
{
ulint index; /* index of the reserved wait cell */
ulint i; /* spin round count */
+#ifndef UNIV_HOTBACKUP
ib_longlong lstart_time = 0, lfinish_time; /* for timing os_wait */
ulint ltime_diff;
ulint sec;
ulint ms;
-#ifndef UNIV_HOTBACKUP
uint timer_started = 0;
#endif /* !UNIV_HOTBACKUP */
ut_ad(mutex);
@@ -535,7 +535,7 @@ finish_timing:
ut_usectime(&sec, &ms);
lfinish_time= (ib_longlong)sec * 1000000 + ms;
- ltime_diff= lfinish_time - lstart_time;
+ ltime_diff= (ulint) (lfinish_time - lstart_time);
mutex->lspent_time += ltime_diff;
if (mutex->lmax_spent_time < ltime_diff)
{
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index 559c2cb5128..4c68e0a0dd3 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -440,7 +440,17 @@ loop:
if ((trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
trx = UT_LIST_GET_NEXT(trx_list, trx);
} else if (trx->conc_state == TRX_PREPARED) {
- trx->sess = trx_dummy_sess;
+
+ /* Roll back all prepared transactions if
+ innobase_force_recovery > 0 in my.cnf */
+
+ if (srv_force_recovery > 0) {
+ trx->conc_state = TRX_ACTIVE;
+ break;
+ } else {
+ trx->sess = trx_dummy_sess;
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
} else {
break;
}
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index a33ca4b8ec3..dd4da33abb5 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -262,6 +262,20 @@ trx_free(
putc('\n', stderr);
}
+ if (trx->n_mysql_tables_in_use != 0
+ || trx->mysql_n_tables_locked != 0) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: MySQL is freeing a thd\n"
+"InnoDB: though trx->n_mysql_tables_in_use is %lu\n"
+"InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
+ (ulong)trx->n_mysql_tables_in_use,
+ (ulong)trx->mysql_n_tables_locked);
+
+ trx_print(stderr, trx);
+ }
+
ut_a(trx->magic_n == TRX_MAGIC_N);
trx->magic_n = 11112222;
@@ -272,9 +286,6 @@ trx_free(
ut_a(trx->insert_undo == NULL);
ut_a(trx->update_undo == NULL);
-
- ut_a(trx->n_mysql_tables_in_use == 0);
- ut_a(trx->mysql_n_tables_locked == 0);
if (trx->undo_no_arr) {
trx_undo_arr_free(trx->undo_no_arr);
@@ -435,14 +446,14 @@ trx_lists_init_at_db_start(void)
if (undo->state == TRX_UNDO_PREPARED) {
- fprintf(stderr,
+ fprintf(stderr,
"InnoDB: Transaction %lu %lu was in the XA prepared state.\n",
ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id));
- /* trx->conc_state = TRX_PREPARED; */
- trx->conc_state =
- TRX_ACTIVE;
+ trx->conc_state = TRX_ACTIVE;
+
+ /* trx->conc_state = TRX_PREPARED;*/
} else {
trx->conc_state =
TRX_COMMITTED_IN_MEMORY;
@@ -498,16 +509,15 @@ trx_lists_init_at_db_start(void)
commit or abort decision from MySQL */
if (undo->state == TRX_UNDO_PREPARED) {
-
- fprintf(stderr,
+ fprintf(stderr,
"InnoDB: Transaction %lu %lu was in the XA prepared state.\n",
- ut_dulint_get_high(trx->id),
- ut_dulint_get_low(trx->id));
+ ut_dulint_get_high(trx->id),
+ ut_dulint_get_low(trx->id));
- /* trx->conc_state = TRX_PREPARED; */
- trx->conc_state =
- TRX_ACTIVE;
+ trx->conc_state = TRX_ACTIVE;
+ /* trx->conc_state =
+ TRX_PREPARED; */
} else {
trx->conc_state =
TRX_COMMITTED_IN_MEMORY;
@@ -1638,10 +1648,13 @@ trx_print(
fputs(", not started", f);
break;
case TRX_ACTIVE:
- case TRX_PREPARED:
fprintf(f, ", ACTIVE %lu sec",
(ulong)difftime(time(NULL), trx->start_time));
break;
+ case TRX_PREPARED:
+ fprintf(f, ", ACTIVE (PREPARED) %lu sec",
+ (ulong)difftime(time(NULL), trx->start_time));
+ break;
case TRX_COMMITTED_IN_MEMORY:
fputs(", COMMITTED IN MEMORY", f);
break;
@@ -1938,7 +1951,7 @@ trx_get_trx_by_xid(
if (xid->gtrid_length == trx->xid.gtrid_length &&
xid->bqual_length == trx->xid.bqual_length &&
- memcmp(xid, &trx->xid,
+ memcmp(xid->data, trx->xid.data,
xid->gtrid_length +
xid->bqual_length) == 0) {
break;
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index 545e1b77fee..88185973dfc 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -599,11 +599,10 @@ trx_undo_read_xid(
Adds the XA XID after an undo log old-style header. */
static
void
-trx_undo_header_add_xid(
-/*====================*/
+trx_undo_header_add_space_for_xid(
+/*==============================*/
page_t* undo_page,/* in: undo log segment header page */
trx_ulogf_t* log_hdr,/* in: undo log header */
- XID* xid, /* in: X/Open XA transaction identification */
mtr_t* mtr) /* in: mtr */
{
trx_upagef_t* page_hdr;
@@ -620,9 +619,8 @@ trx_undo_header_add_xid(
new_free = free + (TRX_UNDO_LOG_XA_HDR_SIZE
- TRX_UNDO_LOG_OLD_HDR_SIZE);
- trx_undo_write_xid(log_hdr, xid, mtr);
- /* Now that we added the XID after the header, update the free offset
+ /* Add space for a XID after the header, update the free offset
fields on the undo log page and in the undo log header */
mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free,
@@ -1532,7 +1530,7 @@ trx_undo_create(
offset = trx_undo_header_create(undo_page, trx_id, mtr);
- trx_undo_header_add_xid(undo_page, undo_page + offset, xid, mtr);
+ trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
page_no, offset);
@@ -1599,7 +1597,7 @@ trx_undo_reuse_cached(
if (type == TRX_UNDO_INSERT) {
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
- trx_undo_header_add_xid(undo_page, undo_page + offset, xid,
+ trx_undo_header_add_space_for_xid(undo_page, undo_page + offset,
mtr);
} else {
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
@@ -1607,7 +1605,7 @@ trx_undo_reuse_cached(
== TRX_UNDO_UPDATE);
offset = trx_undo_header_create(undo_page, trx_id, mtr);
- trx_undo_header_add_xid(undo_page, undo_page + offset, xid,
+ trx_undo_header_add_space_for_xid(undo_page, undo_page + offset,
mtr);
}
diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c
index 9e026ed0011..3e8fd79a739 100644
--- a/innobase/ut/ut0mem.c
+++ b/innobase/ut/ut0mem.c
@@ -14,6 +14,7 @@ Created 5/11/1994 Heikki Tuuri
#include "mem0mem.h"
#include "os0sync.h"
+#include "os0thread.h"
/* This struct is placed first in every allocated memory block */
typedef struct ut_mem_block_struct ut_mem_block_t;
@@ -66,6 +67,7 @@ ut_malloc_low(
ibool assert_on_error) /* in: if TRUE, we crash mysqld if the memory
cannot be allocated */
{
+ ulint retry_count = 0;
void* ret;
ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
@@ -73,24 +75,26 @@ ut_malloc_low(
if (!ut_mem_block_list_inited) {
ut_mem_block_list_init();
}
-
+retry:
os_fast_mutex_lock(&ut_list_mutex);
ret = malloc(n + sizeof(ut_mem_block_t));
- if (ret == NULL) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Fatal error: cannot allocate %lu bytes of\n"
+ if (ret == NULL && retry_count < 60) {
+ if (retry_count == 0) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+ " InnoDB: Error: cannot allocate %lu bytes of\n"
"InnoDB: memory with malloc! Total allocated memory\n"
"InnoDB: by InnoDB %lu bytes. Operating system errno: %lu\n"
- "InnoDB: Cannot continue operation!\n"
"InnoDB: Check if you should increase the swap file or\n"
"InnoDB: ulimits of your operating system.\n"
"InnoDB: On FreeBSD check you have compiled the OS with\n"
"InnoDB: a big enough maximum process size.\n"
"InnoDB: Note that in most 32-bit computers the process\n"
- "InnoDB: memory space is limited to 2 GB or 4 GB.\n",
+ "InnoDB: memory space is limited to 2 GB or 4 GB.\n"
+ "InnoDB: We keep retrying the allocation for 60 seconds...\n",
(ulong) n, (ulong) ut_total_allocated_memory,
#ifdef __WIN__
(ulong) GetLastError()
@@ -98,7 +102,21 @@ ut_malloc_low(
(ulong) errno
#endif
);
+ }
+
+ os_fast_mutex_unlock(&ut_list_mutex);
+ /* Sleep for a second and retry the allocation; maybe this is
+ just a temporary shortage of memory */
+
+ os_thread_sleep(1000000);
+
+ retry_count++;
+
+ goto retry;
+ }
+
+ if (ret == NULL) {
/* Flush stderr to make more probable that the error
message gets in the error file before we generate a seg
fault */
@@ -113,8 +131,10 @@ ut_malloc_low(
by graceful exit handling in ut_a(). */
#if (!defined __NETWARE__)
if (assert_on_error) {
+ ut_print_timestamp(stderr);
+
fprintf(stderr,
- "InnoDB: We now intentionally generate a seg fault so that\n"
+ " InnoDB: We now intentionally generate a seg fault so that\n"
"InnoDB: on Linux we get a stack trace.\n");
if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 1ef29210c0b..20a000f1e4d 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -1116,25 +1116,6 @@ mysql_fetch_field(MYSQL_RES *result)
/**************************************************************************
- Get column lengths of the current row
- If one uses mysql_use_result, res->lengths contains the length information,
- else the lengths are calculated from the offset between pointers.
-**************************************************************************/
-
-ulong * STDCALL
-mysql_fetch_lengths(MYSQL_RES *res)
-{
- MYSQL_ROW column;
-
- if (!(column=res->current_row))
- return 0; /* Something is wrong */
- if (res->data)
- (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
- return res->lengths;
-}
-
-
-/**************************************************************************
Move to a specific row and column
**************************************************************************/
diff --git a/myisam/mi_create.c b/myisam/mi_create.c
index 1f6ed87182c..8635d6bcf36 100644
--- a/myisam/mi_create.c
+++ b/myisam/mi_create.c
@@ -39,7 +39,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
{
register uint i,j;
File dfile,file;
- int errpos,save_errno;
+ int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
myf create_flag;
uint fields,length,max_key_length,packed,pointer,real_length_diff,
key_length,info_length,key_segs,options,min_key_length_skip,
@@ -173,7 +173,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
min_pack_length+= varchar_length;
if (flags & HA_CREATE_TMP_TABLE)
+ {
options|= HA_OPTION_TMP_TABLE;
+ create_mode|= O_EXCL | O_NOFOLLOW;
+ }
if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
{
options|= HA_OPTION_CHECKSUM;
@@ -558,9 +561,22 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
create_flag=MY_DELETE_OLD;
}
- if ((file= my_create_with_symlink(linkname_ptr,
- filename,
- 0, O_RDWR | O_TRUNC,
+ /*
+ If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
+ but no entry is made in the table cache for them.
+ A TRUNCATE command checks for the table in the cache only and could
+ be fooled to believe, the table is not open.
+ Pull the emergency brake in this situation. (Bug #8306)
+ */
+ if (test_if_reopen(filename))
+ {
+ my_printf_error(0, "MyISAM table '%s' is in use "
+ "(most likely by a MERGE table). Try FLUSH TABLES.",
+ MYF(0), name + dirname_length(name));
+ goto err;
+ }
+
+ if ((file= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
MYF(MY_WME | create_flag))) < 0)
goto err;
errpos=1;
@@ -571,7 +587,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (share.base.raid_type)
{
(void) fn_format(filename,name,"",MI_NAME_DEXT,2+4);
- if ((dfile=my_raid_create(filename,0,O_RDWR | O_TRUNC,
+ if ((dfile=my_raid_create(filename, 0, create_mode,
share.base.raid_type,
share.base.raid_chunks,
share.base.raid_chunksize,
@@ -595,8 +611,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
create_flag=MY_DELETE_OLD;
}
if ((dfile=
- my_create_with_symlink(linkname_ptr, filename,
- 0,O_RDWR | O_TRUNC,
+ my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
MYF(MY_WME | create_flag))) < 0)
goto err;
}
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 9a6cfe9f33c..504bc33ecc1 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -50,7 +50,7 @@ if (pos > end_pos) \
** In MySQL the server will handle version issues.
******************************************************************************/
-static MI_INFO *test_if_reopen(char *filename)
+MI_INFO *test_if_reopen(char *filename)
{
LIST *pos;
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index 9a92a916558..b66d7e71a05 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -708,6 +708,7 @@ void mi_copy_status(void* to,void *from);
my_bool mi_check_status(void* param);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
+extern MI_INFO *test_if_reopen(char *filename);
my_bool check_table_is_closed(const char *name, const char *where);
int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup);
int mi_open_keyfile(MYISAM_SHARE *share);
diff --git a/myisammrg/myrg_create.c b/myisammrg/myrg_create.c
index 5fc3c60ff32..7ddb7ecb3b9 100644
--- a/myisammrg/myrg_create.c
+++ b/myisammrg/myrg_create.c
@@ -34,7 +34,7 @@ int myrg_create(const char *name, const char **table_names,
errpos=0;
if ((file = my_create(fn_format(buff,name,"",MYRG_NAME_EXT,4),0,
- O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
goto err;
errpos=1;
if (table_names)
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index a749d2bd4d1..6bcd0715ccd 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -45,7 +45,8 @@ mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c
dist-hook:
mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \
$(distdir)/std_data
- $(INSTALL_DATA) $(srcdir)/t/*.test $(srcdir)/t/*.disabled $(distdir)/t
+ $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t
+ -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t
$(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include
$(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.result.es $(srcdir)/r/*.require $(distdir)/r
@@ -63,7 +64,7 @@ install-data-local:
$(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir)
$(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t
- $(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t
+ -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.opt $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.sh $(DESTDIR)$(testdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.slave-mi $(DESTDIR)$(testdir)/t
diff --git a/mysql-test/include/have_cp1250_ch.inc b/mysql-test/include/have_cp1250_ch.inc
new file mode 100644
index 00000000000..eec5d69fbd6
--- /dev/null
+++ b/mysql-test/include/have_cp1250_ch.inc
@@ -0,0 +1,4 @@
+-- require r/have_cp1250_ch.require
+disable_query_log;
+show collation like "cp1250_czech_cs";
+enable_query_log;
diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result
index 4268b121b1d..50e99e3ecd7 100644
--- a/mysql-test/r/bigint.result
+++ b/mysql-test/r/bigint.result
@@ -87,3 +87,42 @@ drop table t1;
SELECT '0x8000000000000001'+0;
'0x8000000000000001'+0
0
+create table t1 (
+value64 bigint unsigned not null,
+value32 integer not null,
+primary key(value64, value32)
+);
+create table t2 (
+value64 bigint unsigned not null,
+value32 integer not null,
+primary key(value64, value32)
+);
+insert into t1 values(17156792991891826145, 1);
+insert into t1 values( 9223372036854775807, 2);
+insert into t2 values(17156792991891826145, 3);
+insert into t2 values( 9223372036854775807, 4);
+select * from t1;
+value64 value32
+9223372036854775807 2
+17156792991891826145 1
+select * from t2;
+value64 value32
+9223372036854775807 4
+17156792991891826145 3
+select * from t1, t2 where t1.value64=17156792991891826145 and
+t2.value64=17156792991891826145;
+value64 value32 value64 value32
+17156792991891826145 1 17156792991891826145 3
+select * from t1, t2 where t1.value64=17156792991891826145 and
+t2.value64=t1.value64;
+value64 value32 value64 value32
+17156792991891826145 1 17156792991891826145 3
+select * from t1, t2 where t1.value64= 9223372036854775807 and
+t2.value64=9223372036854775807;
+value64 value32 value64 value32
+9223372036854775807 2 9223372036854775807 4
+select * from t1, t2 where t1.value64= 9223372036854775807 and
+t2.value64=t1.value64;
+value64 value32 value64 value32
+9223372036854775807 2 9223372036854775807 4
+drop table t1, t2;
diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result
index 201e1c6de08..e3130888a05 100644
--- a/mysql-test/r/ctype_collate.result
+++ b/mysql-test/r/ctype_collate.result
@@ -514,7 +514,7 @@ Variable_name Value
character_set_client latin1
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
-latin1 latin1_swedish_ci 3 1
+latin1 latin1_swedish_ci 4 1
explain extended SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
@@ -525,7 +525,7 @@ SHOW VARIABLES LIKE 'collation_client';
Variable_name Value
SELECT charset('a'),collation('a'),coercibility('a'),'a'='A';
charset('a') collation('a') coercibility('a') 'a'='A'
-latin1 latin1_swedish_ci 3 1
+latin1 latin1_swedish_ci 4 1
SET CHARACTER SET 'DEFAULT';
ERROR 42000: Unknown character set: 'DEFAULT'
DROP TABLE t1;
diff --git a/mysql-test/r/ctype_cp1250_ch.result b/mysql-test/r/ctype_cp1250_ch.result
new file mode 100644
index 00000000000..62936b84caf
--- /dev/null
+++ b/mysql-test/r/ctype_cp1250_ch.result
@@ -0,0 +1,9 @@
+SHOW COLLATION LIKE 'cp1250_czech_cs';
+Collation Charset Id Default Compiled Sortlen
+cp1250_czech_cs cp1250 34 Yes 2
+CREATE TABLE t1 (a char(16)) character set cp1250 collate cp1250_czech_cs;
+INSERT INTO t1 VALUES ('');
+SELECT a, length(a), a='', a=' ', a=' ' FROM t1;
+a length(a) a='' a=' ' a=' '
+ 0 1 1 1
+DROP TABLE t1;
diff --git a/mysql-test/r/ctype_cp1251.result b/mysql-test/r/ctype_cp1251.result
index 3793e962d40..647f8c6236c 100644
--- a/mysql-test/r/ctype_cp1251.result
+++ b/mysql-test/r/ctype_cp1251.result
@@ -54,3 +54,19 @@ select collation(a), collation(b), collation(binary 'ccc') from t1 limit 1;
collation(a) collation(b) collation(binary 'ccc')
cp1251_bin binary binary
drop table t1;
+create table t1 (
+a varchar(16) character set cp1251 collate cp1251_bin not null,
+b int(10) default null,
+primary key(a)
+) charset=cp1251;
+insert into t1 (a) values ('air'),
+('we'),('g'),('we_toshko'), ('s0urce'),('we_ivo'),('we_iliyan'),
+('we_martin'),('vw_grado'),('vw_vasko'),('tn_vili'),('tn_kalina'),
+('tn_fakira'),('vw_silvia'),('vw_starshi'),('vw_geo'),('vw_b0x1');
+select * from t1 where a like 'we_%';
+a b
+we_iliyan NULL
+we_ivo NULL
+we_martin NULL
+we_toshko NULL
+drop table t1;
diff --git a/mysql-test/r/drop_temp_table.result b/mysql-test/r/drop_temp_table.result
index e3561ef9d07..26b8511661a 100644
--- a/mysql-test/r/drop_temp_table.result
+++ b/mysql-test/r/drop_temp_table.result
@@ -18,5 +18,4 @@ master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`drop-temp+table-test`.`shortn1`
-master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a")
drop database `drop-temp+table-test`;
diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result
index 4ed0b45a4c5..00c52a53c42 100644
--- a/mysql-test/r/federated.result
+++ b/mysql-test/r/federated.result
@@ -5,23 +5,40 @@ reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
stop slave;
-drop database if exists federated;
-create database federated;
-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`)) DEFAULT CHARSET=latin1;
-drop database if exists federated;
-create database federated;
-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`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, other) values ('First Name', 11111);
-insert into federated.t1 (name, other) values ('Second Name', 22222);
-insert into federated.t1 (name, other) values ('Third Name', 33333);
-insert into federated.t1 (name, other) values ('Fourth Name', 44444);
-insert into federated.t1 (name, other) values ('Fifth Name', 55555);
-insert into federated.t1 (name, other) values ('Sixth Name', 66666);
-insert into federated.t1 (name, other) values ('Seventh Name', 77777);
-insert into federated.t1 (name, other) values ('Eigth Name', 88888);
-insert into federated.t1 (name, other) values ('Ninth Name', 99999);
-insert into federated.t1 (name, other) values ('Tenth Name', 101010);
-select * from federated.t1;
+DROP DATABASE IF EXISTS federated;
+CREATE DATABASE federated;
+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`))
+DEFAULT CHARSET=latin1;
+DROP DATABASE IF EXISTS federated;
+CREATE DATABASE federated;
+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`))
+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);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES ('Fourth Name', 44444);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name, other) VALUES ('Seventh Name', 77777);
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (name, other) VALUES ('Tenth Name', 101010);
+SELECT * FROM federated.t1;
id name other created
1 First Name 11111 2004-04-04 04:04:04
2 Second Name 22222 2004-04-04 04:04:04
@@ -33,19 +50,19 @@ id name other created
8 Eigth Name 88888 2004-04-04 04:04:04
9 Ninth Name 99999 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
-select * from federated.t1 where id = 5;
+SELECT * FROM federated.t1 WHERE id = 5;
id name other created
5 Fifth Name 55555 2004-04-04 04:04:04
-select * from federated.t1 where name = 'Sixth Name';
+SELECT * FROM federated.t1 WHERE name = 'Sixth Name';
id name other created
6 Sixth Name 66666 2004-04-04 04:04:04
-select * from federated.t1 where id = 6 and name = 'Sixth Name';
+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 other = 44444;
id name other created
4 Fourth Name 44444 2004-04-04 04:04:04
-select * from federated.t1 where name like '%th%';
+SELECT * FROM federated.t1 WHERE name like '%th%';
id name other created
3 Third Name 33333 2004-04-04 04:04:04
4 Fourth Name 44444 2004-04-04 04:04:04
@@ -55,15 +72,15 @@ id name other created
8 Eigth Name 88888 2004-04-04 04:04:04
9 Ninth Name 99999 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
-update federated.t1 set name = '3rd name' where id = 3;
-select * from federated.t1 where name = '3rd name';
+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-04-04 04:04:04
-update federated.t1 set name = 'Third name' where name = '3rd name';
-select * from federated.t1 where name = 'Third name';
+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-04-04 04:04:04
-select * from federated.t1 order by id DESC;
+SELECT * FROM federated.t1 ORDER BY id DESC;
id name other created
10 Tenth Name 101010 2004-04-04 04:04:04
9 Ninth Name 99999 2004-04-04 04:04:04
@@ -75,7 +92,7 @@ id name other created
3 Third name 33333 2004-04-04 04:04:04
2 Second Name 22222 2004-04-04 04:04:04
1 First Name 11111 2004-04-04 04:04:04
-select * from federated.t1 order by name;
+SELECT * FROM federated.t1 ORDER BY name;
id name other created
8 Eigth Name 88888 2004-04-04 04:04:04
5 Fifth Name 55555 2004-04-04 04:04:04
@@ -87,7 +104,7 @@ id name other created
6 Sixth Name 66666 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
3 Third name 33333 2004-04-04 04:04:04
-select * from federated.t1 order by name DESC;
+SELECT * FROM federated.t1 ORDER BY name DESC;
id name other created
3 Third name 33333 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
@@ -99,7 +116,7 @@ id name other created
1 First Name 11111 2004-04-04 04:04:04
5 Fifth Name 55555 2004-04-04 04:04:04
8 Eigth Name 88888 2004-04-04 04:04:04
-select * from federated.t1 order by name ASC;
+SELECT * FROM federated.t1 ORDER BY name ASC;
id name other created
8 Eigth Name 88888 2004-04-04 04:04:04
5 Fifth Name 55555 2004-04-04 04:04:04
@@ -111,7 +128,7 @@ id name other created
6 Sixth Name 66666 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
3 Third name 33333 2004-04-04 04:04:04
-select * from federated.t1 group by other;
+SELECT * FROM federated.t1 GROUP BY other;
id name other created
1 First Name 11111 2004-04-04 04:04:04
2 Second Name 22222 2004-04-04 04:04:04
@@ -123,52 +140,65 @@ id name other created
8 Eigth Name 88888 2004-04-04 04:04:04
9 Ninth Name 99999 2004-04-04 04:04:04
10 Tenth Name 101010 2004-04-04 04:04:04
-delete from federated.t1 where id = 5;
-select * from federated.t1 where id = 5;
+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;
+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), `other` varchar(20), PRIMARY KEY (`id`) );
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, other) values ('First Name', 11111);
-insert into federated.t1 (name, other) values ('Second Name', NULL);
-insert into federated.t1 (name, other) values ('Third Name', 33333);
-insert into federated.t1 (name, other) values (NULL, NULL);
-insert into federated.t1 (name, other) values ('Fifth Name', 55555);
-insert into federated.t1 (name, other) values ('Sixth Name', 66666);
-insert into federated.t1 (name) values ('Seventh Name');
-insert into federated.t1 (name, other) values ('Eigth Name', 88888);
-insert into federated.t1 (name, other) values ('Ninth Name', 99999);
-insert into federated.t1 (other) values ('fee fie foe fum');
-select * from federated.t1 where other IS NULL;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32),
+`other` varchar(20),
+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);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES (NULL, NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name) VALUES ('Seventh Name');
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (other) VALUES ('fee fie foe fum');
+SELECT * FROM federated.t1 WHERE other IS NULL;
id name other
2 Second Name NULL
4 NULL NULL
7 Seventh Name NULL
-select * from federated.t1 where name IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL;
id name other
4 NULL NULL
10 NULL fee fie foe fum
-select * from federated.t1 where name IS NULL and other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL and other IS NULL;
id name other
4 NULL NULL
-select * from federated.t1 where name IS NULL or other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL or other IS NULL;
id name other
2 Second Name NULL
4 NULL NULL
7 Seventh Name NULL
10 NULL fee fie foe fum
-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 name = 'Tenth Name' where other like 'fee fie%';
-select * from federated.t1 where name IS NULL or other IS NULL ;
+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 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;
+SELECT * FROM federated.t1;
id name other
1 First Name 11111
2 Second Name seven seven
@@ -180,149 +210,206 @@ id name other
8 Eigth Name 88888
9 Ninth Name 99999
10 Tenth Name fee fie foe fum
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name`
-varchar(32) NOT NULL DEFAULT '', `other` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`id`), key nameoth (name, other) );
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32) NOT NULL DEFAULT '', `other` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`id`), key nameoth (name, other)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, other) values ('First Name', '1111');
-insert into federated.t1 (name, other) values ('Second Name', '2222');
-insert into federated.t1 (name, other) values ('Third Name', '3333');
-select * from federated.t1 where name = 'Second Name';
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL DEFAULT '',
+`other` varchar(20) NOT NULL DEFAULT '',
+PRIMARY KEY (`id`),
+KEY nameoth (name, other) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`name` varchar(32) NOT NULL DEFAULT '',
+`other` varchar(20) NOT NULL DEFAULT '',
+PRIMARY KEY (`id`),
+KEY nameoth (name, other))
+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', '1111');
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222');
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', '3333');
+SELECT * FROM federated.t1 WHERE name = 'Second Name';
id name other
2 Second Name 2222
-select * from federated.t1 where other = '2222';
+SELECT * FROM federated.t1 WHERE other = '2222';
id name other
2 Second Name 2222
-select * from federated.t1 where name = 'Third Name';
+SELECT * FROM federated.t1 WHERE name = 'Third Name';
id name other
3 Third Name 3333
-select * from federated.t1 where name = 'Third Name' and other = '3333';
+SELECT * FROM federated.t1 WHERE name = 'Third Name' AND other = '3333';
id name other
3 Third Name 3333
-drop table if exists federated.t1;
-CREATE TABLE federated.t1
-(id int NOT NULL auto_increment,
-name char(32) NOT NULL DEFAULT '',
-bincol binary(4) NOT NULL,
-floatval decimal(5,2) NOT NULL DEFAULT 0.0,
-other int NOT NULL DEFAULT 0,
-primary key(id),
-key nameoth(name, other),
-key bincol(bincol),
-key floatval(floatval));
-drop table if exists federated.t1;
-CREATE TABLE federated.t1
-(id int NOT NULL auto_increment,
-name char(32) NOT NULL DEFAULT '',
-bincol binary(4) NOT NULL,
-floatval decimal(5,2) NOT NULL DEFAULT 0.0,
-other int NOT NULL DEFAULT 0,
-primary key(id),
-key nameoth(name,other),
-key bincol(bincol),
-key floatval(floatval))
-ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, bincol, floatval, other) values ('first', 0x65, 11.11, 1111);
-insert into federated.t1 (name, bincol, floatval, other) values ('second', 0x66, 22.22, 2222);
-insert into federated.t1 (name, bincol, floatval, other) values ('third', 'g', 22.22, 2222);
-select * from federated.t1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int NOT NULL auto_increment,
+`name` char(32) NOT NULL DEFAULT '',
+`bincol` binary(4) NOT NULL,
+`floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+`other` int NOT NULL DEFAULT 0,
+PRIMARY KEY (id),
+KEY nameoth(name, other),
+KEY bincol(bincol),
+KEY floatval(floatval));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int NOT NULL auto_increment,
+`name` char(32) NOT NULL DEFAULT '',
+`bincol` binary(4) NOT NULL,
+`floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+`other` int NOT NULL DEFAULT 0,
+PRIMARY KEY (id),
+KEY nameoth(name,other),
+KEY bincol(bincol),
+KEY floatval(floatval))
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('first', 0x65, 11.11, 1111);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('second', 0x66, 22.22, 2222);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+VALUES ('third', 'g', 22.22, 2222);
+SELECT * FROM federated.t1;
id name bincol floatval other
1 first e 11.11 1111
2 second f 22.22 2222
3 third g 22.22 2222
-select * from federated.t1 where name = 'second';
+SELECT * FROM federated.t1 WHERE name = 'second';
id name bincol floatval other
2 second f 22.22 2222
-select * from federated.t1 where bincol= 'f';
+SELECT * FROM federated.t1 WHERE bincol= 'f';
id name bincol floatval other
2 second f 22.22 2222
-select * from federated.t1 where bincol= 0x66;
+SELECT * FROM federated.t1 WHERE bincol= 0x66;
id name bincol floatval other
2 second f 22.22 2222
-select * from federated.t1 where bincol= 0x67;
+SELECT * FROM federated.t1 WHERE bincol= 0x67;
id name bincol floatval other
3 third g 22.22 2222
-select * from federated.t1 where bincol= 'g';
+SELECT * FROM federated.t1 WHERE bincol= 'g';
id name bincol floatval other
3 third g 22.22 2222
-select * from federated.t1 where floatval=11.11;
+SELECT * FROM federated.t1 WHERE floatval=11.11;
id name bincol floatval other
1 first e 11.11 1111
-select * from federated.t1 where name='third';
+SELECT * FROM federated.t1 WHERE name='third';
id name bincol floatval other
3 third g 22.22 2222
-select * from federated.t1 where other=2222;
+SELECT * FROM federated.t1 WHERE other=2222;
id name bincol floatval other
2 second f 22.22 2222
3 third g 22.22 2222
-select * from federated.t1 where name='third' and other=2222;
+SELECT * FROM federated.t1 WHERE name='third' and other=2222;
id name bincol floatval other
3 third g 22.22 2222
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 (id int, name varchar(32), floatval float, other int) DEFAULT CHARSET=latin1;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 (id int, name varchar(32), floatval float, other int) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 values (NULL, NULL, NULL, NULL);
-insert into federated.t1 values ();
-insert into federated.t1 (id) values (1);
-insert into federated.t1 (name, floatval, other) values ('foo', 33.33333332, NULL);
-insert into federated.t1 (name, floatval, other) values (0, 00.3333, NULL);
-select * from federated.t1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int,
+`name` varchar(32),
+`floatval` float,
+`other` int)
+DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int,
+`name` varchar(32),
+`floatval` float,
+`other` int)
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL);
+INSERT INTO federated.t1 values ();
+INSERT INTO federated.t1 (id) VALUES (1);
+INSERT INTO federated.t1 (name, floatval, other)
+VALUES ('foo', 33.33333332, NULL);
+INSERT INTO federated.t1 (name, floatval, other)
+VALUES (0, 00.3333, NULL);
+SELECT * FROM federated.t1;
id name floatval other
NULL NULL NULL NULL
NULL NULL NULL NULL
1 NULL NULL NULL
NULL foo 33.3333 NULL
NULL 0 0.3333 NULL
-select count(*) from federated.t1 where id IS NULL and name IS NULL and floatval IS NULL and other IS NULL;
+SELECT count(*) FROM federated.t1
+WHERE id IS NULL
+AND name IS NULL
+AND floatval IS NULL
+AND other IS NULL;
count(*)
2
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( blurb_id int NOT NULL DEFAULT 0, blurb text default '', primary key(blurb_id)) DEFAULT CHARSET=latin1;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( blurb_id int NOT NULL DEFAULT 0, blurb text default '', primary key(blurb_id)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`blurb_id` int NOT NULL DEFAULT 0,
+`blurb` text default '',
+PRIMARY KEY (blurb_id))
+DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`blurb_id` int NOT NULL DEFAULT 0,
+`blurb` text default '',
+PRIMARY KEY (blurb_id))
+ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.");
INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.");
INSERT INTO federated.t1 VALUES (3, " A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined. ");
INSERT INTO federated.t1 VALUES(4, "Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:");
-select * from federated.t1;
+SELECT * FROM federated.t1;
blurb_id blurb
1 MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.
2 All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.
3 A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined.
4 Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:
-drop table if exists federated.t1;
-create table federated.t1 (a int not null, b int not null, c int not null, primary key (a),key(b));
-drop table if exists federated.t1;
-create table federated.t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/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;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` int NOT NULL,
+`b` int NOT NULL,
+`c` int NOT NULL,
+PRIMARY KEY (a),key(b));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` int NOT NULL,
+`b` int NOT NULL,
+`c` int NOT NULL,
+PRIMARY KEY (a),
+KEY (b))
+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;
+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;
+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;
+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;
+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;
+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;
+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;
+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
+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
int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
@@ -447,10 +534,11 @@ int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
int, i999 int, i1000 int, b blob) row_format=dynamic;
-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
-int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+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 int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
@@ -572,8 +660,13 @@ int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
-int, i999 int, i1000 int, b blob) row_format=dynamic ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+int, i999 int, i1000 int, b blob)
+row_format=dynamic
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1
+values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -612,64 +705,108 @@ insert into federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "PatrickG");
-update federated.t1 set b=repeat('a',256);
-update federated.t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
-select * from federated.t1 where i9=0 and i10=0;
+UPDATE federated.t1 SET b=repeat('a',256);
+UPDATE federated.t1 SET i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
+SELECT * FROM federated.t1 WHERE i9=0 and i10=0;
i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 PatrickG
-update federated.t1 set i50=20;
-select * from federated.t1;
+UPDATE federated.t1 SET i50=20;
+SELECT * FROM federated.t1;
i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 PatrickG
-delete from federated.t1 where i51=20;
-select * from federated.t1;
+DELETE FROM federated.t1 WHERE i51=20;
+SELECT * FROM federated.t1;
i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 PatrickG
-delete from federated.t1 where i50=20;
-select * from federated.t1;
+DELETE FROM federated.t1 WHERE i50=20;
+SELECT * FROM federated.t1;
i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 i21 i22 i23 i24 i25 i26 i27 i28 i29 i30 i31 i32 i33 i34 i35 i36 i37 i38 i39 i40 i41 i42 i43 i44 i45 i46 i47 i48 i49 i50 i51 i52 i53 i54 i55 i56 i57 i58 i59 i60 i61 i62 i63 i64 i65 i66 i67 i68 i69 i70 i71 i72 i73 i74 i75 i76 i77 i78 i79 i80 i81 i82 i83 i84 i85 i86 i87 i88 i89 i90 i91 i92 i93 i94 i95 i96 i97 i98 i99 i100 i101 i102 i103 i104 i105 i106 i107 i108 i109 i110 i111 i112 i113 i114 i115 i116 i117 i118 i119 i120 i121 i122 i123 i124 i125 i126 i127 i128 i129 i130 i131 i132 i133 i134 i135 i136 i137 i138 i139 i140 i141 i142 i143 i144 i145 i146 i147 i148 i149 i150 i151 i152 i153 i154 i155 i156 i157 i158 i159 i160 i161 i162 i163 i164 i165 i166 i167 i168 i169 i170 i171 i172 i173 i174 i175 i176 i177 i178 i179 i180 i181 i182 i183 i184 i185 i186 i187 i188 i189 i190 i191 i192 i193 i194 i195 i196 i197 i198 i199 i200 i201 i202 i203 i204 i205 i206 i207 i208 i209 i210 i211 i212 i213 i214 i215 i216 i217 i218 i219 i220 i221 i222 i223 i224 i225 i226 i227 i228 i229 i230 i231 i232 i233 i234 i235 i236 i237 i238 i239 i240 i241 i242 i243 i244 i245 i246 i247 i248 i249 i250 i251 i252 i253 i254 i255 i256 i257 i258 i259 i260 i261 i262 i263 i264 i265 i266 i267 i268 i269 i270 i271 i272 i273 i274 i275 i276 i277 i278 i279 i280 i281 i282 i283 i284 i285 i286 i287 i288 i289 i290 i291 i292 i293 i294 i295 i296 i297 i298 i299 i300 i301 i302 i303 i304 i305 i306 i307 i308 i309 i310 i311 i312 i313 i314 i315 i316 i317 i318 i319 i320 i321 i322 i323 i324 i325 i326 i327 i328 i329 i330 i331 i332 i333 i334 i335 i336 i337 i338 i339 i340 i341 i342 i343 i344 i345 i346 i347 i348 i349 i350 i351 i352 i353 i354 i355 i356 i357 i358 i359 i360 i361 i362 i363 i364 i365 i366 i367 i368 i369 i370 i371 i372 i373 i374 i375 i376 i377 i378 i379 i380 i381 i382 i383 i384 i385 i386 i387 i388 i389 i390 i391 i392 i393 i394 i395 i396 i397 i398 i399 i400 i401 i402 i403 i404 i405 i406 i407 i408 i409 i410 i411 i412 i413 i414 i415 i416 i417 i418 i419 i420 i421 i422 i423 i424 i425 i426 i427 i428 i429 i430 i431 i432 i433 i434 i435 i436 i437 i438 i439 i440 i441 i442 i443 i444 i445 i446 i447 i448 i449 i450 i451 i452 i453 i454 i455 i456 i457 i458 i459 i460 i461 i462 i463 i464 i465 i466 i467 i468 i469 i470 i471 i472 i473 i474 i475 i476 i477 i478 i479 i480 i481 i482 i483 i484 i485 i486 i487 i488 i489 i490 i491 i492 i493 i494 i495 i496 i497 i498 i499 i500 i501 i502 i503 i504 i505 i506 i507 i508 i509 i510 i511 i512 i513 i514 i515 i516 i517 i518 i519 i520 i521 i522 i523 i524 i525 i526 i527 i528 i529 i530 i531 i532 i533 i534 i535 i536 i537 i538 i539 i540 i541 i542 i543 i544 i545 i546 i547 i548 i549 i550 i551 i552 i553 i554 i555 i556 i557 i558 i559 i560 i561 i562 i563 i564 i565 i566 i567 i568 i569 i570 i571 i572 i573 i574 i575 i576 i577 i578 i579 i580 i581 i582 i583 i584 i585 i586 i587 i588 i589 i590 i591 i592 i593 i594 i595 i596 i597 i598 i599 i600 i601 i602 i603 i604 i605 i606 i607 i608 i609 i610 i611 i612 i613 i614 i615 i616 i617 i618 i619 i620 i621 i622 i623 i624 i625 i626 i627 i628 i629 i630 i631 i632 i633 i634 i635 i636 i637 i638 i639 i640 i641 i642 i643 i644 i645 i646 i647 i648 i649 i650 i651 i652 i653 i654 i655 i656 i657 i658 i659 i660 i661 i662 i663 i664 i665 i666 i667 i668 i669 i670 i671 i672 i673 i674 i675 i676 i677 i678 i679 i680 i681 i682 i683 i684 i685 i686 i687 i688 i689 i690 i691 i692 i693 i694 i695 i696 i697 i698 i699 i700 i701 i702 i703 i704 i705 i706 i707 i708 i709 i710 i711 i712 i713 i714 i715 i716 i717 i718 i719 i720 i721 i722 i723 i724 i725 i726 i727 i728 i729 i730 i731 i732 i733 i734 i735 i736 i737 i738 i739 i740 i741 i742 i743 i744 i745 i746 i747 i748 i749 i750 i751 i752 i753 i754 i755 i756 i757 i758 i759 i760 i761 i762 i763 i764 i765 i766 i767 i768 i769 i770 i771 i772 i773 i774 i775 i776 i777 i778 i779 i780 i781 i782 i783 i784 i785 i786 i787 i788 i789 i790 i791 i792 i793 i794 i795 i796 i797 i798 i799 i800 i801 i802 i803 i804 i805 i806 i807 i808 i809 i810 i811 i812 i813 i814 i815 i816 i817 i818 i819 i820 i821 i822 i823 i824 i825 i826 i827 i828 i829 i830 i831 i832 i833 i834 i835 i836 i837 i838 i839 i840 i841 i842 i843 i844 i845 i846 i847 i848 i849 i850 i851 i852 i853 i854 i855 i856 i857 i858 i859 i860 i861 i862 i863 i864 i865 i866 i867 i868 i869 i870 i871 i872 i873 i874 i875 i876 i877 i878 i879 i880 i881 i882 i883 i884 i885 i886 i887 i888 i889 i890 i891 i892 i893 i894 i895 i896 i897 i898 i899 i900 i901 i902 i903 i904 i905 i906 i907 i908 i909 i910 i911 i912 i913 i914 i915 i916 i917 i918 i919 i920 i921 i922 i923 i924 i925 i926 i927 i928 i929 i930 i931 i932 i933 i934 i935 i936 i937 i938 i939 i940 i941 i942 i943 i944 i945 i946 i947 i948 i949 i950 i951 i952 i953 i954 i955 i956 i957 i958 i959 i960 i961 i962 i963 i964 i965 i966 i967 i968 i969 i970 i971 i972 i973 i974 i975 i976 i977 i978 i979 i980 i981 i982 i983 i984 i985 i986 i987 i988 i989 i990 i991 i992 i993 i994 i995 i996 i997 i998 i999 i1000 b
-drop table if exists federated.t1;
-create table federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', primary key(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
-drop table if exists federated.t1;
-create table federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', primary key(id), index(code), index(fileguts(10))) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (code, fileguts, creation_date) values ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
-insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
-insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
-select * from federated.t1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', PRIMARY KEY(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+id int NOT NULL auto_increment,
+code char(20) NOT NULL,
+fileguts blob NOT NULL,
+creation_date datetime,
+entered_time datetime default '2004-04-04 04:04:04',
+PRIMARY KEY(id),
+index(code),
+index(fileguts(10)))
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
+SELECT * FROM federated.t1;
id code fileguts creation_date entered_time
1 ASDFWERQWETWETAWETA *()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[ 2003-03-03 03:03:03 2004-04-04 04:04:04
2 DEUEUEUEUEUEUEUEUEU *()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[ 2004-04-04 04:04:04 2004-04-04 04:04:04
3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04
-select * from federated.t1 where fileguts = 'jimbob';
+SELECT * FROM federated.t1 WHERE fileguts = 'jimbob';
id code fileguts creation_date entered_time
3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id));
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111);
-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);
-drop table if exists federated.countries;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (`a` BLOB);
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`a` BLOB)
+ENGINE="FEDERATED"
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 VALUES (0x00);
+INSERT INTO federated.t1 VALUES (0x0001);
+INSERT INTO federated.t1 VALUES (0x0100);
+SELECT HEX(a) FROM federated.t1;
+HEX(a)
+00
+0001
+0100
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`country_id` int(20) NOT NULL DEFAULT 0,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`),
+key (country_id));
+DROP TABLE IF EXISTS federated.countries;
Warnings:
Note 1051 Unknown table 'countries'
-CREATE TABLE federated.countries ( `id` int(20) NOT NULL auto_increment, `country` varchar(32), primary key (id));
-insert into federated.countries (country) values ('India');
-insert into federated.countries (country) values ('Germany');
-insert into federated.countries (country) values ('Italy');
-insert into federated.countries (country) values ('Finland');
-insert into federated.countries (country) values ('Ukraine');
-select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id;
+CREATE TABLE federated.countries (
+`id` int(20) NOT NULL auto_increment,
+`country` varchar(32),
+PRIMARY KEY (id));
+INSERT INTO federated.countries (country) VALUES ('India');
+INSERT INTO federated.countries (country) VALUES ('Germany');
+INSERT INTO federated.countries (country) VALUES ('Italy');
+INSERT INTO federated.countries (country) VALUES ('Finland');
+INSERT INTO federated.countries (country) VALUES ('Ukraine');
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+`id` int(20) NOT NULL auto_increment,
+`country_id` int(20) NOT NULL DEFAULT 0,
+`name` varchar(32),
+`other` varchar(20),
+PRIMARY KEY (`id`),
+KEY (country_id) )
+ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111);
+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);
+SELECT federated.t1.*, federated.countries.country
+FROM federated.t1 left join federated.countries
+ON federated.t1.country_id = federated.countries.id;
id country_id name other country
1 1 Kumar 11111 India
2 2 Lenz 22222 Germany
3 3 Marizio 33333 Italy
4 4 Monty 33333 Finland
5 5 Sanja 33333 Ukraine
-drop table federated.countries;
-drop table if exists federated.t1;
-drop database if exists federated;
-drop table if exists federated.t1;
-drop database if exists federated;
+DROP TABLE federated.countries;
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index 017a6a239df..ba769a0b23d 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -669,12 +669,24 @@ select charset(max(a)), coercibility(max(a)),
charset(min(a)), coercibility(min(a)) from t1;
charset(max(a)) coercibility(max(a)) charset(min(a)) coercibility(min(a))
latin2 2 latin2 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(1) character set latin2 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
create table t2 select max(a),min(a) from t1;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
- `max(a)` varchar(1) character set latin2 default NULL,
- `min(a)` varchar(1) character set latin2 default NULL
+ `max(a)` char(1) character set latin2 default NULL,
+ `min(a)` char(1) character set latin2 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2;
+create table t2 select concat(a) from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `concat(a)` varchar(1) character set latin2 default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t2,t1;
create table t1 (a int);
@@ -757,6 +769,15 @@ one 2
two 2
three 1
drop table t1;
+create table t1(a int, b datetime);
+insert into t1 values (1, NOW()), (2, NOW());
+create table t2 select MAX(b) from t1 group by a;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `MAX(b)` datetime default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1, t2;
create table t1(f1 datetime);
insert into t1 values (now());
create table t2 select f2 from (select max(now()) f2 from t1) a;
@@ -811,3 +832,29 @@ id stddev_pop(value1) var_pop(value1) stddev_samp(value1) var_samp(value1)
1 0.816497 0.666667 1.000000 1.000000
2 1.118034 1.250000 1.290994 1.666667
DROP TABLE t1;
+CREATE TABLE t1(
+id int PRIMARY KEY,
+a int,
+b int,
+INDEX i_b_id(a,b,id),
+INDEX i_id(a,id)
+);
+INSERT INTO t1 VALUES
+(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
+SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
+MAX(id)
+NULL
+DROP TABLE t1;
+CREATE TABLE t1(
+id int PRIMARY KEY,
+a int,
+b int,
+INDEX i_id(a,id),
+INDEX i_b_id(a,b,id)
+);
+INSERT INTO t1 VALUES
+(1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
+SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
+MAX(id)
+NULL
+DROP TABLE t1;
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 85a0c2c55f9..9b93fe2ad1c 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -467,97 +467,97 @@ select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE la
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_swedish_ci,COERCIBLE), (latin1_bin,EXPLICIT) for operation ' IN '
select collation(bin(130)), coercibility(bin(130));
collation(bin(130)) coercibility(bin(130))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(oct(130)), coercibility(oct(130));
collation(oct(130)) coercibility(oct(130))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(conv(130,16,10)), coercibility(conv(130,16,10));
collation(conv(130,16,10)) coercibility(conv(130,16,10))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(hex(130)), coercibility(hex(130));
collation(hex(130)) coercibility(hex(130))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(char(130)), coercibility(hex(130));
collation(char(130)) coercibility(hex(130))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(format(130,10)), coercibility(format(130,10));
collation(format(130,10)) coercibility(format(130,10))
-latin1_swedish_ci 3
+latin1_swedish_ci 4
select collation(lcase(_latin2'a')), coercibility(lcase(_latin2'a'));
collation(lcase(_latin2'a')) coercibility(lcase(_latin2'a'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(ucase(_latin2'a')), coercibility(ucase(_latin2'a'));
collation(ucase(_latin2'a')) coercibility(ucase(_latin2'a'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(left(_latin2'a',1)), coercibility(left(_latin2'a',1));
collation(left(_latin2'a',1)) coercibility(left(_latin2'a',1))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(right(_latin2'a',1)), coercibility(right(_latin2'a',1));
collation(right(_latin2'a',1)) coercibility(right(_latin2'a',1))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(substring(_latin2'a',1,1)), coercibility(substring(_latin2'a',1,1));
collation(substring(_latin2'a',1,1)) coercibility(substring(_latin2'a',1,1))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(concat(_latin2'a',_latin2'b')), coercibility(concat(_latin2'a',_latin2'b'));
collation(concat(_latin2'a',_latin2'b')) coercibility(concat(_latin2'a',_latin2'b'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(lpad(_latin2'a',4,_latin2'b')), coercibility(lpad(_latin2'a',4,_latin2'b'));
collation(lpad(_latin2'a',4,_latin2'b')) coercibility(lpad(_latin2'a',4,_latin2'b'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(rpad(_latin2'a',4,_latin2'b')), coercibility(rpad(_latin2'a',4,_latin2'b'));
collation(rpad(_latin2'a',4,_latin2'b')) coercibility(rpad(_latin2'a',4,_latin2'b'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(concat_ws(_latin2'a',_latin2'b')), coercibility(concat_ws(_latin2'a',_latin2'b'));
collation(concat_ws(_latin2'a',_latin2'b')) coercibility(concat_ws(_latin2'a',_latin2'b'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')), coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c'));
collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set(255,_latin2'a',_latin2'b',_latin2'c'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' '));
collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')) coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' '))
-binary 3
+binary 4
select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a '));
collation(trim(_latin2' a ')) coercibility(trim(_latin2' a '))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(ltrim(_latin2' a ')), coercibility(ltrim(_latin2' a '));
collation(ltrim(_latin2' a ')) coercibility(ltrim(_latin2' a '))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(rtrim(_latin2' a ')), coercibility(rtrim(_latin2' a '));
collation(rtrim(_latin2' a ')) coercibility(rtrim(_latin2' a '))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(trim(LEADING _latin2' ' FROM _latin2'a')), coercibility(trim(LEADING _latin2'a' FROM _latin2'a'));
collation(trim(LEADING _latin2' ' FROM _latin2'a')) coercibility(trim(LEADING _latin2'a' FROM _latin2'a'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(trim(TRAILING _latin2' ' FROM _latin2'a')), coercibility(trim(TRAILING _latin2'a' FROM _latin2'a'));
collation(trim(TRAILING _latin2' ' FROM _latin2'a')) coercibility(trim(TRAILING _latin2'a' FROM _latin2'a'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(trim(BOTH _latin2' ' FROM _latin2'a')), coercibility(trim(BOTH _latin2'a' FROM _latin2'a'));
collation(trim(BOTH _latin2' ' FROM _latin2'a')) coercibility(trim(BOTH _latin2'a' FROM _latin2'a'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(repeat(_latin2'a',10)), coercibility(repeat(_latin2'a',10));
collation(repeat(_latin2'a',10)) coercibility(repeat(_latin2'a',10))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(reverse(_latin2'ab')), coercibility(reverse(_latin2'ab'));
collation(reverse(_latin2'ab')) coercibility(reverse(_latin2'ab'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(quote(_latin2'ab')), coercibility(quote(_latin2'ab'));
collation(quote(_latin2'ab')) coercibility(quote(_latin2'ab'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(soundex(_latin2'ab')), coercibility(soundex(_latin2'ab'));
collation(soundex(_latin2'ab')) coercibility(soundex(_latin2'ab'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(substring(_latin2'ab',1)), coercibility(substring(_latin2'ab',1));
collation(substring(_latin2'ab',1)) coercibility(substring(_latin2'ab',1))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(insert(_latin2'abcd',2,3,_latin2'ef')), coercibility(insert(_latin2'abcd',2,3,_latin2'ef'));
collation(insert(_latin2'abcd',2,3,_latin2'ef')) coercibility(insert(_latin2'abcd',2,3,_latin2'ef'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(replace(_latin2'abcd',_latin2'b',_latin2'B')), coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B'));
collation(replace(_latin2'abcd',_latin2'b',_latin2'B')) coercibility(replace(_latin2'abcd',_latin2'b',_latin2'B'))
-latin2_general_ci 3
+latin2_general_ci 4
select collation(encode('abcd','ab')), coercibility(encode('abcd','ab'));
collation(encode('abcd','ab')) coercibility(encode('abcd','ab'))
-binary 3
+binary 4
create table t1
select
bin(130),
diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result
index 0f827913780..9aa936f1c78 100644
--- a/mysql-test/r/func_system.result
+++ b/mysql-test/r/func_system.result
@@ -68,3 +68,11 @@ drop table t1;
select TRUE,FALSE,NULL;
TRUE FALSE NULL
1 0 NULL
+create table t1 (a char(10)) character set latin1;
+select * from t1 where a=version();
+a
+select * from t1 where a=database();
+a
+select * from t1 where a=user();
+a
+drop table t1;
diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result
index 0779e2adfa2..821f67536f3 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -233,3 +233,20 @@ drop user mysqltest_B@'%';
ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql'
drop user mysqltest_B@'%';
drop user mysqltest_3@localhost;
+set @@sql_mode='';
+create database mysqltest_1;
+create table mysqltest_1.t1 (i int);
+insert into mysqltest_1.t1 values (1),(2),(3);
+GRANT ALL ON mysqltest_1.t1 TO mysqltest_1@'127.0.0.0/255.0.0.0';
+show grants for current_user();
+Grants for mysqltest_1@127.0.0.0/255.0.0.0
+GRANT USAGE ON *.* TO 'mysqltest_1'@'127.0.0.0/255.0.0.0'
+GRANT ALL PRIVILEGES ON `mysqltest_1`.`t1` TO 'mysqltest_1'@'127.0.0.0/255.0.0.0'
+select * from t1;
+i
+1
+2
+3
+REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0';
+drop table mysqltest_1.t1;
+drop database mysqltest_1;
diff --git a/mysql-test/r/have_cp1250_ch.require b/mysql-test/r/have_cp1250_ch.require
new file mode 100644
index 00000000000..2eb834d97e2
--- /dev/null
+++ b/mysql-test/r/have_cp1250_ch.require
@@ -0,0 +1,2 @@
+Collation Charset Id Default Compiled Sortlen
+cp1250_czech_cs cp1250 34 Yes 2
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 121de940560..0e72de7ab12 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1,7 +1,8 @@
show variables where variable_name like "skip_show_database";
Variable_name Value
skip_show_database OFF
-grant all privileges on test.* to mysqltest_1@localhost;
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
select * from information_schema.SCHEMATA where schema_name > 'm';
CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH
NULL mysql latin1 NULL
@@ -229,6 +230,44 @@ sel2 sel2
select count(*) from information_schema.ROUTINES;
count(*)
2
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+show create function sub1;
+ERROR 42000: FUNCTION sub1 does not exist
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+grant all privileges on test.* to mysqltest_1@localhost;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+create function sub2(i int) returns int
+return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+sub2 return i+1
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2
+show create function sub1;
+Function sql_mode Create Function
+sub1
+show create function sub2;
+Function sql_mode Create Function
+sub2 CREATE FUNCTION `test`.`sub2`(i int) RETURNS int
+return i+1
+drop function sub2;
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2 CREATE PROCEDURE `test`.`sel2`()
+begin
+select * from t1;
+select * from t2;
+end
create view v0 (c) as select schema_name from information_schema.schemata;
select * from v0;
c
@@ -311,8 +350,8 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRAN
'mysqltest_1'@'localhost' NULL test t1 a INSERT NO
'mysqltest_1'@'localhost' NULL test t1 a UPDATE NO
'mysqltest_1'@'localhost' NULL test t1 a REFERENCES NO
-delete from mysql.user where user='mysqltest_1';
-delete from mysql.db where user='mysqltest_1';
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
@@ -631,3 +670,10 @@ TABLES UPDATE_TIME datetime
TABLES CHECK_TIME datetime
ROUTINES CREATED datetime
ROUTINES LAST_ALTERED datetime
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A
+WHERE NOT EXISTS
+(SELECT * FROM INFORMATION_SCHEMA.COLUMNS B
+WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+AND A.TABLE_NAME = B.TABLE_NAME);
+COUNT(*)
+0
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index c63c869219a..2c285efafaf 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -906,6 +906,7 @@ truncate table t1;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
commit;
truncate table t1;
+truncate table t1;
select * from t1;
a
insert into t1 values(1),(2);
@@ -924,6 +925,7 @@ a
1
2
truncate table t1;
+truncate table t1;
insert into t1 values(1),(2);
delete from t1;
select * from t1;
@@ -1637,14 +1639,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 152
+Binlog_cache_use 154
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 153
+Binlog_cache_use 155
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@@ -1653,7 +1655,7 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 154
+Binlog_cache_use 156
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result
index db2842061b4..16c92fa201f 100644
--- a/mysql-test/r/lock.result
+++ b/mysql-test/r/lock.result
@@ -42,7 +42,7 @@ check table t2;
Table Op Msg_type Msg_text
test.t2 check error Table 't2' was not locked with LOCK TABLES
insert into t1 select index1,nr from t1;
-ERROR 42000: INSERT command denied to user 'root'@'localhost' for column 'index1' in table 't1'
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
unlock tables;
lock tables t1 write, t1 as t1_alias read;
insert into t1 select index1,nr from t1 as t1_alias;
diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result
index d4ff95e4e29..53cd61f8a2e 100644
--- a/mysql-test/r/mix_innodb_myisam_binlog.result
+++ b/mysql-test/r/mix_innodb_myisam_binlog.result
@@ -93,7 +93,6 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 165 Query 1 # use `test`; insert into t1 values(8)
master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 348 Query 1 # use `test`; ROLLBACK
-master-bin.000001 420 Query 1 # use `test`; DO RELEASE_LOCK("a")
delete from t1;
delete from t2;
reset master;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index b0cb6462252..73550d97dad 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -568,6 +568,24 @@ select count(*) from t1 where a is null;
count(*)
2
drop table t1;
+create table t1 (c1 int, index(c1));
+create table t2 (c1 int, index(c1)) engine=merge union=(t1);
+insert into t1 values (1);
+flush tables;
+select * from t2;
+c1
+1
+flush tables;
+truncate table t1;
+insert into t1 values (1);
+flush tables;
+select * from t2;
+c1
+1
+truncate table t1;
+ERROR HY000: MyISAM table 't1' is in use (most likely by a MERGE table). Try FLUSH TABLES.
+insert into t1 values (1);
+drop table t1,t2;
set storage_engine=MyISAM;
drop table if exists t1,t2,t3;
--- Testing varchar ---
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index d8d9e60acd1..ac7f182b4c4 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -1,5 +1,6 @@
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
drop database if exists mysqldump_test_db;
+drop view if exists v1;
CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
<?xml version="1.0"?>
@@ -479,27 +480,6 @@ CREATE TABLE `t1` (
/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
LOCK TABLES `t1` WRITE;
-INSERT INTO `t1` VALUES ('ÄÖÜß');
-UNLOCK TABLES;
-/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO,MYSQL323' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-DROP TABLE IF EXISTS `t1`;
-CREATE TABLE `t1` (
- `a` char(10) default NULL
-) TYPE=MyISAM;
-
-
-/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
-LOCK TABLES `t1` WRITE;
INSERT INTO `t1` VALUES ('Ž™šá');
UNLOCK TABLES;
/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 7fe67eb22fe..5b638fd58ab 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -129,7 +129,7 @@ FOUND_ROWS()
1
execute stmt1;
FOUND_ROWS()
-0
+1
deallocate prepare stmt1;
drop table t1;
create table t1
@@ -487,3 +487,40 @@ insert into t1 values ('foo');
prepare stmt FROM 'SELECT char_length (a) FROM t1';
ERROR 42000: FUNCTION test.char_length does not exist
drop table t1;
+prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0";
+execute stmt;
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+2
+execute stmt;
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+2
+deallocate prepare stmt;
+create table t1 (a char(3) not null, b char(3) not null,
+c char(3) not null, primary key (a, b, c));
+create table t2 like t1;
+prepare stmt from
+"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
+ where t1.a=1";
+execute stmt;
+a
+execute stmt;
+a
+execute stmt;
+a
+prepare stmt from
+"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
+(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
+left outer join t2 t3 on t3.a=? where t1.a=?";
+set @a:=1, @b:=1, @c:=1;
+execute stmt using @a, @b, @c;
+a b c a b c
+execute stmt using @a, @b, @c;
+a b c a b c
+execute stmt using @a, @b, @c;
+a b c a b c
+deallocate prepare stmt;
+drop table t1,t2;
diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result
index eef986d8f8c..74075b188ba 100644
--- a/mysql-test/r/rpl000001.result
+++ b/mysql-test/r/rpl000001.result
@@ -33,27 +33,12 @@ select sum(length(word)) from t1;
sum(length(word))
1022
drop table t1,t3;
+create table t1 (n int) engine=myisam;
reset master;
stop slave;
reset slave;
-create table t1(n int);
-select get_lock("hold_slave",10);
-get_lock("hold_slave",10)
-1
-explain extended select get_lock("hold_slave",10);
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
-Warnings:
-Note 1003 select sql_no_cache get_lock(_latin1'hold_slave',10) AS `get_lock("hold_slave",10)`
+lock tables t1 read;
start slave;
-select release_lock("hold_slave");
-release_lock("hold_slave")
-1
-explain extended select release_lock("hold_slave");
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
-Warnings:
-Note 1003 select sql_no_cache release_lock(_latin1'hold_slave') AS `release_lock("hold_slave")`
unlock tables;
create table t2(id int);
insert into t2 values(connection_id());
diff --git a/mysql-test/r/rpl_change_master.result b/mysql-test/r/rpl_change_master.result
index 033d55140e3..6ffdb15fcf8 100644
--- a/mysql-test/r/rpl_change_master.result
+++ b/mysql-test/r/rpl_change_master.result
@@ -4,26 +4,20 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-select get_lock("a",5);
-get_lock("a",5)
-1
create table t1(n int);
-insert into t1 values(1+get_lock("a",15)*0);
-insert into t1 values(2);
-stop slave;
select * from t1;
n
-1
+stop slave sql_thread;
+insert into t1 values(1);
+insert into t1 values(2);
+stop slave;
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 377 # # master-bin.000001 No No 0 0 289 # None 0 No #
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 358 # # master-bin.000001 No No 0 0 182 # None 0 No #
change master to master_user='root';
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
-# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 289 # # master-bin.000001 No No 0 0 289 # None 0 No #
-select release_lock("a");
-release_lock("a")
-1
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 182 # # master-bin.000001 No No 0 0 182 # None 0 No #
start slave;
select * from t1;
n
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
new file mode 100644
index 00000000000..fd9853a9e5f
--- /dev/null
+++ b/mysql-test/r/rpl_deadlock.result
@@ -0,0 +1,81 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+create table t1 (a int not null, key(a)) engine=innodb;
+create table t2 (a int not null, key(a)) engine=innodb;
+create table t3 (a int) engine=innodb;
+create table t4 (a int) engine=innodb;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+stop slave;
+begin;
+insert into t3 select * from t2 for update;
+insert into t1 values(1);
+commit;
+begin;
+select * from t1 for update;
+a
+start slave;
+insert into t2 values(22);
+commit;
+select * from t1;
+a
+1
+select * from t2;
+a
+22
+show slave status;
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
+stop slave;
+change master to master_log_pos=534;
+begin;
+select * from t2 for update;
+a
+22
+start slave;
+commit;
+select * from t1;
+a
+1
+1
+select * from t2;
+a
+22
+show slave status;
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
+set global max_relay_log_size=0;
+stop slave;
+change master to master_log_pos=534;
+begin;
+select * from t2 for update;
+a
+22
+start slave;
+commit;
+select * from t1;
+a
+1
+1
+1
+select * from t2;
+a
+22
+show slave status;
+Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
+# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
+drop table t1,t2;
diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result
index 1a2d366fb2a..7abd65beb46 100644
--- a/mysql-test/r/select_found.result
+++ b/mysql-test/r/select_found.result
@@ -246,6 +246,31 @@ SELECT FOUND_ROWS();
FOUND_ROWS()
0
DROP TABLE t1;
+SELECT 'foo';
+foo
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+1
+SELECT SQL_CALC_FOUND_ROWS 'foo';
+foo
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+1
+SELECT SQL_CALC_FOUND_ROWS 'foo' limit 0;
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+1
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+1
+SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0;
+foo
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+2
CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5);
SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2;
diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result
index 766ee8c0e14..7a29db42dd9 100644
--- a/mysql-test/r/select_safe.result
+++ b/mysql-test/r/select_safe.result
@@ -78,4 +78,19 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref b b 21 test.t1.b 6 Using where
SET MAX_SEEKS_FOR_KEY=DEFAULT;
drop table t1;
+create table t1 (a int);
+insert into t1 values (1),(2),(3),(4),(5);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+set local max_join_size=8;
+select * from (select * from t1) x;
+ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
+set local max_join_size=1;
+select * from (select * from t1 a, t1 b) x;
+ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
+set local max_join_size=1;
+select * from (select 1 union select 2 union select 3) x;
+ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay
+drop table t1;
SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 53882e6be69..15cae7646f9 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -254,7 +254,7 @@ create table t1 (a int not null);
create table t2 select max(a) from t1;
show columns from t2;
Field Type Null Key Default Extra
-max(a) bigint(20) YES NULL
+max(a) int(11) YES NULL
drop table t1,t2;
create table t1 (c decimal, d double, f float, r real);
show columns from t1;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index b4198a5f467..2ee912aaea7 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -237,6 +237,13 @@ insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3)|
drop procedure if exists sub1|
create procedure sub1(id char(16), x int)
insert into test.t1 values (id, x)|
+drop procedure if exists sub2|
+create procedure sub2(id char(16))
+begin
+declare x int;
+set x = (select sum(t.i) from test.t2 t);
+insert into test.t1 values (id, x);
+end|
drop procedure if exists sub3|
create function sub3(i int) returns int
return i+1|
@@ -244,16 +251,19 @@ call sub1("sub1a", (select 7))|
call sub1("sub1b", (select max(i) from t2))|
call sub1("sub1c", (select i,d from t2 limit 1))|
call sub1("sub1d", (select 1 from (select 1) a))|
+call sub2("sub2");
select * from t1|
id data
sub1a 7
sub1b 3
sub1c 1
sub1d 1
+sub2 6
select sub3((select max(i) from t2))|
sub3((select max(i) from t2))
4
drop procedure sub1|
+drop procedure sub2|
drop function sub3|
delete from t2|
drop procedure if exists a0|
@@ -269,6 +279,7 @@ sub1a 7
sub1b 3
sub1c 1
sub1d 1
+sub2 6
a0 2
a0 1
a0 0
@@ -1045,6 +1056,200 @@ select row_count()|
row_count()
-1
drop procedure rc|
+drop function if exists f0|
+drop function if exists f1|
+drop function if exists f2|
+drop function if exists f3|
+drop function if exists f4|
+drop function if exists f5|
+drop function if exists f6|
+drop function if exists f7|
+drop function if exists f8|
+drop view if exists v0|
+drop view if exists v1|
+drop view if exists v2|
+delete from t1|
+delete from t2|
+insert into t1 values ("a", 1), ("b", 2) |
+insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
+create function f1() returns int
+return (select sum(data) from t1)|
+select f1()|
+f1()
+3
+select id, f1() from t1|
+id f1()
+a 3
+b 3
+create function f2() returns int
+return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
+select f2()|
+f2()
+1
+select id, f2() from t1|
+id f2()
+a 1
+b 1
+create function f3() returns int
+begin
+declare n int;
+declare m int;
+set n:= (select min(data) from t1);
+set m:= (select max(data) from t1);
+return n < m;
+end|
+select f3()|
+f3()
+1
+select id, f3() from t1|
+id f3()
+a 1
+b 1
+select f1(), f3()|
+f1() f3()
+3 1
+select id, f1(), f3() from t1|
+id f1() f3()
+a 3 1
+b 3 1
+create function f4() returns double
+return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
+select f4()|
+f4()
+2
+select s, f4() from t2|
+s f4()
+a 2
+b 2
+c 2
+create function f5(i int) returns int
+begin
+if i <= 0 then
+return 0;
+elseif i = 1 then
+return (select count(*) from t1 where data = i);
+else
+return (select count(*) + f5( i - 1) from t1 where data = i);
+end if;
+end|
+select f5(1)|
+f5(1)
+1
+select f5(2)|
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+create function f6() returns int
+begin
+declare n int;
+set n:= f1();
+return (select count(*) from t1 where data <= f7() and data <= n);
+end|
+create function f7() returns int
+return (select sum(data) from t1 where data <= f1())|
+select f6()|
+f6()
+2
+select id, f6() from t1|
+id f6()
+a 2
+b 2
+create view v1 (a) as select f1()|
+select * from v1|
+a
+3
+select id, a from t1, v1|
+id a
+a 3
+b 3
+select * from v1, v1 as v|
+a a
+3 3
+create view v2 (a) as select a*10 from v1|
+select * from v2|
+a
+30
+select id, a from t1, v2|
+id a
+a 30
+b 30
+select * from v1, v2|
+a a
+3 30
+create function f8 () returns int
+return (select count(*) from v2)|
+select *, f8() from v1|
+a f8()
+3 1
+drop function f1|
+select * from v1|
+ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s)
+create function f1() returns int
+return (select sum(data) from t1) + (select sum(data) from v1)|
+drop function f1|
+create function f1() returns int
+return (select sum(data) from t1)|
+create function f0() returns int
+return (select * from (select 100) as r)|
+select f0()|
+f0()
+100
+select *, f0() from (select 1) as t|
+1 f0()
+1 100
+create view v0 as select f0()|
+select * from v0|
+f0()
+100
+select *, f0() from v0|
+f0() f0()
+100 100
+lock tables t1 read, t1 as t11 read, mysql.proc read|
+select f3()|
+f3()
+1
+select id, f3() from t1 as t11|
+id f3()
+a 1
+b 1
+select f0()|
+f0()
+100
+select * from v0|
+f0()
+100
+select *, f0() from v0, (select 123) as d1|
+f0() 123 f0()
+100 123 100
+select id, f3() from t1|
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+select f4()|
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
+unlock tables|
+lock tables v2 read, mysql.proc read|
+select * from v2|
+a
+30
+select * from v1|
+a
+3
+select * from v1, v2|
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+select f4()|
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
+unlock tables|
+drop function f0|
+drop function f1|
+drop function f2|
+drop function f3|
+drop function f4|
+drop function f5|
+drop function f6|
+drop function f7|
+drop function f8|
+drop view v0|
+drop view v1|
+drop view v2|
+delete from t1 |
+delete from t2 |
drop procedure if exists bug822|
create procedure bug822(a_id char(16), a_data int)
begin
@@ -1177,56 +1382,6 @@ select @x2|
@x2
2
drop procedure bug2260|
-drop procedure if exists bug2267_1|
-create procedure bug2267_1()
-begin
-show procedure status;
-end|
-drop procedure if exists bug2267_2|
-create procedure bug2267_2()
-begin
-show function status;
-end|
-drop procedure if exists bug2267_3|
-create procedure bug2267_3()
-begin
-show create procedure bug2267_1;
-end|
-drop procedure if exists bug2267_4|
-create procedure bug2267_4()
-begin
-show create function fac;
-end|
-call bug2267_1()|
-Db Name Type Definer Modified Created Security_type Comment
-test bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-test bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-test bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-test bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-call bug2267_2()|
-Db Name Type Definer Modified Created Security_type Comment
-test fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-call bug2267_3()|
-Procedure sql_mode Create Procedure
-bug2267_1 CREATE PROCEDURE `test`.`bug2267_1`()
-begin
-show procedure status;
-end
-call bug2267_4()|
-Function sql_mode Create Function
-fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned
-begin
-declare f bigint unsigned default 1;
-while n > 1 do
-set f = f * n;
-set n = n - 1;
-end while;
-return f;
-end
-drop procedure bug2267_1|
-drop procedure bug2267_2|
-drop procedure bug2267_3|
-drop procedure bug2267_4|
drop procedure if exists bug2227|
create procedure bug2227(x int)
begin
@@ -1331,7 +1486,7 @@ declare t2 int;
declare t3 int;
declare rc int default 0;
declare continue handler for 1065 set rc = 1;
-drop table if exists temp_t1;
+drop temporary table if exists temp_t1;
create temporary table temp_t1 (
f1 int auto_increment, f2 varchar(20), primary key (f1)
);
@@ -1349,6 +1504,7 @@ f1 rc t3
2 0 NULL
2 0 NULL
drop procedure bug1863|
+drop temporary table temp_t1;
drop table t3, t4|
drop table if exists t3, t4|
create table t3 (
@@ -2204,6 +2360,10 @@ call bug8757()|
delete from t1|
delete from t2|
drop procedure bug8757|
+drop procedure if exists bug8762|
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure bug8762|
drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)|
drop procedure if exists ifac|
@@ -2511,7 +2671,7 @@ delete from t1|
insert into t1 values ("answer", 42)|
select id, bug5240() from t1|
id bug5240()
-42 42
+answer 42
drop function bug5240|
drop function if exists bug5278|
create function bug5278 () returns char
@@ -2538,3 +2698,41 @@ drop procedure bug7992|
drop table t3|
drop table t1;
drop table t2;
+CREATE TABLE t1 (
+lpitnumber int(11) default NULL,
+lrecordtype int(11) default NULL
+);
+CREATE TABLE t2 (
+lbsiid int(11) NOT NULL default '0',
+ltradingmodeid int(11) NOT NULL default '0',
+ltradingareaid int(11) NOT NULL default '0',
+csellingprice decimal(19,4) default NULL,
+PRIMARY KEY (lbsiid,ltradingmodeid,ltradingareaid)
+);
+CREATE TABLE t3 (
+lbsiid int(11) NOT NULL default '0',
+ltradingareaid int(11) NOT NULL default '0',
+PRIMARY KEY (lbsiid,ltradingareaid)
+);
+CREATE PROCEDURE bug8849()
+begin
+insert into t3
+(
+t3.lbsiid,
+t3.ltradingareaid
+)
+select distinct t1.lpitnumber, t2.ltradingareaid
+from
+t2 join t1 on
+t1.lpitnumber = t2.lbsiid
+and t1.lrecordtype = 1
+left join t2 as price01 on
+price01.lbsiid = t2.lbsiid and
+price01.ltradingmodeid = 1 and
+t2.ltradingareaid = price01.ltradingareaid;
+end|
+call bug8849();
+call bug8849();
+call bug8849();
+drop procedure bug8849;
+drop tables t1,t2,t3;
diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result
index 8aa20a88177..b36020bc2a3 100644
--- a/mysql-test/r/symlink.result
+++ b/mysql-test/r/symlink.result
@@ -93,3 +93,15 @@ t1 CREATE TABLE `t1` (
`b` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t1;
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index 7b9a94ba998..a9b90617bcc 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -509,7 +509,7 @@ charset(load_file('../../std_data/words.dat')),
collation(load_file('../../std_data/words.dat')),
coercibility(load_file('../../std_data/words.dat'));
charset(load_file('../../std_data/words.dat')) collation(load_file('../../std_data/words.dat')) coercibility(load_file('../../std_data/words.dat'))
-binary binary 3
+binary binary 4
explain extended select
charset(load_file('../../std_data/words.dat')),
collation(load_file('../../std_data/words.dat')),
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 5b6612572cb..bb5f9e7f3b0 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -733,6 +733,9 @@ abs(9999999999999999999999)
select abs(-9999999999999999999999);
abs(-9999999999999999999999)
9999999999999999999999
+select ceiling(999999999999999999);
+ceiling(999999999999999999)
+999999999999999999
select ceiling(99999999999999999999);
ceiling(99999999999999999999)
99999999999999999999
@@ -741,13 +744,16 @@ ceiling(9.9999999999999999999)
10
select ceiling(-9.9999999999999999999);
ceiling(-9.9999999999999999999)
--10
+-9
+select floor(999999999999999999);
+floor(999999999999999999)
+999999999999999999
select floor(9999999999999999999999);
floor(9999999999999999999999)
9999999999999999999999
select floor(9.999999999999999999999);
floor(9.999999999999999999999)
-10
+9
select floor(-9.999999999999999999999);
floor(-9.999999999999999999999)
-10
diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test
index c509a4113f4..a26b78254e7 100644
--- a/mysql-test/t/bigint.test
+++ b/mysql-test/t/bigint.test
@@ -71,3 +71,36 @@ drop table t1;
# atof() behaviour is different of different systems. to be fixed in 4.1
SELECT '0x8000000000000001'+0;
+# Test for BUG#8562: joins over BIGINT UNSIGNED value + constant propagation
+create table t1 (
+ value64 bigint unsigned not null,
+ value32 integer not null,
+ primary key(value64, value32)
+);
+
+create table t2 (
+ value64 bigint unsigned not null,
+ value32 integer not null,
+ primary key(value64, value32)
+);
+
+insert into t1 values(17156792991891826145, 1);
+insert into t1 values( 9223372036854775807, 2);
+insert into t2 values(17156792991891826145, 3);
+insert into t2 values( 9223372036854775807, 4);
+
+select * from t1;
+select * from t2;
+
+select * from t1, t2 where t1.value64=17156792991891826145 and
+t2.value64=17156792991891826145;
+select * from t1, t2 where t1.value64=17156792991891826145 and
+t2.value64=t1.value64;
+
+select * from t1, t2 where t1.value64= 9223372036854775807 and
+t2.value64=9223372036854775807;
+select * from t1, t2 where t1.value64= 9223372036854775807 and
+t2.value64=t1.value64;
+
+drop table t1, t2;
+
diff --git a/mysql-test/t/ctype_cp1250_ch.test b/mysql-test/t/ctype_cp1250_ch.test
new file mode 100644
index 00000000000..06aea7b9979
--- /dev/null
+++ b/mysql-test/t/ctype_cp1250_ch.test
@@ -0,0 +1,12 @@
+-- source include/have_cp1250_ch.inc
+
+SHOW COLLATION LIKE 'cp1250_czech_cs';
+
+#
+# Bugs: #8840: Empty string comparison and character set 'cp1250'
+#
+
+CREATE TABLE t1 (a char(16)) character set cp1250 collate cp1250_czech_cs;
+INSERT INTO t1 VALUES ('');
+SELECT a, length(a), a='', a=' ', a=' ' FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/ctype_cp1251.test b/mysql-test/t/ctype_cp1251.test
index 66a8a5aa909..2d670ec3607 100644
--- a/mysql-test/t/ctype_cp1251.test
+++ b/mysql-test/t/ctype_cp1251.test
@@ -32,3 +32,17 @@ select * from t1 where lower(b)='bbb';
select charset(a), charset(b), charset(binary 'ccc') from t1 limit 1;
select collation(a), collation(b), collation(binary 'ccc') from t1 limit 1;
drop table t1;
+
+# Test for BUG#8560
+create table t1 (
+ a varchar(16) character set cp1251 collate cp1251_bin not null,
+ b int(10) default null,
+ primary key(a)
+) charset=cp1251;
+insert into t1 (a) values ('air'),
+ ('we'),('g'),('we_toshko'), ('s0urce'),('we_ivo'),('we_iliyan'),
+ ('we_martin'),('vw_grado'),('vw_vasko'),('tn_vili'),('tn_kalina'),
+ ('tn_fakira'),('vw_silvia'),('vw_starshi'),('vw_geo'),('vw_b0x1');
+
+select * from t1 where a like 'we_%';
+drop table t1;
diff --git a/mysql-test/t/federated.disabled b/mysql-test/t/federated.disabled
deleted file mode 100644
index 5ad728b6f10..00000000000
--- a/mysql-test/t/federated.disabled
+++ /dev/null
@@ -1 +0,0 @@
-Patrick Galbraith should fix this
diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test
index 413509a0a6a..5c6eb8db179 100644
--- a/mysql-test/t/federated.test
+++ b/mysql-test/t/federated.test
@@ -10,206 +10,304 @@ stop slave;
--disable_warnings
# at this point, we are connected to master
-drop database if exists federated;
+DROP DATABASE IF EXISTS federated;
--enable_warnings
-create database federated;
+CREATE DATABASE federated;
# I wanted to use timestamp, but results will fail if so!!!
-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`)) 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`))
+ DEFAULT CHARSET=latin1;
connection master;
--disable_warnings
-drop database if exists federated;
+DROP DATABASE IF EXISTS federated;
--enable_warnings
-create database federated;
-
-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`)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-
-insert into federated.t1 (name, other) values ('First Name', 11111);
-insert into federated.t1 (name, other) values ('Second Name', 22222);
-insert into federated.t1 (name, other) values ('Third Name', 33333);
-insert into federated.t1 (name, other) values ('Fourth Name', 44444);
-insert into federated.t1 (name, other) values ('Fifth Name', 55555);
-insert into federated.t1 (name, other) values ('Sixth Name', 66666);
-insert into federated.t1 (name, other) values ('Seventh Name', 77777);
-insert into federated.t1 (name, other) values ('Eigth Name', 88888);
-insert into federated.t1 (name, other) values ('Ninth Name', 99999);
-insert into federated.t1 (name, other) values ('Tenth Name', 101010);
+CREATE DATABASE federated;
+
+--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 default '2004-04-04 04:04:04',
+ PRIMARY KEY (`id`),
+ KEY `name` (`name`),
+ KEY `other_key` (`other`))
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', 22222);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES ('Fourth Name', 44444);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name, other) VALUES ('Seventh Name', 77777);
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (name, other) VALUES ('Tenth Name', 101010);
# basic select
-select * from federated.t1;
-# with primary key index_read_idx
-select * from federated.t1 where id = 5;
+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';
-# regular and primary key index_read_idx
-select * from federated.t1 where id = 6 and name = 'Sixth Name';
+SELECT * FROM federated.t1 WHERE name = 'Sixth Name';
+# 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
-select * from federated.t1 where other = 44444;
-select * from federated.t1 where name like '%th%';
+SELECT * FROM federated.t1 WHERE other = 44444;
+SELECT * FROM federated.t1 WHERE name like '%th%';
# update - update_row, index_read_idx
-update federated.t1 set name = '3rd name' where id = 3;
-select * from federated.t1 where name = '3rd name';
+UPDATE federated.t1 SET name = '3rd name' WHERE id = 3;
+SELECT * FROM federated.t1 WHERE name = '3rd name';
# update - update_row, index_read -> index_read_idx
-update federated.t1 set name = 'Third name' where name = '3rd name';
-select * from federated.t1 where name = 'Third 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;
+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 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;
+DELETE FROM federated.t1;
+SELECT * FROM federated.t1 WHERE id = 5;
connection slave;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`) );
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-
-insert into federated.t1 (name, other) values ('First Name', 11111);
-insert into federated.t1 (name, other) values ('Second Name', NULL);
-insert into federated.t1 (name, other) values ('Third Name', 33333);
-insert into federated.t1 (name, other) values (NULL, NULL);
-insert into federated.t1 (name, other) values ('Fifth Name', 55555);
-insert into federated.t1 (name, other) values ('Sixth Name', 66666);
-insert into federated.t1 (name) values ('Seventh Name');
-insert into federated.t1 (name, other) values ('Eigth Name', 88888);
-insert into federated.t1 (name, other) values ('Ninth Name', 99999);
-insert into federated.t1 (other) values ('fee fie foe fum');
-
-select * from federated.t1 where other IS NULL;
-select * from federated.t1 where name IS NULL;
-select * from federated.t1 where name IS NULL and other IS NULL;
-select * from federated.t1 where name IS NULL or other IS NULL;
-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 name = 'Tenth Name' where other like 'fee fie%';
-select * from federated.t1 where name IS NULL or other IS NULL ;
-select * from federated.t1;
+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),
+ `other` varchar(20),
+ PRIMARY KEY (`id`) )
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', 11111);
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', 33333);
+INSERT INTO federated.t1 (name, other) VALUES (NULL, NULL);
+INSERT INTO federated.t1 (name, other) VALUES ('Fifth Name', 55555);
+INSERT INTO federated.t1 (name, other) VALUES ('Sixth Name', 66666);
+INSERT INTO federated.t1 (name) VALUES ('Seventh Name');
+INSERT INTO federated.t1 (name, other) VALUES ('Eigth Name', 88888);
+INSERT INTO federated.t1 (name, other) VALUES ('Ninth Name', 99999);
+INSERT INTO federated.t1 (other) VALUES ('fee fie foe fum');
+
+SELECT * FROM federated.t1 WHERE other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL and other IS NULL;
+SELECT * FROM federated.t1 WHERE name IS NULL or other IS NULL;
+
+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 name = 'Tenth Name' WHERE other like 'fee fie%';
+SELECT * FROM federated.t1 WHERE name IS NULL OR other IS NULL ;
+SELECT * FROM federated.t1;
# test multi-keys
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` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`id`), key nameoth (name, other) );
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `name` varchar(32) NOT NULL DEFAULT '',
+ `other` varchar(20) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY nameoth (name, other) );
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `name` varchar(32) NOT NULL DEFAULT '', `other` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`id`), key nameoth (name, other)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, other) values ('First Name', '1111');
-insert into federated.t1 (name, other) values ('Second Name', '2222');
-insert into federated.t1 (name, other) values ('Third Name', '3333');
-select * from federated.t1 where name = 'Second Name';
-select * from federated.t1 where other = '2222';
-select * from federated.t1 where name = 'Third Name';
-select * from federated.t1 where name = 'Third Name' and other = '3333';
+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` varchar(20) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY nameoth (name, other))
+ ENGINE="FEDERATED" DEFAULT
+ CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, other) VALUES ('First Name', '1111');
+INSERT INTO federated.t1 (name, other) VALUES ('Second Name', '2222');
+INSERT INTO federated.t1 (name, other) VALUES ('Third Name', '3333');
+SELECT * FROM federated.t1 WHERE name = 'Second Name';
+SELECT * FROM federated.t1 WHERE other = '2222';
+SELECT * FROM federated.t1 WHERE name = 'Third Name';
+SELECT * FROM federated.t1 WHERE name = 'Third Name' AND other = '3333';
connection slave;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1
- (id int NOT NULL auto_increment,
- name char(32) NOT NULL DEFAULT '',
- bincol binary(4) NOT NULL,
- floatval decimal(5,2) NOT NULL DEFAULT 0.0,
- other int NOT NULL DEFAULT 0,
- primary key(id),
- key nameoth(name, other),
- key bincol(bincol),
- key floatval(floatval));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int NOT NULL auto_increment,
+ `name` char(32) NOT NULL DEFAULT '',
+ `bincol` binary(4) NOT NULL,
+ `floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+ `other` int NOT NULL DEFAULT 0,
+ PRIMARY KEY (id),
+ KEY nameoth(name, other),
+ KEY bincol(bincol),
+ KEY floatval(floatval));
# test other types of indexes
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1
- (id int NOT NULL auto_increment,
- name char(32) NOT NULL DEFAULT '',
- bincol binary(4) NOT NULL,
- floatval decimal(5,2) NOT NULL DEFAULT 0.0,
- other int NOT NULL DEFAULT 0,
- primary key(id),
- key nameoth(name,other),
- key bincol(bincol),
- key floatval(floatval))
- ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-
-insert into federated.t1 (name, bincol, floatval, other) values ('first', 0x65, 11.11, 1111);
-insert into federated.t1 (name, bincol, floatval, other) values ('second', 0x66, 22.22, 2222);
-insert into federated.t1 (name, bincol, floatval, other) values ('third', 'g', 22.22, 2222);
-select * from federated.t1;
-select * from federated.t1 where name = 'second';
-select * from federated.t1 where bincol= 'f';
-select * from federated.t1 where bincol= 0x66;
-select * from federated.t1 where bincol= 0x67;
-select * from federated.t1 where bincol= 'g';
-select * from federated.t1 where floatval=11.11;
-select * from federated.t1 where name='third';
-select * from federated.t1 where other=2222;
-select * from federated.t1 where name='third' and other=2222;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int NOT NULL auto_increment,
+ `name` char(32) NOT NULL DEFAULT '',
+ `bincol` binary(4) NOT NULL,
+ `floatval` decimal(5,2) NOT NULL DEFAULT 0.0,
+ `other` int NOT NULL DEFAULT 0,
+ PRIMARY KEY (id),
+ KEY nameoth(name,other),
+ KEY bincol(bincol),
+ KEY floatval(floatval))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('first', 0x65, 11.11, 1111);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('second', 0x66, 22.22, 2222);
+INSERT INTO federated.t1 (name, bincol, floatval, other)
+ VALUES ('third', 'g', 22.22, 2222);
+SELECT * FROM federated.t1;
+SELECT * FROM federated.t1 WHERE name = 'second';
+SELECT * FROM federated.t1 WHERE bincol= 'f';
+SELECT * FROM federated.t1 WHERE bincol= 0x66;
+SELECT * FROM federated.t1 WHERE bincol= 0x67;
+SELECT * FROM federated.t1 WHERE bincol= 'g';
+SELECT * FROM federated.t1 WHERE floatval=11.11;
+SELECT * FROM federated.t1 WHERE name='third';
+SELECT * FROM federated.t1 WHERE other=2222;
+SELECT * FROM federated.t1 WHERE name='third' and other=2222;
# test NULLs
connection slave;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 (id int, name varchar(32), floatval float, other int) DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int,
+ `name` varchar(32),
+ `floatval` float,
+ `other` int)
+DEFAULT CHARSET=latin1;
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 (id int, name varchar(32), floatval float, other int) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int,
+ `name` varchar(32),
+ `floatval` float,
+ `other` int)
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
# these both should be the same
-insert into federated.t1 values (NULL, NULL, NULL, NULL);
-insert into federated.t1 values ();
-insert into federated.t1 (id) values (1);
-insert into federated.t1 (name, floatval, other) values ('foo', 33.33333332, NULL);
-insert into federated.t1 (name, floatval, other) values (0, 00.3333, NULL);
-select * from federated.t1;
-select count(*) from federated.t1 where id IS NULL and name IS NULL and floatval IS NULL and other IS NULL;
+INSERT INTO federated.t1 values (NULL, NULL, NULL, NULL);
+INSERT INTO federated.t1 values ();
+INSERT INTO federated.t1 (id) VALUES (1);
+INSERT INTO federated.t1 (name, floatval, other)
+ VALUES ('foo', 33.33333332, NULL);
+INSERT INTO federated.t1 (name, floatval, other)
+ VALUES (0, 00.3333, NULL);
+SELECT * FROM federated.t1;
+SELECT count(*) FROM federated.t1
+WHERE id IS NULL
+AND name IS NULL
+AND floatval IS NULL
+AND other IS NULL;
connection slave;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( blurb_id int NOT NULL DEFAULT 0, blurb text default '', primary key(blurb_id)) DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `blurb_id` int NOT NULL DEFAULT 0,
+ `blurb` text default '',
+ PRIMARY KEY (blurb_id))
+ DEFAULT CHARSET=latin1;
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( blurb_id int NOT NULL DEFAULT 0, blurb text default '', primary key(blurb_id)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `blurb_id` int NOT NULL DEFAULT 0,
+ `blurb` text default '',
+ PRIMARY KEY (blurb_id))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
INSERT INTO federated.t1 VALUES (1, " MySQL supports a number of column types in several categories: numeric types, date and time types, and string (character) types. This chapter first gives an overview of these column types, and then provides a more detailed description of the properties of the types in each category, and a summary of the column type storage requirements. The overview is intentionally brief. The more detailed descriptions should be consulted for additional information about particular column types, such as the allowable formats in which you can specify values.");
INSERT INTO federated.t1 VALUES (2, "All arithmetic is done using signed BIGINT or DOUBLE values, so you should not use unsigned big integers larger than 9223372036854775807 (63 bits) except with bit functions! If you do that, some of the last digits in the result may be wrong because of rounding errors when converting a BIGINT value to a DOUBLE.");
INSERT INTO federated.t1 VALUES (3, " A floating-point number. p represents the precision. It can be from 0 to 24 for a single-precision floating-point number and from 25 to 53 for a double-precision floating-point number. These types are like the FLOAT and DOUBLE types described immediately following. FLOAT(p) has the same range as the corresponding FLOAT and DOUBLE types, but the display size and number of decimals are undefined. ");
INSERT INTO federated.t1 VALUES(4, "Die Übersetzung einer so umfangreichen technischen Dokumentation wie des MySQL-Referenzhandbuchs ist schon eine besondere Herausforderung. Zumindest für jemanden, der seine Zielsprache ernst nimmt:");
-select * from federated.t1;
+SELECT * FROM federated.t1;
connection slave;
-drop table if exists federated.t1;
-create table federated.t1 (a int not null, b int not null, c int not null, primary key (a),key(b));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `a` int NOT NULL,
+ `b` int NOT NULL,
+ `c` int NOT NULL,
+ PRIMARY KEY (a),key(b));
connection master;
-drop table if exists federated.t1;
-create table federated.t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/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;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `a` int NOT NULL,
+ `b` int NOT NULL,
+ `c` int NOT NULL,
+ PRIMARY KEY (a),
+ KEY (b))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
+ 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;
-create table federated.t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+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
int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
@@ -336,10 +434,12 @@ int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
int, i999 int, i1000 int, b blob) row_format=dynamic;
connection master;
-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
-int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval 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 int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
@@ -461,8 +561,14 @@ int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
-int, i999 int, i1000 int, b blob) row_format=dynamic ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+int, i999 int, i1000 int, b blob)
+row_format=dynamic
+ENGINE="FEDERATED"
+DEFAULT CHARSET=latin1
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1
+values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -501,93 +607,145 @@ insert into federated.t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "PatrickG");
-update federated.t1 set b=repeat('a',256);
-update federated.t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
-select * from federated.t1 where i9=0 and i10=0;
-update federated.t1 set i50=20;
-select * from federated.t1;
-delete from federated.t1 where i51=20;
-select * from federated.t1;
-delete from federated.t1 where i50=20;
-select * from federated.t1;
+UPDATE federated.t1 SET b=repeat('a',256);
+UPDATE federated.t1 SET i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0, i10=0;
+SELECT * FROM federated.t1 WHERE i9=0 and i10=0;
+UPDATE federated.t1 SET i50=20;
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1 WHERE i51=20;
+SELECT * FROM federated.t1;
+DELETE FROM federated.t1 WHERE i50=20;
+SELECT * FROM federated.t1;
connection slave;
-drop table if exists federated.t1;
-create table federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', primary key(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', PRIMARY KEY(id), index(code), index(fileguts(10))) DEFAULT CHARSET=latin1;
connection master;
-drop table if exists federated.t1;
-create table federated.t1 (id int NOT NULL auto_increment, code char(20) NOT NULL, fileguts blob NOT NULL, creation_date datetime, entered_time datetime default '2004-04-04 04:04:04', primary key(id), index(code), index(fileguts(10))) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (code, fileguts, creation_date) values ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
-insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
-insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
-select * from federated.t1;
-select * from federated.t1 where fileguts = 'jimbob';
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ id int NOT NULL auto_increment,
+ code char(20) NOT NULL,
+ fileguts blob NOT NULL,
+ creation_date datetime,
+ entered_time datetime default '2004-04-04 04:04:04',
+ PRIMARY KEY(id),
+ index(code),
+ index(fileguts(10)))
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('ASDFWERQWETWETAWETA', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2003-03-03 03:03:03');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
+INSERT INTO federated.t1 (code, fileguts, creation_date) VALUES ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
+SELECT * FROM federated.t1;
# test blob indexes
+SELECT * FROM federated.t1 WHERE fileguts = 'jimbob';
+
+# test blob with binary
+connection slave;
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (`a` BLOB);
+
+connection master;
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `a` BLOB)
+ENGINE="FEDERATED"
+COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 VALUES (0x00);
+INSERT INTO federated.t1 VALUES (0x0001);
+INSERT INTO federated.t1 VALUES (0x0100);
+SELECT HEX(a) FROM federated.t1;
+
# TODO
#
-# create table federated.t1 (a char(20)) charset=cp1251 ENGINE="FEDERATED" COMMENT="mysql://root@127.0.0.1:9308/federated/t1";
+# CREATE TABLE federated.t1
+# (a char(20)) charset=cp1251
+# ENGINE="FEDERATED" COMMENT="mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1";
#
# connection slave;
-# drop table if exists federated.t1;
-# create table federated.t1 (a char(20)) charset=cp1251;
+# DROP TABLE IF EXISTS federated.t1;
+# CREATE TABLE federated.t1 (a char(20)) charset=cp1251;
#
# connection master;
-# insert into federated.t1 values (_cp1251'À-ÁÂÃ-1');
-# insert into federated.t1 values (_cp1251'Á-ÂÃÄ-2');
-# set names cp1251;
-# insert into federated.t1 values ('Â-ÃÄÅ-3');
-# insert into federated.t1 values ('Ã-ŨÆ-4');
-# select * from federated.t1;
+# INSERT INTO federated.t1 values (_cp1251'À-ÁÂÃ-1');
+# INSERT INTO federated.t1 values (_cp1251'Á-ÂÃÄ-2');
+# SET names cp1251;
+# INSERT INTO federated.t1 values ('Â-ÃÄÅ-3');
+# INSERT INTO federated.t1 values ('Ã-ŨÆ-4');
+# SELECT * FROM federated.t1;
# select hex(a) from federated.t1;
-# select hex(a) from federated.t1 order by a desc;
-# update federated.t1 set a='À-ÁÂÃ-1íîâûé' where a='À-ÁÂÃ-1';
-# select * from federated.t1;
-# delete from federated.t1 where a='Ã-ŨÆ-4';
-# select * from federated.t1;
-# delete from federated.t1 where a>'Â-';
-# select * from federated.t1;
-# set names default;
+# select hex(a) from federated.t1 ORDER BY a desc;
+# update federated.t1 SET a='À-ÁÂÃ-1íîâûé' WHERE a='À-ÁÂÃ-1';
+# SELECT * FROM federated.t1;
+# DELETE FROM federated.t1 WHERE a='Ã-ŨÆ-4';
+# SELECT * FROM federated.t1;
+# DELETE FROM federated.t1 WHERE a>'Â-';
+# SELECT * FROM federated.t1;
+# SET names default;
#
-# drop table if exists federated.t1;
+# DROP TABLE IF EXISTS federated.t1;
#
# test joins with non-federated table
connection slave;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id));
+DROP TABLE IF EXISTS federated.t1;
+CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `country_id` int(20) NOT NULL DEFAULT 0,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`),
+ key (country_id));
connection master;
-drop table if exists federated.t1;
-CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
-insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111);
-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);
-
-
-drop table if exists federated.countries;
-CREATE TABLE federated.countries ( `id` int(20) NOT NULL auto_increment, `country` varchar(32), primary key (id));
-insert into federated.countries (country) values ('India');
-insert into federated.countries (country) values ('Germany');
-insert into federated.countries (country) values ('Italy');
-insert into federated.countries (country) values ('Finland');
-insert into federated.countries (country) values ('Ukraine');
-
-select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id;
-
-drop table federated.countries;
+DROP TABLE IF EXISTS federated.countries;
+CREATE TABLE federated.countries (
+ `id` int(20) NOT NULL auto_increment,
+ `country` varchar(32),
+ PRIMARY KEY (id));
+INSERT INTO federated.countries (country) VALUES ('India');
+INSERT INTO federated.countries (country) VALUES ('Germany');
+INSERT INTO federated.countries (country) VALUES ('Italy');
+INSERT INTO federated.countries (country) VALUES ('Finland');
+INSERT INTO federated.countries (country) VALUES ('Ukraine');
+
+DROP TABLE IF EXISTS federated.t1;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE federated.t1 (
+ `id` int(20) NOT NULL auto_increment,
+ `country_id` int(20) NOT NULL DEFAULT 0,
+ `name` varchar(32),
+ `other` varchar(20),
+ PRIMARY KEY (`id`),
+ KEY (country_id) )
+ ENGINE="FEDERATED" DEFAULT CHARSET=latin1
+ COMMENT='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
+
+INSERT INTO federated.t1 (name, country_id, other) VALUES ('Kumar', 1, 11111);
+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);
+
+SELECT federated.t1.*, federated.countries.country
+FROM federated.t1 left join federated.countries
+ON federated.t1.country_id = federated.countries.id;
+
+DROP TABLE federated.countries;
connection master;
--disable_warnings
-drop table if exists federated.t1;
-drop database if exists federated;
+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;
+DROP TABLE IF EXISTS federated.t1;
+DROP DATABASE IF EXISTS federated;
--enable_warnings
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 9a61e6f7029..2d8bac701b1 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -395,8 +395,12 @@ create table t1 (a char character set latin2);
insert into t1 values ('a'),('b');
select charset(max(a)), coercibility(max(a)),
charset(min(a)), coercibility(min(a)) from t1;
+show create table t1;
create table t2 select max(a),min(a) from t1;
show create table t2;
+drop table t2;
+create table t2 select concat(a) from t1;
+show create table t2;
drop table t2,t1;
#
@@ -479,6 +483,15 @@ INSERT INTO t1 VALUES
select val, count(*) from t1 group by val;
drop table t1;
+#
+# Bug #5615: type of aggregate function column wrong when using group by
+#
+
+create table t1(a int, b datetime);
+insert into t1 values (1, NOW()), (2, NOW());
+create table t2 select MAX(b) from t1 group by a;
+show create table t2;
+drop table t1, t2;
#
# Bug 7833: Wrong datatype of aggregate column is returned
@@ -524,3 +537,32 @@ CREATE TABLE t1 (id int(11),value1 float(10,2));
INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00), (2,13.00);
select id, stddev_pop(value1), var_pop(value1), stddev_samp(value1), var_samp(value1) from t1 group by id;
DROP TABLE t1;
+#
+# Bug 8893: wrong result for min/max optimization with 2 indexes
+#
+
+CREATE TABLE t1(
+ id int PRIMARY KEY,
+ a int,
+ b int,
+ INDEX i_b_id(a,b,id),
+ INDEX i_id(a,id)
+);
+INSERT INTO t1 VALUES
+ (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
+SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
+DROP TABLE t1;
+
+# change the order of the last two index definitions
+
+CREATE TABLE t1(
+ id int PRIMARY KEY,
+ a int,
+ b int,
+ INDEX i_id(a,id),
+ INDEX i_b_id(a,b,id)
+);
+INSERT INTO t1 VALUES
+ (1,1,4), (2,2,1), (3,1,3), (4,2,1), (5,1,1);
+SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
+DROP TABLE t1;
diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test
index a05b80ca56b..7fff165e057 100644
--- a/mysql-test/t/func_system.test
+++ b/mysql-test/t/func_system.test
@@ -30,3 +30,12 @@ show create table t1;
drop table t1;
select TRUE,FALSE,NULL;
+
+#
+# Bug#8291 Illegal collation mix with USER() function
+#
+create table t1 (a char(10)) character set latin1;
+select * from t1 where a=version();
+select * from t1 where a=database();
+select * from t1 where a=user();
+drop table t1;
diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index d0778d4c082..3b1200f8a6e 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -246,3 +246,18 @@ connection default;
drop user mysqltest_B@'%';
drop user mysqltest_3@localhost;
#
+# Bug #3309: Test IP addresses with netmask
+set @@sql_mode='';
+create database mysqltest_1;
+create table mysqltest_1.t1 (i int);
+insert into mysqltest_1.t1 values (1),(2),(3);
+GRANT ALL ON mysqltest_1.t1 TO mysqltest_1@'127.0.0.0/255.0.0.0';
+connect (n1,127.0.0.1,mysqltest_1,,mysqltest_1,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection n1;
+show grants for current_user();
+select * from t1;
+disconnect n1;
+connection default;
+REVOKE ALL ON mysqltest_1.t1 FROM mysqltest_1@'127.0.0.0/255.0.0.0';
+drop table mysqltest_1.t1;
+drop database mysqltest_1;
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 86d7bad76bc..4319fec258c 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -3,7 +3,8 @@
# show databases
show variables where variable_name like "skip_show_database";
-grant all privileges on test.* to mysqltest_1@localhost;
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
select * from information_schema.SCHEMATA where schema_name > 'm';
select schema_name from information_schema.schemata;
@@ -104,6 +105,30 @@ select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
select count(*) from information_schema.ROUTINES;
+connect (user1,localhost,mysqltest_1,,);
+connect (user3,localhost,mysqltest_2,,);
+connection user1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+--error 1305
+show create function sub1;
+connection user3;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+connection default;
+grant all privileges on test.* to mysqltest_1@localhost;
+connect (user2,localhost,mysqltest_1,,);
+connection user2;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+create function sub2(i int) returns int
+ return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+show create procedure sel2;
+show create function sub1;
+show create function sub2;
+connection default;
+disconnect user1;
+drop function sub2;
+show create procedure sel2;
+
#
# Test for views
#
@@ -138,8 +163,8 @@ select * from information_schema.USER_PRIVILEGES where grantee like '%mysqltest_
select * from information_schema.SCHEMA_PRIVILEGES where grantee like '%mysqltest_1%';
select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%';
select * from information_schema.COLUMN_PRIVILEGES where grantee like '%mysqltest_1%';
-delete from mysql.user where user='mysqltest_1';
-delete from mysql.db where user='mysqltest_1';
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
@@ -160,13 +185,11 @@ TABLE_SCHEMA= "test";
select * from information_schema.KEY_COLUMN_USAGE where
TABLE_SCHEMA= "test";
-
-connect (user1,localhost,mysqltest_1,,);
-connection user1;
+connection user2;
select table_name from information_schema.TABLES where table_schema like "test%";
select table_name,column_name from information_schema.COLUMNS where table_schema like "test%";
select ROUTINE_NAME from information_schema.ROUTINES;
-disconnect user1;
+disconnect user2;
connection default;
delete from mysql.user where user='mysqltest_1';
drop table t1;
@@ -400,3 +423,12 @@ information_schema.columns
where data_type = 'longtext';
select table_name, column_name, data_type from information_schema.columns
where data_type = 'datetime';
+
+#
+# Bug #8164 subquery with INFORMATION_SCHEMA.COLUMNS, 100 % CPU
+#
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A
+WHERE NOT EXISTS
+(SELECT * FROM INFORMATION_SCHEMA.COLUMNS B
+ WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA
+ AND A.TABLE_NAME = B.TABLE_NAME);
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 797ad5cb5f9..3c9752bb928 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -591,6 +591,7 @@ insert into t1 values(1),(2);
truncate table t1;
commit;
truncate table t1;
+truncate table t1;
select * from t1;
insert into t1 values(1),(2);
delete from t1;
@@ -605,6 +606,7 @@ truncate table t1;
insert into t1 values(1),(2);
select * from t1;
truncate table t1;
+truncate table t1;
insert into t1 values(1),(2);
delete from t1;
select * from t1;
diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test
index 80da2cad192..faa1fa3ac25 100644
--- a/mysql-test/t/lock.test
+++ b/mysql-test/t/lock.test
@@ -53,7 +53,7 @@ check table t1;
# Check error message
lock tables t1 write;
check table t2;
---error 1143
+--error 1100
insert into t1 select index1,nr from t1;
unlock tables;
lock tables t1 write, t1 as t1_alias read;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index df3b8743b10..9464513413a 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -528,6 +528,32 @@ select count(*) from t1 where a is null;
drop table t1;
#
+# Bug #8306: TRUNCATE leads to index corruption
+#
+create table t1 (c1 int, index(c1));
+create table t2 (c1 int, index(c1)) engine=merge union=(t1);
+insert into t1 values (1);
+# Close all tables.
+flush tables;
+# Open t2 and (implicitly) t1.
+select * from t2;
+# Truncate after flush works (unless another threads reopens t2 in between).
+flush tables;
+truncate table t1;
+insert into t1 values (1);
+# Close all tables.
+flush tables;
+# Open t2 and (implicitly) t1.
+select * from t2;
+# Truncate t1, wich was not recognized as open without the bugfix.
+# Now, it should fail with a table-in-use error message.
+--error 1105
+truncate table t1;
+# The insert used to fail on the crashed table.
+insert into t1 values (1);
+drop table t1,t2;
+
+#
# Test varchar
#
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index 3f19c7f0c52..be24c380e0d 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -1,6 +1,7 @@
--disable_warnings
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
drop database if exists mysqldump_test_db;
+drop view if exists v1;
--enable_warnings
# XML output
@@ -158,7 +159,14 @@ drop database mysqldump_test_db;
CREATE TABLE t1 (a CHAR(10));
INSERT INTO t1 VALUES (_latin1 'ÄÖÜß');
--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments test t1
---exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --compatible=mysql323 test t1
+#
+# Bug#8063: make test mysqldump [ fail ]
+# We cannot tes this command because its output depends
+# on --default-character-set incompiled into "mysqldump" program.
+# If the future we can move this command into a separate test with
+# checking that "mysqldump" is compiled with "latin1"
+#
+#--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --compatible=mysql323 test t1
--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --compatible=mysql323 --default-character-set=cp850 test t1
--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1
--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 7f65a7b04da..1af84119b79 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -497,3 +497,46 @@ insert into t1 values ('foo');
prepare stmt FROM 'SELECT char_length (a) FROM t1';
drop table t1;
+#
+# Bug #6089: FOUND_ROWS returns wrong values when no table/view is used
+#
+
+prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0";
+execute stmt;
+SELECT FOUND_ROWS();
+execute stmt;
+SELECT FOUND_ROWS();
+deallocate prepare stmt;
+
+#
+# Bug#8115: equality propagation and prepared statements
+#
+
+create table t1 (a char(3) not null, b char(3) not null,
+ c char(3) not null, primary key (a, b, c));
+create table t2 like t1;
+
+# reduced query
+prepare stmt from
+ "select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
+ where t1.a=1";
+execute stmt;
+execute stmt;
+execute stmt;
+
+# original query
+prepare stmt from
+"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
+(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
+left outer join t2 t3 on t3.a=? where t1.a=?";
+
+set @a:=1, @b:=1, @c:=1;
+
+execute stmt using @a, @b, @c;
+execute stmt using @a, @b, @c;
+execute stmt using @a, @b, @c;
+
+deallocate prepare stmt;
+
+drop table t1,t2;
+
diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test
index 835af92186f..e9a87529706 100644
--- a/mysql-test/t/rpl000001.test
+++ b/mysql-test/t/rpl000001.test
@@ -39,7 +39,13 @@ save_master_pos;
connection slave;
sync_with_master;
-#test handling of aborted connection in the middle of update
+# Test if the slave SQL thread can be more than 16K behind the slave
+# I/O thread (> IO_SIZE)
+
+connection master;
+# we'll use table-level locking to delay slave SQL thread
+create table t1 (n int) engine=myisam;
+sync_slave_with_master;
connection master;
reset master;
connection slave;
@@ -47,29 +53,26 @@ stop slave;
reset slave;
connection master;
-create table t1(n int);
-#we want the log to exceed 16K to test deal with the log that is bigger than
-#IO_SIZE
let $1=5000;
+# Generate 16K of relay log
disable_query_log;
while ($1)
{
- eval insert into t1 values($1+get_lock("hold_slave",10)*0);
+ eval insert into t1 values($1);
dec $1;
}
enable_query_log;
-# Try to cause a large relay log lag on the slave
+# Try to cause a large relay log lag on the slave by locking t1
connection slave;
-select get_lock("hold_slave",10);
-explain extended select get_lock("hold_slave",10);
+lock tables t1 read;
start slave;
#hope this is long enough for I/O thread to fetch over 16K relay log data
sleep 3;
-select release_lock("hold_slave");
-explain extended select release_lock("hold_slave");
unlock tables;
+#test handling of aborted connection in the middle of update
+
connection master;
create table t2(id int);
insert into t2 values(connection_id());
diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test
index ddac966b073..23866447c98 100644
--- a/mysql-test/t/rpl_change_master.test
+++ b/mysql-test/t/rpl_change_master.test
@@ -1,16 +1,23 @@
+# Verify that after CHANGE MASTER, replication (I/O thread and SQL
+# thread) restart from where SQL thread left, not from where
+# I/O thread left (some old bug fixed in 4.0.17)
+
source include/master-slave.inc;
-connection slave;
-select get_lock("a",5);
connection master;
+# Make SQL slave thread advance a bit
create table t1(n int);
-insert into t1 values(1+get_lock("a",15)*0);
+sync_slave_with_master;
+select * from t1;
+# Now stop it and make I/O slave thread be ahead
+stop slave sql_thread;
+connection master;
+insert into t1 values(1);
insert into t1 values(2);
save_master_pos;
connection slave;
---real_sleep 3; # can't sync_with_master as we should be blocked
+--real_sleep 3; # wait for I/O thread to have read updates
stop slave;
-select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
@@ -18,8 +25,6 @@ change master to master_user='root';
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
-# Will restart from after the values(2), which is bug
-select release_lock("a");
start slave;
sync_with_master;
select * from t1;
diff --git a/mysql-test/t/rpl_deadlock-slave.opt b/mysql-test/t/rpl_deadlock-slave.opt
new file mode 100644
index 00000000000..f4a8c640458
--- /dev/null
+++ b/mysql-test/t/rpl_deadlock-slave.opt
@@ -0,0 +1 @@
+--innodb --loose-innodb_lock_wait_timeout=4 --slave-transaction-retries=2 --max-relay-log-size=4096
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
new file mode 100644
index 00000000000..aa474f79963
--- /dev/null
+++ b/mysql-test/t/rpl_deadlock.test
@@ -0,0 +1,107 @@
+# See if slave restarts the transaction after failing on an InnoDB deadlock error.
+
+# Note: testing what happens when too many retries is possible, but
+# needs large waits when running with --debug, so we don't do it.
+# The same way, this test may not test what is expected when run
+# under Valgrind, timings are too short then (with --valgrind I
+# (Guilhem) have seen the test manage to provoke lock wait timeout
+# error but not deadlock error; that is ok as code deals with the two
+# errors in exactly the same way.
+
+source include/have_innodb.inc;
+source include/master-slave.inc;
+
+connection master;
+create table t1 (a int not null, key(a)) engine=innodb;
+create table t2 (a int not null, key(a)) engine=innodb;
+create table t3 (a int) engine=innodb;
+create table t4 (a int) engine=innodb;
+sync_slave_with_master;
+
+show create table t1;
+show create table t2;
+stop slave;
+
+# 1) Test deadlock
+
+connection master;
+begin;
+# Let's keep BEGIN and the locked statement in two different relay logs.
+let $1=200;
+disable_query_log;
+while ($1)
+{
+ eval insert into t3 values( $1 );
+ dec $1;
+}
+enable_query_log;
+insert into t3 select * from t2 for update;
+insert into t1 values(1);
+commit;
+save_master_pos;
+
+connection slave;
+begin;
+# Let's make our transaction large so that it's slave who is chosen as
+# victim
+let $1=1000;
+disable_query_log;
+while ($1)
+{
+ eval insert into t4 values( $1 );
+ dec $1;
+}
+enable_query_log;
+select * from t1 for update;
+start slave;
+--sleep 3; # hope that slave is blocked now
+insert into t2 values(22); # provoke deadlock, slave should be victim
+commit;
+sync_with_master;
+select * from t1; # check that slave succeeded finally
+select * from t2;
+# check that no error is reported
+--replace_column 1 # 8 # 9 # 23 # 33 #
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+show slave status;
+
+# 2) Test lock wait timeout
+
+stop slave;
+change master to master_log_pos=534; # the BEGIN log event
+begin;
+select * from t2 for update; # hold lock
+start slave;
+--sleep 10; # slave should have blocked, and be retrying
+commit;
+sync_with_master;
+select * from t1; # check that slave succeeded finally
+select * from t2;
+# check that no error is reported
+--replace_column 1 # 8 # 9 # 23 # 33 #
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+show slave status;
+
+# Now we repeat 2), but with BEGIN in the same relay log as
+# COMMIT (to see if seeking into hot log is ok).
+
+set global max_relay_log_size=0;
+
+# This is really copy-paste of 2) of above
+stop slave;
+change master to master_log_pos=534;
+begin;
+select * from t2 for update;
+start slave;
+--sleep 10;
+commit;
+sync_with_master;
+select * from t1;
+select * from t2;
+--replace_column 1 # 8 # 9 # 23 # 33 #
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+show slave status;
+
+connection master;
+drop table t1,t2;
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_get_lock.test b/mysql-test/t/rpl_get_lock.test
index 5e58753e59a..847e7145be6 100644
--- a/mysql-test/t/rpl_get_lock.test
+++ b/mysql-test/t/rpl_get_lock.test
@@ -22,6 +22,13 @@ connection slave;
sync_with_master;
select get_lock("lock",3);
select * from t1;
+# There is no point in testing REPLICATIION of the IS_*_LOCK
+# functions; slave does not run with the same concurrency context as
+# master (generally in slave we can't know that on master this lock
+# was already held by another connection and so that the the
+# get_lock() we're replicating timed out on master hence returned 0,
+# or that the is_free_lock() we're playing returned 0 etc.
+# But here all we do is test these functions outside of replication.
select is_free_lock("lock"), is_used_lock("lock") = connection_id();
explain extended select is_free_lock("lock"), is_used_lock("lock");
# Check lock functions
diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test
index 5bd068eb0e6..91879015b51 100644
--- a/mysql-test/t/select_found.test
+++ b/mysql-test/t/select_found.test
@@ -168,6 +168,21 @@ SELECT FOUND_ROWS();
DROP TABLE t1;
#
+# Bug #6089: queries which don't use any tables
+#
+
+SELECT 'foo';
+SELECT FOUND_ROWS();
+SELECT SQL_CALC_FOUND_ROWS 'foo';
+SELECT FOUND_ROWS();
+SELECT SQL_CALC_FOUND_ROWS 'foo' limit 0;
+SELECT FOUND_ROWS();
+SELECT FOUND_ROWS();
+
+SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0;
+SELECT FOUND_ROWS();
+
+#
# Bug #7945: group by + distinct with constant expression + limit
#
diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test
index 3cafd31a879..5b2dfb00bb7 100644
--- a/mysql-test/t/select_safe.test
+++ b/mysql-test/t/select_safe.test
@@ -66,4 +66,24 @@ SET MAX_SEEKS_FOR_KEY=DEFAULT;
drop table t1;
+# BUG#8726
+create table t1 (a int);
+insert into t1 values (1),(2),(3),(4),(5);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+
+set local max_join_size=8;
+--error 1104
+select * from (select * from t1) x;
+
+set local max_join_size=1;
+--error 1104
+select * from (select * from t1 a, t1 b) x;
+
+set local max_join_size=1;
+--error 1104
+select * from (select 1 union select 2 union select 3) x;
+drop table t1;
+
SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index cfb5de7ddd0..3c98e5ca4ba 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -339,16 +339,15 @@ drop procedure if exists sub1|
create procedure sub1(id char(16), x int)
insert into test.t1 values (id, x)|
-# QQ This doesn't work yet
-#--disable_warnings
-#drop procedure if exists sub2|
-#--enable_warnings
-#create procedure sub2(id char(16))
-#begin
-# declare x int;
-# set x = (select sum(t.x) from test.t2 t);
-# insert into test.t1 values (id, x);
-#end|
+--disable_warnings
+drop procedure if exists sub2|
+--enable_warnings
+create procedure sub2(id char(16))
+begin
+ declare x int;
+ set x = (select sum(t.i) from test.t2 t);
+ insert into test.t1 values (id, x);
+end|
--disable_warnings
drop procedure if exists sub3|
@@ -360,11 +359,11 @@ call sub1("sub1a", (select 7))|
call sub1("sub1b", (select max(i) from t2))|
call sub1("sub1c", (select i,d from t2 limit 1))|
call sub1("sub1d", (select 1 from (select 1) a))|
-#call sub2("sub2");
+call sub2("sub2");
select * from t1|
select sub3((select max(i) from t2))|
drop procedure sub1|
-#drop procedure sub2|
+drop procedure sub2|
drop function sub3|
delete from t2|
@@ -1279,6 +1278,202 @@ drop procedure rc|
#
+# Let us test how well new locking scheme works.
+#
+
+# Let us prepare playground
+--disable_warnings
+drop function if exists f0|
+drop function if exists f1|
+drop function if exists f2|
+drop function if exists f3|
+drop function if exists f4|
+drop function if exists f5|
+drop function if exists f6|
+drop function if exists f7|
+drop function if exists f8|
+drop view if exists v0|
+drop view if exists v1|
+drop view if exists v2|
+--enable_warnings
+delete from t1|
+delete from t2|
+insert into t1 values ("a", 1), ("b", 2) |
+insert into t2 values ("a", 1, 1.0), ("b", 2, 2.0), ("c", 3, 3.0) |
+
+# Test the simplest function using tables
+create function f1() returns int
+ return (select sum(data) from t1)|
+select f1()|
+# This should work too (and give 2 rows as result)
+select id, f1() from t1|
+
+# Function which uses two instances of table simultaneously
+create function f2() returns int
+ return (select data from t1 where data <= (select sum(data) from t1) limit 1)|
+select f2()|
+select id, f2() from t1|
+
+# Function which uses the same table twice in different queries
+create function f3() returns int
+begin
+ declare n int;
+ declare m int;
+ set n:= (select min(data) from t1);
+ set m:= (select max(data) from t1);
+ return n < m;
+end|
+select f3()|
+select id, f3() from t1|
+
+# Calling two functions using same table
+select f1(), f3()|
+select id, f1(), f3() from t1|
+
+# Function which uses two different tables
+create function f4() returns double
+ return (select d from t1, t2 where t1.data = t2.i and t1.id= "b")|
+select f4()|
+select s, f4() from t2|
+
+# Recursive functions which due to this recursion require simultaneous
+# access to several instance of the same table won't work
+create function f5(i int) returns int
+begin
+ if i <= 0 then
+ return 0;
+ elseif i = 1 then
+ return (select count(*) from t1 where data = i);
+ else
+ return (select count(*) + f5( i - 1) from t1 where data = i);
+ end if;
+end|
+select f5(1)|
+# This should generate an error about insuficient number of tables locked
+--error 1100
+select f5(2)|
+# But now it simply miserably fails because we are trying to use the same
+# lex on the next iteration :/ It should generate some error too...
+# select f5(3)|
+
+# OTOH this should work
+create function f6() returns int
+begin
+ declare n int;
+ set n:= f1();
+ return (select count(*) from t1 where data <= f7() and data <= n);
+end|
+create function f7() returns int
+ return (select sum(data) from t1 where data <= f1())|
+select f6()|
+select id, f6() from t1|
+
+# TODO Test temporary table handling
+
+#
+# Let us test how new locking work with views
+#
+# The most trivial view
+create view v1 (a) as select f1()|
+select * from v1|
+select id, a from t1, v1|
+select * from v1, v1 as v|
+# A bit more complex construction
+create view v2 (a) as select a*10 from v1|
+select * from v2|
+select id, a from t1, v2|
+select * from v1, v2|
+
+# Nice example where the same view is used on
+# on different expression levels
+create function f8 () returns int
+ return (select count(*) from v2)|
+
+select *, f8() from v1|
+
+# Let us test what will happen if function is missing
+drop function f1|
+--error 1356
+select * from v1|
+
+# And what will happen if we have recursion which involves
+# views and functions ?
+create function f1() returns int
+ return (select sum(data) from t1) + (select sum(data) from v1)|
+# FIXME All these just exceed file limit for me :)
+#select f1()|
+#select * from v1|
+#select * from v2|
+# Back to the normal cases
+drop function f1|
+create function f1() returns int
+ return (select sum(data) from t1)|
+
+# Let us also test some weird cases where no real tables is used
+create function f0() returns int
+ return (select * from (select 100) as r)|
+select f0()|
+select *, f0() from (select 1) as t|
+create view v0 as select f0()|
+select * from v0|
+select *, f0() from v0|
+
+#
+# Let us test how well prelocking works with explicit LOCK TABLES.
+#
+# Nowdays we have to lock mysql.proc to be able to read SP definitions.
+# But Monty was going to fix this.
+lock tables t1 read, t1 as t11 read, mysql.proc read|
+# These should work well
+select f3()|
+select id, f3() from t1 as t11|
+# Degenerate cases work too :)
+select f0()|
+select * from v0|
+select *, f0() from v0, (select 123) as d1|
+# But these should not !
+--error 1100
+select id, f3() from t1|
+--error 1100
+select f4()|
+unlock tables|
+
+# Let us test how LOCK TABLES which implicitly depends on functions
+# works
+lock tables v2 read, mysql.proc read|
+select * from v2|
+select * from v1|
+# These should not work as we have too little instances of tables locked
+--error 1100
+select * from v1, v2|
+--error 1100
+select f4()|
+unlock tables|
+
+
+# TODO We also should test integration with triggers
+
+
+# Cleanup
+drop function f0|
+drop function f1|
+drop function f2|
+drop function f3|
+drop function f4|
+drop function f5|
+drop function f6|
+drop function f7|
+drop function f8|
+drop view v0|
+drop view v1|
+drop view v2|
+delete from t1 |
+delete from t2 |
+
+# End of non-bug tests
+
+
+#
# Test cases for old bugs
#
@@ -1453,49 +1648,56 @@ drop procedure bug2260|
#
# BUG#2267
#
---disable_warnings
-drop procedure if exists bug2267_1|
---enable_warnings
-create procedure bug2267_1()
-begin
- show procedure status;
-end|
-
---disable_warnings
-drop procedure if exists bug2267_2|
---enable_warnings
-create procedure bug2267_2()
-begin
- show function status;
-end|
-
---disable_warnings
-drop procedure if exists bug2267_3|
---enable_warnings
-create procedure bug2267_3()
-begin
- show create procedure bug2267_1;
-end|
-
---disable_warnings
-drop procedure if exists bug2267_4|
---enable_warnings
-create procedure bug2267_4()
-begin
- show create function fac;
-end|
-
---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
-call bug2267_1()|
---replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
-call bug2267_2()|
-call bug2267_3()|
-call bug2267_4()|
-
-drop procedure bug2267_1|
-drop procedure bug2267_2|
-drop procedure bug2267_3|
-drop procedure bug2267_4|
+# NOTE: This test case will be fixed as soon as Monty
+# will allow to open mysql.proc table under LOCK TABLES
+# without mentioning in lock list.
+#
+# FIXME: Other solution would be to use preopened proc table
+# instead of opening it anew.
+#
+#--disable_warnings
+#drop procedure if exists bug2267_1|
+#--enable_warnings
+#create procedure bug2267_1()
+#begin
+# show procedure status;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_2|
+#--enable_warnings
+#create procedure bug2267_2()
+#begin
+# show function status;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_3|
+#--enable_warnings
+#create procedure bug2267_3()
+#begin
+# show create procedure bug2267_1;
+#end|
+#
+#--disable_warnings
+#drop procedure if exists bug2267_4|
+#--enable_warnings
+#create procedure bug2267_4()
+#begin
+# show create function fac;
+#end|
+#
+#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+#call bug2267_1()|
+#--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+#call bug2267_2()|
+#call bug2267_3()|
+#call bug2267_4()|
+#
+#drop procedure bug2267_1|
+#drop procedure bug2267_2|
+#drop procedure bug2267_3|
+#drop procedure bug2267_4|
#
# BUG#2227
@@ -1529,7 +1731,7 @@ drop procedure bug2227|
#--enable_warnings
#create procedure bug2614()
#begin
-# drop table if exists t3;
+# drop temporary table if exists t3;
# create temporary table t3 (id int default '0' not null);
# insert into t3 select 12;
# insert into t3 select * from t3;
@@ -1539,7 +1741,7 @@ drop procedure bug2227|
#call bug2614()|
#--enable_warnings
#call bug2614()|
-#drop table t3|
+#drop temporary table t3|
#drop procedure bug2614|
#
@@ -1680,7 +1882,7 @@ begin
declare rc int default 0;
declare continue handler for 1065 set rc = 1;
- drop table if exists temp_t1;
+ drop temporary table if exists temp_t1;
create temporary table temp_t1 (
f1 int auto_increment, f2 varchar(20), primary key (f1)
);
@@ -1702,6 +1904,7 @@ call bug1863(10)|
select * from t4|
drop procedure bug1863|
+drop temporary table temp_t1;
drop table t3, t4|
#
@@ -2715,6 +2918,19 @@ drop procedure bug8757|
#
+# BUG#8762: Stored Procedures: Inconsistent behavior
+# of DROP PROCEDURE IF EXISTS statement.
+--disable_warnings
+drop procedure if exists bug8762|
+--enable_warnings
+# Doesn't exist
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+# Does exist
+drop procedure if exists bug8762; create procedure bug8762() begin end|
+drop procedure bug8762|
+
+
+#
# Some "real" examples
#
@@ -2993,15 +3209,6 @@ drop table t3|
drop function getcount|
#
-# Former BUG#1654
-# QQ Currently crashes
-#
-#create function bug1654() returns int
-# return (select sum(t1.data) from test.t1 t)|
-#
-#select bug1654()|
-
-#
# BUG#5240: Stored procedure crash if function has cursor declaration
#
# The following test case fails in --ps-protocol mode due to some bugs
@@ -3026,7 +3233,6 @@ end|
delete from t1|
insert into t1 values ("answer", 42)|
-# QQ BUG: This returns the wrong result, id=42 instead of "answer".
select id, bug5240() from t1|
drop function bug5240|
@@ -3073,3 +3279,52 @@ delimiter ;|
drop table t1;
drop table t2;
+#
+# Bug#8849: rolling back changes to AND/OR structure of ON and WHERE clauses
+# in SP
+#
+
+CREATE TABLE t1 (
+ lpitnumber int(11) default NULL,
+ lrecordtype int(11) default NULL
+);
+
+CREATE TABLE t2 (
+ lbsiid int(11) NOT NULL default '0',
+ ltradingmodeid int(11) NOT NULL default '0',
+ ltradingareaid int(11) NOT NULL default '0',
+ csellingprice decimal(19,4) default NULL,
+ PRIMARY KEY (lbsiid,ltradingmodeid,ltradingareaid)
+);
+
+CREATE TABLE t3 (
+ lbsiid int(11) NOT NULL default '0',
+ ltradingareaid int(11) NOT NULL default '0',
+ PRIMARY KEY (lbsiid,ltradingareaid)
+);
+
+delimiter |;
+CREATE PROCEDURE bug8849()
+begin
+ insert into t3
+ (
+ t3.lbsiid,
+ t3.ltradingareaid
+ )
+ select distinct t1.lpitnumber, t2.ltradingareaid
+ from
+ t2 join t1 on
+ t1.lpitnumber = t2.lbsiid
+ and t1.lrecordtype = 1
+ left join t2 as price01 on
+ price01.lbsiid = t2.lbsiid and
+ price01.ltradingmodeid = 1 and
+ t2.ltradingareaid = price01.ltradingareaid;
+end|
+delimiter ;|
+
+call bug8849();
+call bug8849();
+call bug8849();
+drop procedure bug8849;
+drop tables t1,t2,t3;
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index 25c78129129..f477fc378c6 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -83,7 +83,7 @@ create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, p
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="not-hard-path";
# Should fail becasue the file t9.MYI already exist in 'run'
---error 1,1
+--error 1,1,1105
eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="$MYSQL_TEST_DIR/var/run";
# Should fail becasue the file t9.MYD already exist in 'tmp'
@@ -121,3 +121,18 @@ eval alter table t1 index directory="$MYSQL_TEST_DIR/var/log";
enable_query_log;
show create table t1;
drop table t1;
+
+#
+# Test specifying DATA DIRECTORY that is the same as what would normally
+# have been chosen. (Bug #8707)
+#
+disable_query_log;
+eval create table t1 (i int) data directory = "$MYSQL_TEST_DIR/var/master-data/test/";
+enable_query_log;
+show create table t1;
+drop table t1;
+disable_query_log;
+eval create table t1 (i int) index directory = "$MYSQL_TEST_DIR/var/master-data/test/";
+enable_query_log;
+show create table t1;
+drop table t1;
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index 3922a0448e9..d116d56fa48 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -601,6 +601,7 @@ select abs(9999999999999999999999);
select abs(-9999999999999999999999);
#-- should return 9999999999999999999999
#
+select ceiling(999999999999999999);
select ceiling(99999999999999999999);
#-- should return 99999999999999999999
#
@@ -610,6 +611,7 @@ select ceiling(9.9999999999999999999);
select ceiling(-9.9999999999999999999);
#-- should return 9
#
+select floor(999999999999999999);
select floor(9999999999999999999999);
#-- should return 9999999999999999999999
#
diff --git a/mysys/mf_tempfile.c b/mysys/mf_tempfile.c
index af9ff0d6711..a15bda4da6d 100644
--- a/mysys/mf_tempfile.c
+++ b/mysys/mf_tempfile.c
@@ -70,7 +70,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
{
strmake(to,res,FN_REFLEN-1);
(*free)(res);
- file=my_create(to,0, mode, MyFlags);
+ file=my_create(to,0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
}
environ=old_env;
}
@@ -81,7 +81,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
{
strmake(to,res,FN_REFLEN-1);
(*free)(res);
- file=my_create(to, 0, mode, MyFlags);
+ file=my_create(to, 0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
}
#elif defined(HAVE_MKSTEMP) && !defined(__NETWARE__)
{
@@ -143,7 +143,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
strmake(to,res,FN_REFLEN-1);
(*free)(res);
file=my_create(to,0,
- (int) (O_RDWR | O_BINARY | O_TRUNC |
+ (int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME));
@@ -186,7 +186,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
}
(void) strmov(end_pos,TMP_EXT);
file=my_create(to,0,
- (int) (O_RDWR | O_BINARY | O_TRUNC |
+ (int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME));
}
diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c
index ed662a38712..a111c3dc571 100644
--- a/mysys/my_mmap.c
+++ b/mysys/my_mmap.c
@@ -28,8 +28,7 @@ int my_msync(int fd, void *addr, size_t len, int flags)
return my_sync(fd, MYF(0));
}
-#else
-#ifdef __WIN__
+#elif defined(__WIN__)
static SECURITY_ATTRIBUTES mmap_security_attributes=
{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
@@ -83,13 +82,7 @@ int my_msync(int fd, void *addr, size_t len, int flags)
return FlushViewOfFile(addr, len) ? 0 : -1;
}
-#endif
-
-#ifdef _WINDOWS
-#pragma message "no mmap!"
#else
#warning "no mmap!"
#endif
-#endif
-
diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c
index 913f632fbb4..80dca7d56ac 100644
--- a/mysys/my_symlink2.c
+++ b/mysys/my_symlink2.c
@@ -32,6 +32,7 @@ File my_create_with_symlink(const char *linkname, const char *filename,
int tmp_errno;
/* Test if we should create a link */
int create_link;
+ char abs_linkname[FN_REFLEN];
DBUG_ENTER("my_create_with_symlink");
if (my_disable_symlinks)
@@ -42,7 +43,11 @@ File my_create_with_symlink(const char *linkname, const char *filename,
filename= linkname;
}
else
- create_link= (linkname && strcmp(linkname,filename));
+ {
+ if (linkname)
+ my_realpath(&abs_linkname, linkname, MYF(0));
+ create_link= (linkname && strcmp(abs_linkname,filename));
+ }
if (!(MyFlags & MY_DELETE_OLD))
{
diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
index 5db0cd7af1b..78209c3affa 100644
--- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
+++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
@@ -6443,7 +6443,7 @@ Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
// write index key attributes
AttributeRecordPtr aRecPtr;
c_attributeRecordPool.getPtr(aRecPtr, tablePtr.p->firstAttribute);
- for (unsigned k = 0; k < opPtr.p->m_attrList.sz; k++) {
+ for (k = 0; k < opPtr.p->m_attrList.sz; k++) {
// insert the attributes in the order decided above in attrid_map
// k is new order, current_id is in previous order
// ToDo: make sure "current_id" is stored with the table and
diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index 6325f659e39..17d55176830 100644
--- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -5344,7 +5344,8 @@ void Dbtc::execTC_COMMITREQ(Signal* signal)
const Uint32 transId1 = regApiPtr->transid[0];
const Uint32 transId2 = regApiPtr->transid[1];
Uint32 errorCode = 0;
-
+
+ regApiPtr->m_exec_flag = 1;
switch (regApiPtr->apiConnectstate) {
case CS_STARTED:
tcConnectptr.i = regApiPtr->firstTcConnect;
@@ -6073,11 +6074,17 @@ int Dbtc::releaseAndAbort(Signal* signal)
UintR TnoLoops = tcConnectptr.p->noOfNodes;
apiConnectptr.p->counter++;
+ bool prevAlive = false;
for (Uint32 Ti = 0; Ti < TnoLoops ; Ti++) {
localHostptr.i = tcConnectptr.p->tcNodedata[Ti];
ptrCheckGuard(localHostptr, chostFilesize, hostRecord);
if (localHostptr.p->hostStatus == HS_ALIVE) {
jam();
+ if (prevAlive) {
+ // if previous is alive, its LQH forwards abort to this node
+ jam();
+ continue;
+ }
/* ************< */
/* ABORT < */
/* ************< */
@@ -6087,15 +6094,16 @@ int Dbtc::releaseAndAbort(Signal* signal)
signal->theData[2] = apiConnectptr.p->transid[0];
signal->theData[3] = apiConnectptr.p->transid[1];
sendSignal(tblockref, GSN_ABORT, signal, 4, JBB);
- return 1;
+ prevAlive = true;
} else {
jam();
signal->theData[0] = tcConnectptr.i;
signal->theData[1] = apiConnectptr.p->transid[0];
signal->theData[2] = apiConnectptr.p->transid[1];
- signal->theData[3] = hostptr.i;
+ signal->theData[3] = localHostptr.i;
signal->theData[4] = ZFALSE;
sendSignal(cownref, GSN_ABORTED, signal, 5, JBB);
+ prevAlive = false;
}//if
}//for
return 1;
diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am
index 5eb3c215ee5..9a1726ae11a 100644
--- a/ndb/test/ndbapi/Makefile.am
+++ b/ndb/test/ndbapi/Makefile.am
@@ -74,8 +74,8 @@ testReadPerf_SOURCES = testReadPerf.cpp
testLcp_SOURCES = testLcp.cpp
testPartitioning_SOURCES = testPartitioning.cpp
testBitfield_SOURCES = testBitfield.cpp
-DbCreate_SOURCES= bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp
-DbAsyncGenerator_SOURCES= bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp
+DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
+DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel
diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp
index 7913b4b240e..1ce934a19ca 100644
--- a/ndb/test/ndbapi/testNodeRestart.cpp
+++ b/ndb/test/ndbapi/testNodeRestart.cpp
@@ -344,6 +344,71 @@ err:
return NDBT_FAILED;
}
+int runLateCommit(NDBT_Context* ctx, NDBT_Step* step){
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+ int records = ctx->getNumRecords();
+ NdbRestarter restarter;
+ HugoOperations hugoOps(*ctx->getTab());
+ Ndb* pNdb = GETNDB(step);
+
+ int i = 0;
+ while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
+ g_info << i << ": ";
+
+ if(hugoOps.startTransaction(pNdb) != 0)
+ return NDBT_FAILED;
+
+ if(hugoOps.pkUpdateRecord(pNdb, 1) != 0)
+ return NDBT_FAILED;
+
+ if(hugoOps.execute_NoCommit(pNdb) != 0)
+ return NDBT_FAILED;
+
+ Uint32 transNode= hugoOps.getTransaction()->getConnectedNodeId();
+ int id = i % restarter.getNumDbNodes();
+ int nodeId;
+ while((nodeId = restarter.getDbNodeId(id)) == transNode)
+ id = (id + 1) % restarter.getNumDbNodes();
+
+ ndbout << "Restart node " << nodeId << endl;
+
+ restarter.restartOneDbNode(nodeId,
+ /** initial */ false,
+ /** nostart */ true,
+ /** abort */ true);
+
+ restarter.waitNodesNoStart(&nodeId, 1);
+
+ int res;
+ if(i & 1)
+ res= hugoOps.execute_Commit(pNdb);
+ else
+ res= hugoOps.execute_Rollback(pNdb);
+
+ ndbout_c("res= %d", res);
+
+ hugoOps.closeTransaction(pNdb);
+
+ restarter.startNodes(&nodeId, 1);
+ restarter.waitNodesStarted(&nodeId, 1);
+
+ if(i & 1)
+ {
+ if(res != 286)
+ return NDBT_FAILED;
+ }
+ else
+ {
+ if(res != 0)
+ return NDBT_FAILED;
+ }
+ i++;
+ }
+
+ return NDBT_OK;
+}
+
NDBT_TESTSUITE(testNodeRestart);
TESTCASE("NoLoad",
"Test that one node at a time can be stopped and then restarted "\
@@ -600,6 +665,12 @@ TESTCASE("CommittedRead",
STEP(runDirtyRead);
FINALIZER(runClearTable);
}
+TESTCASE("LateCommit",
+ "Test commit after node failure"){
+ INITIALIZER(runLoadTable);
+ STEP(runLateCommit);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNodeRestart);
int main(int argc, const char** argv){
diff --git a/ndb/test/run-test/daily-devel-tests.txt b/ndb/test/run-test/daily-devel-tests.txt
index 5c9b36fb836..ec90a88a77f 100644
--- a/ndb/test/run-test/daily-devel-tests.txt
+++ b/ndb/test/run-test/daily-devel-tests.txt
@@ -71,6 +71,10 @@ args: -n CommittedRead T1
max-time: 2500
cmd: testNodeRestart
+args: -n LateCommit T1
+
+max-time: 2500
+cmd: testNodeRestart
args: -n Terror T6 T13
max-time: 2500
diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh
index 2cfe91da115..632174dc41a 100644
--- a/scripts/mysqlhotcopy.sh
+++ b/scripts/mysqlhotcopy.sh
@@ -272,10 +272,7 @@ foreach my $rdb ( @db_desc ) {
my $negated;
if ($rdb->{t_regex}) {
$t_regex = $rdb->{t_regex}; ## assign temporary regex
- $negated = $t_regex =~ tr/~//d; ## remove and count
- ## negation operator: we
- ## don't allow ~ in table
- ## names
+ $negated = $t_regex =~ s/^~//; ## note and remove negation operator
$t_regex = qr/$t_regex/; ## make regex string from
## user regex
@@ -820,6 +817,16 @@ sub get_list_of_tables {
});
my @dbh_tables = eval { $dbh->tables() };
+
+ ## Remove quotes around table names
+ my $quote = $dbh->get_info(29); # SQL_IDENTIFIER_QUOTE_CHAR
+ if ($quote) {
+ foreach (@dbh_tables) {
+ s/^$quote(.*)$quote$/$1/;
+ s/$quote$quote/$quote/g;
+ }
+ }
+
$dbh->disconnect();
return @dbh_tables;
}
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
index d73ba95ea0a..7b1d0383f46 100644
--- a/server-tools/instance-manager/Makefile.am
+++ b/server-tools/instance-manager/Makefile.am
@@ -50,11 +50,11 @@ libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \
CLEANFILES= net_serv.cc client_settings.h
-net_serv.cc: Makefile
+net_serv.cc:
rm -f $(srcdir)/net_serv.cc
@LN_CP_F@ $(top_srcdir)/sql/net_serv.cc $(srcdir)/net_serv.cc
-client_settings.h: Makefile
+client_settings.h:
rm -f $(srcdir)/client_settings.h
@LN_CP_F@ $(top_srcdir)/sql/client_settings.h $(srcdir)/client_settings.h
diff --git a/sql-common/client.c b/sql-common/client.c
index cca1452d710..2c73cb4d07c 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -1681,7 +1681,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE);
+ net->vio= vio_new(sock, VIO_TYPE_SOCKET,
+ VIO_LOCALHOST | VIO_BUFFERED_READ);
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
@@ -1756,7 +1757,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
ER(net->last_errno),socket_errno);
goto error;
}
- net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE);
+ net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
bzero((char*) &sock_addr,sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
@@ -2628,6 +2629,25 @@ mysql_fetch_row(MYSQL_RES *res)
}
+/**************************************************************************
+ Get column lengths of the current row
+ If one uses mysql_use_result, res->lengths contains the length information,
+ else the lengths are calculated from the offset between pointers.
+**************************************************************************/
+
+ulong * STDCALL
+mysql_fetch_lengths(MYSQL_RES *res)
+{
+ MYSQL_ROW column;
+
+ if (!(column=res->current_row))
+ return 0; /* Something is wrong */
+ if (res->data)
+ (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
+ return res->lengths;
+}
+
+
int STDCALL
mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
{
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 518f59eb853..06e7a2f0aa6 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -21,27 +21,27 @@
ha_federated.cc - MySQL Federated Storage Engine
Patrick Galbraith and Brian Aker, 2004
- This is a handler which uses a remote database as the data file, as
+ This is a handler which uses a foreign database as the data file, as
opposed to a handler like MyISAM, which uses .MYD files locally.
How this handler works
----------------------------------
- Normal database files are local and as such: You create a table called
- 'users', a file such as 'users.MYD' is created. A handler reads, inserts,
+ Normal database files are local and as such: You create a table called
+ 'users', a file such as 'users.MYD' is created. A handler reads, inserts,
deletes, updates data in this file. The data is stored in particular format,
so to read, that data has to be parsed into fields, to write, fields have to
- be stored in this format to write to this data file.
+ be stored in this format to write to this data file.
With MySQL Federated storage engine, there will be no local files for each
- table's data (such as .MYD). A remote database will store the data that would
- normally be in this file. This will necessitate the use of MySQL client API
+ table's data (such as .MYD). A foreign database will store the data that would
+ normally be in this file. This will necessitate the use of MySQL client API
to read, delete, update, insert this data. The data will have to be retrieve
via an SQL call "SELECT * FROM users". Then, to read this data, it will have
- to be retrieved via mysql_fetch_row one row at a time, then converted from
+ to be retrieved via mysql_fetch_row one row at a time, then converted from
the column in this select into the format that the handler expects.
- The create table will simply create the .frm file, and within the
- "CREATE TABLE" SQL, there SHALL be any of the following :
+ The create table will simply create the .frm file, and within the
+ "CREATE TABLE" SQL, there SHALL be any of the following :
comment=scheme://username:password@hostname:port/database/tablename
comment=scheme://username@hostname/database/tablename
@@ -57,41 +57,41 @@
Only 'mysql://' is supported at this release.
- This comment connection string is necessary for the handler to be
- able to connect to the remote server.
+ This comment connection string is necessary for the handler to be
+ able to connect to the foreign server.
The basic flow is this:
SQL calls issues locally ->
- mysql handler API (data in handler format) ->
- mysql client API (data converted to SQL calls) ->
- remote database -> mysql client API ->
+ mysql handler API (data in handler format) ->
+ mysql client API (data converted to SQL calls) ->
+ foreign database -> mysql client API ->
convert result sets (if any) to handler format ->
handler API -> results or rows affected to local
What this handler does and doesn't support
------------------------------------------
- * Tables MUST be created on the remote server prior to any action on those
- tables via the handler, first version. IMPORTANT: IF you MUST use the
+ * Tables MUST be created on the foreign server prior to any action on those
+ tables via the handler, first version. IMPORTANT: IF you MUST use the
federated storage engine type on the REMOTE end, MAKE SURE [ :) ] That
- the table you connect to IS NOT a table pointing BACK to your ORIGNAL
+ the table you connect to IS NOT a table pointing BACK to your ORIGNAL
table! You know and have heard the screaching of audio feedback? You
- know putting two mirror in front of each other how the reflection
+ know putting two mirror in front of each other how the reflection
continues for eternity? Well, need I say more?!
* There will not be support for transactions.
- * There is no way for the handler to know if the database on the remote end
+ * There is no way for the handler to know if the foreign database or table
has changed. The reason for this is that this database has to work like a
- data file that would never be written to by anything other than the
- database. The integrity of the data in the local table could be breached
- if there was any change to the remote database.
+ data file that would never be written to by anything other than the
+ database. The integrity of the data in the local table could be breached
+ if there was any change to the foreign database.
* Support for SELECT, INSERT, UPDATE , DELETE, indexes.
* No ALTER TABLE, DROP TABLE or any other Data Definition Language calls.
- * Prepared statements will not be used in the first implementation, it
+ * Prepared statements will not be used in the first implementation, it
remains to to be seen whether the limited subset of the client API for the
server supports this.
- * This uses SELECT, INSERT, UPDATE, DELETE and not HANDLER for its
- implementation.
+ * This uses SELECT, INSERT, UPDATE, DELETE and not HANDLER for its
+ implementation.
* This will not work with the query cache.
Method calls
@@ -100,7 +100,7 @@
(SELECT)
- "SELECT * FROM foo"
+ "SELECT * FROM foo"
ha_federated::info
ha_federated::scan_time:
ha_federated::rnd_init: share->select_query SELECT * FROM foo
@@ -140,7 +140,7 @@
ha_federated::rnd_next
ha_federated::convert_row_to_internal_format
ha_federated::update_row
-
+
<quote 3 cols, new and old data>
Field::quote_data
Field::quote_data
@@ -149,7 +149,7 @@
Field::quote_data
Field::quote_data
</quote 3 cols, new and old data>
-
+
ha_federated::extra
ha_federated::extra
ha_federated::extra
@@ -160,53 +160,53 @@
How do I use this handler?
--------------------------
First of all, you need to build this storage engine:
-
+
./configure --with-federated-storage-engine
make
- Next, to use this handler, it's very simple. You must
+ Next, to use this handler, it's very simple. You must
have two databases running, either both on the same host, or
on different hosts.
- One the server that will be connecting to the remote
+ One the server that will be connecting to the foreign
host (client), you create your table as such:
- CREATE TABLE test_table (
+ CREATE TABLE test_table (
id int(20) NOT NULL auto_increment,
name varchar(32) NOT NULL default '',
other int(20) NOT NULL default '0',
PRIMARY KEY (id),
KEY name (name),
- KEY other_key (other))
- ENGINE="FEDERATED"
- DEFAULT CHARSET=latin1
+ KEY other_key (other))
+ ENGINE="FEDERATED"
+ DEFAULT CHARSET=latin1
COMMENT='root@127.0.0.1:9306/federated/test_federated';
- Notice the "COMMENT" and "ENGINE" field? This is where you
- respectively set the engine type, "FEDERATED" and remote
- host information, this being the database your 'client' database
- will connect to and use as the "data file". Obviously, the remote
- database is running on port 9306, so you want to start up your other
- database so that it is indeed on port 9306, and your federated
- database on a port other than that. In my setup, I use port 5554
- for federated, and port 5555 for the remote.
+ Notice the "COMMENT" and "ENGINE" field? This is where you
+ respectively set the engine type, "FEDERATED" and foreign
+ host information, this being the database your 'client' database
+ will connect to and use as the "data file". Obviously, the foreign
+ database is running on port 9306, so you want to start up your other
+ database so that it is indeed on port 9306, and your federated
+ database on a port other than that. In my setup, I use port 5554
+ for federated, and port 5555 for the foreign database.
- Then, on the remote database:
+ Then, on the foreign database:
- CREATE TABLE test_table (
+ CREATE TABLE test_table (
id int(20) NOT NULL auto_increment,
name varchar(32) NOT NULL default '',
other int(20) NOT NULL default '0',
PRIMARY KEY (id),
KEY name (name),
- KEY other_key (other))
+ KEY other_key (other))
ENGINE="<NAME>" <-- whatever you want, or not specify
DEFAULT CHARSET=latin1 ;
This table is exactly the same (and must be exactly the same),
- except that it is not using the federated handler and does
+ except that it is not using the federated handler and does
not need the URL.
-
+
How to see the handler in action
--------------------------------
@@ -214,17 +214,17 @@
When developing this handler, I compiled the federated database with
debugging:
- ./configure --with-federated-storage-engine
+ ./configure --with-federated-storage-engine
--prefix=/home/mysql/mysql-build/federated/ --with-debug
Once compiled, I did a 'make install' (not for the purpose of installing
the binary, but to install all the files the binary expects to see in the
- diretory I specified in the build with --prefix,
- "/home/mysql/mysql-build/federated".
-
- Then, I started the remote server:
+ diretory I specified in the build with --prefix,
+ "/home/mysql/mysql-build/federated".
+
+ Then, I started the foreign server:
- /usr/local/mysql/bin/mysqld_safe
+ /usr/local/mysql/bin/mysqld_safe
--user=mysql --log=/tmp/mysqld.5555.log -P 5555
Then, I went back to the directory containing the newly compiled mysqld,
@@ -238,18 +238,18 @@
Next, I open several windows for each:
1. Tail the debug trace: tail -f /tmp/mysqld.trace|grep ha_fed
- 2. Tail the SQL calls to the remote database: tail -f /tmp/mysqld.5555.log
+ 2. Tail the SQL calls to the foreign database: tail -f /tmp/mysqld.5555.log
3. A window with a client open to the federated server on port 5554
4. A window with a client open to the federated server on port 5555
- I would create a table on the client to the remote server on port
+ I would create a table on the client to the foreign server on port
5555, and then to the federated server on port 5554. At this point,
I would run whatever queries I wanted to on the federated server,
- just always remembering that whatever changes I wanted to make on
+ just always remembering that whatever changes I wanted to make on
the table, or if I created new tables, that I would have to do that
- on the remote server.
-
- Another thing to look for is 'show variables' to show you that you have
+ on the foreign server.
+
+ Another thing to look for is 'show variables' to show you that you have
support for federated handler support:
show variables like '%federat%'
@@ -264,26 +264,26 @@
Testing
-------
- There is a test for MySQL Federated Storage Handler in ./mysql-test/t,
+ There is a test for MySQL Federated Storage Handler in ./mysql-test/t,
federatedd.test It starts both a slave and master database using
the same setup that the replication tests use, with the exception that
it turns off replication, and sets replication to ignore the test tables.
- After ensuring that you actually do have support for the federated storage
- handler, numerous queries/inserts/updates/deletes are run, many derived
+ After ensuring that you actually do have support for the federated storage
+ handler, numerous queries/inserts/updates/deletes are run, many derived
from the MyISAM tests, plus som other tests which were meant to reveal
any issues that would be most likely to affect this handler. All tests
should work! ;)
- To run these tests, go into ./mysql-test (based in the directory you
+ To run these tests, go into ./mysql-test (based in the directory you
built the server in)
./mysql-test-run federatedd
-
+
To run the test, or if you want to run the test and have debug info:
./mysql-test-run --debug federated
- This will run the test in debug mode, and you can view the trace and
+ This will run the test in debug mode, and you can view the trace and
log files in the ./mysql-test/var/log directory
ls -l mysql-test/var/log/
@@ -307,10 +307,10 @@
Of course, again, you can tail the trace log:
- tail -f mysql-test/var/log/master.trace |grep ha_fed
+ tail -f mysql-test/var/log/master.trace |grep ha_fed
As well as the slave query log:
-
+
tail -f mysql-test/var/log/slave.log
Files that comprise the test suit
@@ -324,7 +324,7 @@
Other tidbits
-------------
- These were the files that were modified or created for this
+ These were the files that were modified or created for this
Federated handler to work:
./configure.in
@@ -342,11 +342,11 @@
./mysql-test/include/have_federated_db.inc
./sql/ha_federated.cc
./sql/ha_federated.h
-
-*/
+
+*/
#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
+#pragma implementation // gcc: Class implementation
#endif
#include <mysql_priv.h>
@@ -355,40 +355,86 @@
#include "ha_federated.h"
#define MAX_REMOTE_SIZE IO_SIZE
/* Variables for federated share methods */
-static HASH federated_open_tables; // Hash used to track open tables
-pthread_mutex_t federated_mutex; // This is the mutex we use to init the hash
-static int federated_init= 0; // Variable for checking the init state of hash
+static HASH federated_open_tables; // Hash used to track open
+ // tables
+pthread_mutex_t federated_mutex; // This is the mutex we use to
+ // init the hash
+static int federated_init= FALSE; // Variable for checking the
+ // init state of hash
-/*
- Function we use in the creation of our hash to get key.
-*/
-static byte* federated_get_key(FEDERATED_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)))
+/* Function we use in the creation of our hash to get key. */
+
+static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
+ my_bool not_used __attribute__ ((unused)))
{
*length= share->table_name_length;
return (byte*) share->table_name;
}
/*
+ Initialize the federated handler.
+
+ SYNOPSIS
+ federated_db_init()
+ void
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool federated_db_init()
+{
+ federated_init= 1;
+ VOID(pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST));
+ return (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
+ (hash_get_key) federated_get_key, 0, 0));
+}
+
+
+/*
+ Release the federated handler.
+
+ SYNOPSIS
+ federated_db_end()
+ void
+
+ RETURN
+ FALSE OK
+*/
+
+bool federated_db_end()
+{
+ if (federated_init)
+ {
+ hash_free(&federated_open_tables);
+ VOID(pthread_mutex_destroy(&federated_mutex));
+ }
+ federated_init= 0;
+ return FALSE;
+}
+
+/*
Parse connection info from table->s->comment
SYNOPSIS
parse_url()
- share pointer to FEDERATED share
- table pointer to current TABLE class
+ share pointer to FEDERATED share
+ table pointer to current TABLE class
+ table_create_flag determines what error to throw
DESCRIPTION
populates the share with information about the connection
- to the remote database that will serve as the data source.
+ to the foreign database that will serve as the data source.
This string must be specified (currently) in the "comment" field,
listed in the CREATE TABLE statement.
This string MUST be in the format of any of these:
-scheme://username:password@hostname:port/database/table
-scheme://username@hostname/database/table
-scheme://username@hostname:port/database/table
-scheme://username:password@hostname/database/table
+ scheme://username:password@hostname:port/database/table
+ scheme://username@hostname/database/table
+ scheme://username@hostname:port/database/table
+ scheme://username:password@hostname/database/table
An Example:
@@ -401,32 +447,28 @@ scheme://username:password@hostname/database/table
RETURN VALUE
0 success
- -1 failure, wrong string format
+ 1 failure, wrong string format
*/
-static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_flag)
+
+static int parse_url(FEDERATED_SHARE *share, TABLE *table,
+ uint table_create_flag)
{
DBUG_ENTER("ha_federated::parse_url");
- // This either get set or will remain the same.
share->port= 0;
- uint error_num= table_create_flag ? ER_CANT_CREATE_TABLE : ER_CONNECT_TO_MASTER ;
+ uint error_num= (table_create_flag ? ER_CANT_CREATE_TABLE :
+ ER_CONNECT_TO_MASTER);
share->scheme= my_strdup(table->s->comment, MYF(0));
-
if ((share->username= strstr(share->scheme, "://")))
{
- share->scheme[share->username - share->scheme] = '\0';
+ share->scheme[share->username - share->scheme]= '\0';
+
if (strcmp(share->scheme, "mysql") != 0)
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("The federated handler currently only supports connecting\
- to a MySQL database!!!\n"));
- my_error(error_num, MYF(0),
- "ERROR: federated handler only supports remote 'mysql://' database");
- DBUG_RETURN(-1);
- }
+ goto error;
+
share->username+= 3;
if ((share->hostname= strchr(share->username, '@')))
@@ -439,35 +481,23 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla
share->username[share->password - share->username]= '\0';
share->password++;
share->username= share->username;
- // make sure there isn't an extra / or @
+ /* make sure there isn't an extra / or @ */
if ((strchr(share->password, '/') || strchr(share->hostname, '@')))
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
- /*
+ goto error;
+ /*
Found that if the string is:
-user:@hostname:port/database/table
-Then password is a null string, so set to NULL
- */
+ user:@hostname:port/database/table
+ Then password is a null string, so set to NULL
+ */
if ((share->password[0] == '\0'))
share->password= NULL;
}
else
share->username= share->username;
- // make sure there isn't an extra / or @
+ /* make sure there isn't an extra / or @ */
if ((strchr(share->username, '/')) || (strchr(share->hostname, '@')))
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
+ goto error;
if ((share->database= strchr(share->hostname, '/')))
{
@@ -490,102 +520,112 @@ Then password is a null string, so set to NULL
share->table_base_name++;
}
else
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
+ goto error;
}
else
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
- // make sure there's not an extra /
+ goto error;
+ /* make sure there's not an extra / */
if ((strchr(share->table_base_name, '/')))
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
+ goto error;
+
if (share->hostname[0] == '\0')
share->hostname= NULL;
- DBUG_PRINT("ha_federated::parse_url",
- ("scheme %s username %s password %s \
- 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));
- }
- else
- {
+ if (!share->port)
+ {
+ if (strcmp(share->hostname, my_localhost) == 0)
+ share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0));
+ else
+ share->port= MYSQL_PORT;
+ }
+
DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
+ ("scheme %s username %s password %s \
+ 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));
}
+ else
+ goto error;
}
else
- {
- DBUG_PRINT("ha_federated::parse_url",
- ("this connection string is not in the correct format!!!\n"));
- my_error(error_num, MYF(0),
- "this connection string is not in the correct format!!!\n");
- DBUG_RETURN(-1);
- }
+ goto error;
+
DBUG_RETURN(0);
+
+error:
+ my_error(error_num, MYF(0),
+ "this connection string is not in the correct format!\n");
+ DBUG_RETURN(1);
+
}
-/*
+/*
Convert MySQL result set row to handler internal format
SYNOPSIS
convert_row_to_internal_format()
- record Byte pointer to record
+ record Byte pointer to record
row MySQL result set row from fetchrow()
DESCRIPTION
- This method simply iterates through a row returned via fetchrow with
+ This method simply iterates through a row returned via fetchrow with
values from a successful SELECT , and then stores each column's value
in the field object via the field object pointer (pointing to the table's
- array of field object pointers). This is how the handler needs the data
+ array of field object pointers). This is how the handler needs the data
to be stored to then return results back to the user
RETURN VALUE
- 0 After fields have had field values stored from record
+ 0 After fields have had field values stored from record
*/
+
uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
{
- unsigned long len;
- int x= 0;
+ ulong *lengths;
+ uint num_fields;
+ uint x= 0;
+
DBUG_ENTER("ha_federated::convert_row_to_internal_format");
- // Question this
- memset(record, 0, table->s->null_bytes);
+ num_fields= mysql_num_fields(result);
+ lengths= mysql_fetch_lengths(result);
+
+ memset(record, 0, table->s->null_bytes);
- for (Field **field=table->field; *field ; field++, x++)
+ for (Field **field= table->field; *field; field++, x++)
{
- if (!row[x])
+ if (!row[x])
(*field)->set_null();
else
- /*
- changed system_charset_info to default_charset_info because
- testing revealed that german text was not being retrieved properly
- */
- (*field)->store(row[x], strlen(row[x]), &my_charset_bin);
+ (*field)->store(row[x], lengths[x], &my_charset_bin);
}
DBUG_RETURN(0);
}
+/*
+ Create a WHERE clause based off of values in keys
+ Note: This code was inspired by key_copy from key.cc
+
+ SYNOPSIS
+ create_where_from_key ()
+ to String object to store WHERE clause
+ key_info KEY struct pointer
+ key byte pointer containing key
+ key_length length of key
+
+ DESCRIPTION
+ Using iteration through all the keys via a KEY_PART_INFO pointer,
+ This method 'extracts' the value of each key in the byte pointer
+ *key, and for each key found, constructs an appropriate WHERE clause
+
+ RETURN VALUE
+ 0 After all keys have been accounted for to create the WHERE clause
+ 1 No keys found
+
+ */
+
bool ha_federated::create_where_from_key(String *to, KEY *key_info,
const byte *key, uint key_length)
{
@@ -595,29 +635,28 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
String tmp;
DBUG_ENTER("ha_federated::create_where_from_key");
- for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
+ for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
{
Field *field= key_part->field;
needs_quotes= field->needs_quotes();
- //bool needs_quotes= type_quote(field->type());
- DBUG_PRINT("ha_federated::create_where_from_key", ("key name %s type %d", field->field_name, field->type()));
uint length= key_part->length;
- if (second_loop++ && to->append(" AND ",5))
+ 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
+ if (to->append('`') || to->append(field->field_name) || to->append("` ", 2))
+ DBUG_RETURN(1); // Out of memory
if (key_part->null_bit)
{
if (*key++)
{
- if (to->append("IS NULL",7))
- DBUG_PRINT("ha_federated::create_where_from_key", ("NULL type %s", to->c_ptr_quick()));
+ if (to->append("IS NULL", 7))
DBUG_RETURN(1);
+
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("NULL type %s", to->c_ptr_quick()));
key_length-= key_part->store_length;
- key+= key_part->store_length-1;
+ key+= key_part->store_length - 1;
continue;
}
key_length--;
@@ -628,23 +667,24 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
DBUG_RETURN(1);
if (key_part->type == HA_KEYTYPE_BIT)
{
- /* This is can be threated as a hex string */
+ /* 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;
+ char buff[64 + 2], *ptr;
+ byte *end= (byte*)(key)+length;
- buff[0]='0';
- buff[1]='x';
- for (ptr= buff+2 ; key < end ; key++)
+ 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];
+ uint tmp= (uint)(uchar) *key;
+ *ptr++= _dig_vec_upper[tmp >> 4];
+ *ptr++= _dig_vec_upper[tmp & 15];
}
- if (to->append(buff, (uint) (ptr-buff)))
+ if (to->append(buff, (uint)(ptr - buff)))
DBUG_RETURN(1);
- DBUG_PRINT("ha_federated::create_where_from_key", ("bit type %s", to->c_ptr_quick()));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("bit type %s", to->c_ptr_quick()));
key_length-= length;
continue;
}
@@ -658,7 +698,8 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
if (append_escaped(to, &tmp))
DBUG_RETURN(1);
- DBUG_PRINT("ha_federated::create_where_from_key", ("blob type %s", to->c_ptr_quick()));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("blob type %s", to->c_ptr_quick()));
length= key_part->length;
}
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
@@ -669,29 +710,33 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
if (append_escaped(to, &tmp))
DBUG_RETURN(1);
- DBUG_PRINT("ha_federated::create_where_from_key", ("varchar type %s", to->c_ptr_quick()));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("varchar type %s", to->c_ptr_quick()));
}
else
{
- DBUG_PRINT("ha_federated::create_where_from_key", ("else block, unknown type so far"));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("else block, unknown type so far"));
char buff[MAX_FIELD_WIDTH];
String str(buff, sizeof(buff), field->charset()), *res;
- res= field->val_str(&str, (char *)(key));
+ res= field->val_str(&str, (char*) (key));
if (field->result_type() == STRING_RESULT)
{
if (append_escaped(to, res))
DBUG_RETURN(1);
- res= field->val_str(&str, (char *)(key));
+ res= field->val_str(&str, (char*) (key));
- DBUG_PRINT("ha_federated::create_where_from_key", ("else block, string type", to->c_ptr_quick()));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("else block, string type", to->c_ptr_quick()));
}
else if (to->append(res->ptr(), res->length()))
DBUG_RETURN(1);
}
if (needs_quotes && to->append("'"))
DBUG_RETURN(1);
- DBUG_PRINT("ha_federated::create_where_from_key", ("final value for 'to' %s", to->c_ptr_quick()));
+ DBUG_PRINT("ha_federated::create_where_from_key",
+ ("final value for 'to' %s", to->c_ptr_quick()));
key+= length;
key_length-= length;
DBUG_RETURN(0);
@@ -699,37 +744,12 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
DBUG_RETURN(1);
}
-int load_conn_info(FEDERATED_SHARE *share, TABLE *table)
-{
- DBUG_ENTER("ha_federated::load_conn_info");
- int retcode;
-
- retcode= parse_url(share, table, 0);
-
- if (retcode < 0)
- {
- DBUG_PRINT("ha_federated::load_conn_info",
- ("retcode %d, setting defaults", retcode));
- /* sanity checks to make sure all needed pieces are present */
- if (!share->port)
- {
- if (strcmp(share->hostname, "localhost") == 0)
- share->socket= my_strdup("/tmp/mysql.sock",MYF(0));
- else
- share->port= 3306;
- }
- }
- DBUG_PRINT("ha_federated::load_conn_info",
- ("returned from retcode %d", retcode));
-
- DBUG_RETURN(retcode);
-}
-
/*
Example of simple lock controls. The "share" it creates is structure we will
pass to each federated handler. Do you have to have one of these? Well, you
have pieces that are used for locking, and they are needed to function.
*/
+
static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
{
FEDERATED_SHARE *share;
@@ -740,79 +760,67 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
uint table_name_length, table_base_name_length;
char *tmp_table_name, *tmp_table_base_name, *table_base_name, *select_query;
- // share->table_name has the file location - we want the actual table's
- // name!
- table_base_name= (char *)table->s->table_name;
- DBUG_PRINT("ha_federated::get_share",("table_name %s", table_base_name));
+ /* share->table_name has the file location - we want the table's name! */
+ table_base_name= (char*) table->s->table_name;
+ DBUG_PRINT("ha_federated::get_share", ("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.
*/
- if (!federated_init)
- {
- /* Hijack a mutex for init'ing the storage engine */
- pthread_mutex_lock(&LOCK_mysql_create_db);
- if (!federated_init)
- {
- federated_init++;
- VOID(pthread_mutex_init(&federated_mutex,MY_MUTEX_INIT_FAST));
- (void) hash_init(&federated_open_tables,system_charset_info,32,0,0,
- (hash_get_key) federated_get_key,0,0);
- }
- pthread_mutex_unlock(&LOCK_mysql_create_db);
- }
pthread_mutex_lock(&federated_mutex);
table_name_length= (uint) strlen(table_name);
table_base_name_length= (uint) strlen(table_base_name);
- if (!(share= (FEDERATED_SHARE*) hash_search(&federated_open_tables,
- (byte*) table_name,
- table_name_length)))
+ if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables,
+ (byte*) table_name,
+ table_name_length)))
{
query.set_charset(system_charset_info);
query.append("SELECT * FROM ");
query.append(table_base_name);
-
+
if (!(share= (FEDERATED_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&share, sizeof(*share),
- &tmp_table_name, table_name_length+1,
- &tmp_table_base_name, table_base_name_length+1,
- &select_query, query.length()+1,
- NullS)))
+ &tmp_table_name, table_name_length + 1,
+ &tmp_table_base_name, table_base_name_length + 1,
+ &select_query, query.length() + 1, NullS)))
{
pthread_mutex_unlock(&federated_mutex);
return NULL;
}
- load_conn_info(share, table);
+ if (parse_url(share, table, 0))
+ goto error;
+
share->use_count= 0;
share->table_name_length= table_name_length;
share->table_name= tmp_table_name;
share->table_base_name_length= table_base_name_length;
share->table_base_name= tmp_table_base_name;
share->select_query= select_query;
- strmov(share->table_name,table_name);
- strmov(share->table_base_name,table_base_name);
- strmov(share->select_query,query.c_ptr_quick());
- DBUG_PRINT("ha_federated::get_share",("share->select_query %s", share->select_query));
+ strmov(share->table_name, table_name);
+ strmov(share->table_base_name, table_base_name);
+ strmov(share->select_query, query.ptr());
+ DBUG_PRINT("ha_federated::get_share",
+ ("share->select_query %s", share->select_query));
if (my_hash_insert(&federated_open_tables, (byte*) share))
goto error;
thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
}
share->use_count++;
pthread_mutex_unlock(&federated_mutex);
return share;
-error2:
- thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
error:
pthread_mutex_unlock(&federated_mutex);
+ if (share->scheme)
+ my_free((gptr) share->scheme, MYF(0));
+ VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0));
return NULL;
@@ -820,18 +828,23 @@ error:
/*
- Free lock controls. We call this whenever we close a table.
+ Free lock controls. We call this whenever we close a table.
If the table had the last reference to the share then we
free memory associated with it.
*/
+
static int free_share(FEDERATED_SHARE *share)
{
pthread_mutex_lock(&federated_mutex);
+
if (!--share->use_count)
{
+ if (share->scheme)
+ my_free((gptr) share->scheme, MYF(0));
+
hash_delete(&federated_open_tables, (byte*) share);
thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
+ VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0));
}
pthread_mutex_unlock(&federated_mutex);
@@ -842,12 +855,19 @@ static int free_share(FEDERATED_SHARE *share)
/*
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
+ what file extentions exist for the storage engine. This is
+ also used by the default rename_table and delete_table method
in handler.cc.
*/
+
const char **ha_federated::bas_ext() const
-{ static const char *ext[]= { NullS }; return ext; }
+{
+ static const char *ext[]=
+ {
+ NullS
+ };
+ return ext;
+}
/*
@@ -860,30 +880,30 @@ const char **ha_federated::bas_ext() const
all tables by calling ha_open() which then calls the handler
specific open().
*/
+
int ha_federated::open(const char *name, int mode, uint test_if_locked)
{
- DBUG_ENTER("ha_federated::open");
int rc;
+ DBUG_ENTER("ha_federated::open");
if (!(share= get_share(name, table)))
DBUG_RETURN(1);
- thr_lock_data_init(&share->lock,&lock,NULL);
-
- /* Connect to remote database mysql_real_connect() */
- mysql= mysql_init(0);
- DBUG_PRINT("ha_federated::open",("hostname %s", share->hostname));
- DBUG_PRINT("ha_federated::open",("username %s", share->username));
- DBUG_PRINT("ha_federated::open",("password %s", share->password));
- DBUG_PRINT("ha_federated::open",("database %s", share->database));
- DBUG_PRINT("ha_federated::open",("port %d", share->port));
+ thr_lock_data_init(&share->lock, &lock, NULL);
+
+ /* Connect to foreign database mysql_real_connect() */
+ mysql= mysql_init(0);
+ DBUG_PRINT("ha_federated::open", ("hostname %s", share->hostname));
+ DBUG_PRINT("ha_federated::open", ("username %s", share->username));
+ DBUG_PRINT("ha_federated::open", ("password %s", share->password));
+ DBUG_PRINT("ha_federated::open", ("database %s", share->database));
+ DBUG_PRINT("ha_federated::open", ("port %d", share->port));
if (!mysql_real_connect(mysql,
- share->hostname,
- share->username,
- share->password,
- share->database,
- share->port,
- NULL,
- 0))
+ share->hostname,
+ share->username,
+ share->password,
+ share->database,
+ share->port,
+ share->socket, 0))
{
my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_CONNECT_TO_MASTER);
@@ -902,9 +922,19 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
myisam table.
For sql_base.cc look at close_data_tables().
*/
+
int ha_federated::close(void)
{
DBUG_ENTER("ha_federated::close");
+
+ /* free the result set */
+ if (result)
+ {
+ DBUG_PRINT("ha_federated::close",
+ ("mysql_free_result result at address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
/* Disconnect from mysql */
mysql_close(mysql);
DBUG_RETURN(free_share(share));
@@ -913,7 +943,7 @@ int ha_federated::close(void)
/*
- Checks if a field in a record is SQL NULL.
+ Checks if a field in a record is SQL NULL.
SYNOPSIS
field_in_record_is_null()
@@ -923,16 +953,16 @@ int ha_federated::close(void)
DESCRIPTION
This method uses the record format information in table to track
- the null bit in record.
+ the null bit in record.
RETURN VALUE
1 if NULL
- 0 otherwise
+ 0 otherwise
*/
-inline uint field_in_record_is_null (
- TABLE* table, /* in: MySQL table object */
- Field* field, /* in: MySQL field object */
- char* record) /* in: a row in MySQL format */
+
+inline uint field_in_record_is_null(TABLE *table,
+ Field *field,
+ char *record)
{
int null_offset;
DBUG_ENTER("ha_federated::field_in_record_is_null");
@@ -940,7 +970,7 @@ inline uint field_in_record_is_null (
if (!field->null_ptr)
DBUG_RETURN(0);
- null_offset= (uint) ((char*) field->null_ptr - (char*) table->record[0]);
+ null_offset= (uint) ((char*)field->null_ptr - (char*)table->record[0]);
if (record[null_offset] & field->null_bit)
DBUG_RETURN(1);
@@ -961,59 +991,58 @@ inline uint field_in_record_is_null (
Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
*/
-int ha_federated::write_row(byte * buf)
+
+int ha_federated::write_row(byte *buf)
{
- int x= 0, num_fields= 0;
+ uint x= 0, num_fields= 0;
Field **field;
ulong current_query_id= 1;
ulong tmp_query_id= 1;
- int all_fields_have_same_query_id= 1;
+ uint all_fields_have_same_query_id= 1;
char insert_buffer[IO_SIZE];
char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE];
- // The main insert query string
+ /* 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
+ /* 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
+ /* 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);
+ sizeof(insert_field_value_buffer),
+ &my_charset_bin);
insert_field_value_string.length(0);
DBUG_ENTER("ha_federated::write_row");
- /*
- I want to use this and the next line, but the repository needs to be
- updated to do so
- */
- statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);
+
+ 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();
/*
- get the current query id - the fields that we add to the insert
- statement to send to the remote will not be appended unless they match
- this query id
+ get the current query id - the fields that we add to the insert
+ statement to send to the foreign will not be appended unless they match
+ this query id
*/
current_query_id= table->in_use->query_id;
DBUG_PRINT("ha_federated::write_row", ("current query id %d",
current_query_id));
- // start off our string
- insert_string.append("INSERT INTO ");
+ /* start off our string */
+ insert_string.append("INSERT INTO ");
insert_string.append(share->table_base_name);
- // start both our field and field values strings
+ /* start both our field and field values strings */
insert_string.append(" (");
values_string.append(" VALUES (");
- /*
+ /*
Even if one field is different, all_fields_same_query_id can't remain
0 if it remains 0, then that means no fields were specified in the query
such as in the case of INSERT INTO table VALUES (val1, val2, valN)
*/
- for (field= table->field; *field ; field++, x++)
+ for (field= table->field; *field; field++, x++)
{
if (x > 0 && tmp_query_id != (*field)->query_id)
all_fields_have_same_query_id= 0;
@@ -1024,15 +1053,15 @@ int ha_federated::write_row(byte * buf)
loop through the field pointer array, add any fields to both the values
list and the fields list that match the current query id
*/
- for (field= table->field; *field ; field++, x++)
+ for (field= table->field; *field; field++, x++)
{
DBUG_PRINT("ha_federated::write_row", ("field type %d", (*field)->type()));
// if there is a query id and if it's equal to the current query id
- if ( ((*field)->query_id && (*field)->query_id == current_query_id )
- || all_fields_have_same_query_id)
+ if (((*field)->query_id && (*field)->query_id == current_query_id)
+ || all_fields_have_same_query_id)
{
num_fields++;
-
+
if ((*field)->is_null())
{
DBUG_PRINT("ha_federated::write_row",
@@ -1046,24 +1075,23 @@ int ha_federated::write_row(byte * buf)
("current query id %d field is not null query ID %d",
current_query_id, (*field)->query_id));
(*field)->val_str(&insert_field_value_string);
+ /* quote these fields if they require it */
+ (*field)->quote_data(&insert_field_value_string);
}
- // append the field name
+ /* append the field name */
insert_string.append((*field)->field_name);
- // quote these fields if they require it
-
- (*field)->quote_data(&insert_field_value_string);
- // append the value
+ /* append the value */
values_string.append(insert_field_value_string);
insert_field_value_string.length(0);
- // append commas between both fields and fieldnames
+ /* append commas between both fields and fieldnames */
insert_string.append(',');
values_string.append(',');
- DBUG_PRINT("ha_federated::write_row",
- ("insert_string %s values_string %s insert_field_value_string %s",
- insert_string.c_ptr_quick(), values_string.c_ptr_quick(),
- insert_field_value_string.c_ptr_quick()));
+ DBUG_PRINT("ha_federated::write_row",
+ ("insert_string %s values_string %s insert_field_value_string %s",
+ insert_string.c_ptr_quick(), values_string.c_ptr_quick(),
+ insert_field_value_string.c_ptr_quick()));
}
}
@@ -1072,38 +1100,35 @@ int ha_federated::write_row(byte * buf)
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"
+ "INSERT INTO foo (field1, field2"
*/
insert_string.chop();
-
/*
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("ha_federated::write_row",("x %d num fields %d",
- x, num_fields));
+ DBUG_PRINT("ha_federated::write_row", ("x %d num fields %d", x, num_fields));
if (num_fields > 0)
{
- // chops off leading commas
+ /* chops off leading commas */
values_string.chop();
insert_string.append(')');
}
- // we always want to append this, even if there aren't any fields
+ /* we always want to append this, even if there aren't any fields */
values_string.append(')');
-
- // add the values
+
+ /* add the values */
insert_string.append(values_string);
- DBUG_PRINT("ha_federated::write_row",("insert query %s",
- insert_string.c_ptr_quick()));
+ DBUG_PRINT("ha_federated::write_row", ("insert query %s",
+ insert_string.c_ptr_quick()));
- if (mysql_real_query(mysql, insert_string.c_ptr_quick(),
- insert_string.length()))
+ 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);
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
}
DBUG_RETURN(0);
@@ -1125,54 +1150,54 @@ int ha_federated::write_row(byte * buf)
Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
*/
-int ha_federated::update_row(
- const byte * old_data,
- byte * new_data
- )
+
+int ha_federated::update_row(const byte *old_data, byte *new_data)
{
- int x= 0;
+ uint x= 0;
uint has_a_primary_key= 0;
- int primary_key_field_num;
+ 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];
- // 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), &my_charset_bin);
+ /* 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),
+ &my_charset_bin);
old_field_value.length(0);
- // stores the new value of the field
- String new_field_value(new_field_value_buffer, sizeof(new_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),
+ &my_charset_bin);
new_field_value.length(0);
- // stores the update query
+ /* stores the update query */
String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin);
update_string.length(0);
- // stores the WHERE clause
+ /* stores the WHERE clause */
String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin);
where_string.length(0);
DBUG_ENTER("ha_federated::update_row");
- 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;
+ 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("ha_federated::update_row", ("has a primary key"));
+ DBUG_PRINT("ha_federated::update_row", ("has a primary key"));
update_string.append("UPDATE ");
update_string.append(share->table_base_name);
update_string.append(" SET ");
/*
- In this loop, we want to match column names to values being inserted
- (while building INSERT statement).
+ In this loop, we want to match column names to values being inserted
+ (while building INSERT statement).
- Iterate through table->field (new data) and share->old_filed (old_data)
- using the same index to created an SQL UPDATE statement, new data is
- used to create SET field=value and old data is used to create WHERE
- field=oldvalue
+ Iterate through table->field (new data) and share->old_filed (old_data)
+ using the same index to created an SQL UPDATE statement, new data is
+ used to create SET field=value and old data is used to create WHERE
+ field=oldvalue
*/
-
- for (Field **field= table->field ; *field ; field++, x++)
+
+ for (Field **field= table->field; *field; field++, x++)
{
/*
In all of these tests for 'has_a_primary_key', what I'm trying to
@@ -1181,9 +1206,9 @@ int ha_federated::update_row(
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 (has_a_primary_key)
{
- if (x == primary_key_field_num)
+ if (x == primary_key_field_num)
where_string.append((*field)->field_name);
}
else
@@ -1196,65 +1221,63 @@ int ha_federated::update_row(
new_field_value.append("NULL");
else
{
- // otherwise =
+ /* otherwise = */
(*field)->val_str(&new_field_value);
(*field)->quote_data(&new_field_value);
- if ( has_a_primary_key )
+ 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("=");
+ else if (!field_in_record_is_null(table, *field, (char*) old_data))
+ where_string.append("=");
}
- if ( has_a_primary_key)
+ if (has_a_primary_key)
{
if (x == primary_key_field_num)
{
(*field)->val_str(&old_field_value,
- (char *)(old_data + (*field)->offset()));
+ (char*) (old_data + (*field)->offset()));
(*field)->quote_data(&old_field_value);
where_string.append(old_field_value);
}
}
else
{
- if (field_in_record_is_null(table, *field, (char*) old_data))
- where_string.append(" IS NULL ");
- else
- {
- (*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(" IS NULL ");
+ else
+ {
+ (*field)->val_str(&old_field_value,
+ (char*) (old_data + (*field)->offset()));
+ (*field)->quote_data(&old_field_value);
+ where_string.append(old_field_value);
+ }
}
update_string.append(new_field_value);
new_field_value.length(0);
- if ((uint) x+1 < table->s->fields)
+ if (x + 1 < table->s->fields)
{
update_string.append(", ");
- if (! has_a_primary_key)
+ if (!has_a_primary_key)
where_string.append(" AND ");
}
old_field_value.length(0);
}
update_string.append(" WHERE ");
- update_string.append(where_string.c_ptr_quick());
+ update_string.append(where_string);
if (! has_a_primary_key)
update_string.append(" LIMIT 1");
DBUG_PRINT("ha_federated::update_row", ("Final update query: %s",
update_string.c_ptr_quick()));
- if (mysql_real_query(mysql, update_string.c_ptr_quick(),
- update_string.length()))
+ 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);
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
}
@@ -1271,13 +1294,14 @@ int ha_federated::update_row(
ORDER BY clauses can be used.
Called in sql_acl.cc and sql_udf.cc to manage internal table information.
- Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select
+ Called in sql_delete.cc, sql_insert.cc, and sql_select.cc. In sql_select
it is used for removing duplicates while in insert it is used for REPLACE
calls.
*/
-int ha_federated::delete_row(const byte * buf)
+
+int ha_federated::delete_row(const byte *buf)
{
- int x= 0;
+ uint x= 0;
char delete_buffer[IO_SIZE];
char data_buffer[IO_SIZE];
@@ -1292,7 +1316,7 @@ int ha_federated::delete_row(const byte * buf)
delete_string.append(share->table_base_name);
delete_string.append(" WHERE ");
- for (Field **field= table->field; *field; field++, x++)
+ for (Field **field= table->field; *field; field++, x++)
{
delete_string.append((*field)->field_name);
@@ -1307,22 +1331,21 @@ int ha_federated::delete_row(const byte * buf)
(*field)->val_str(&data_string);
(*field)->quote_data(&data_string);
}
-
+
delete_string.append(data_string);
data_string.length(0);
- if ((uint) x+1 < table->s->fields)
+ if (x + 1 < table->s->fields)
delete_string.append(" AND ");
}
delete_string.append(" LIMIT 1");
DBUG_PRINT("ha_federated::delete_row",
("Delete sql: %s", delete_string.c_ptr_quick()));
- if ( mysql_real_query(mysql, delete_string.c_ptr_quick(),
- delete_string.length()))
+ 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);
+ my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
}
DBUG_RETURN(0);
@@ -1335,10 +1358,11 @@ int ha_federated::delete_row(const byte * buf)
index. This method, which is called in the case of an SQL statement having
a WHERE clause on a non-primary key index, simply calls index_read_idx.
*/
-int ha_federated::index_read(byte * buf, const byte * key,
- uint key_len __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
+
+int ha_federated::index_read(byte *buf, const byte *key,
+ uint key_len __attribute__ ((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__ ((unused)))
{
DBUG_ENTER("ha_federated::index_read");
DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag));
@@ -1350,13 +1374,14 @@ int ha_federated::index_read(byte * buf, const byte * key,
row if any. This is only used to read whole keys.
This method is called via index_read in the case of a WHERE clause using
- a regular non-primary key index, OR is called DIRECTLY when the WHERE clause
+ a regular non-primary key index, OR is called DIRECTLY when the WHERE clause
uses a PRIMARY KEY index.
*/
-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)))
+
+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)))
{
char index_value[IO_SIZE];
char key_value[IO_SIZE];
@@ -1370,27 +1395,34 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key,
sql_query.length(0);
DBUG_ENTER("ha_federated::index_read_idx");
- statistic_increment(table->in_use->status_var.ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
sql_query.append(share->select_query);
sql_query.append(" WHERE ");
- keylen= strlen((char *)(key));
+ keylen= strlen((char*) (key));
create_where_from_key(&index_string, &table->key_info[index], key, keylen);
sql_query.append(index_string);
DBUG_PRINT("ha_federated::index_read_idx",
- ("current key %d key value %s index_string value %s length %d", index, (char *)(key),index_string.c_ptr_quick(),
- index_string.length()));
+ ("current key %d key value %s index_string value %s length %d",
+ index, (char*) key, index_string.c_ptr_quick(),
+ index_string.length()));
DBUG_PRINT("ha_federated::index_read_idx",
- ("current position %d sql_query %s", current_position,
- sql_query.c_ptr_quick()));
+ ("current position %d sql_query %s", current_position,
+ sql_query.c_ptr_quick()));
- if (mysql_real_query(mysql, sql_query.c_ptr_quick(), sql_query.length()))
+ if (result)
+ {
+ mysql_free_result(result);
+ 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_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
+ DBUG_RETURN(ER_QUERY_ON_MASTER);
}
result= mysql_store_result(mysql);
@@ -1403,15 +1435,13 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key,
if (mysql_errno(mysql))
{
table->status= STATUS_NOT_FOUND;
- DBUG_RETURN(mysql_errno(mysql));
+ DBUG_RETURN(mysql_errno(mysql));
}
DBUG_RETURN(rnd_next(buf));
}
-/*
- Initialized at each key walk (called multiple times unlike ::rnd_init())
-*/
+/* Initialized at each key walk (called multiple times unlike rnd_init()) */
int ha_federated::index_init(uint keynr)
{
int error;
@@ -1422,10 +1452,8 @@ int ha_federated::index_init(uint keynr)
DBUG_RETURN(0);
}
-/*
- Used to read forward through the index.
-*/
-int ha_federated::index_next(byte * buf)
+/* Used to read forward through the index. */
+int ha_federated::index_next(byte *buf)
{
DBUG_ENTER("ha_federated::index_next");
DBUG_RETURN(rnd_next(buf));
@@ -1444,28 +1472,84 @@ int ha_federated::index_next(byte * buf)
Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
sql_table.cc, and sql_update.cc.
*/
+
int ha_federated::rnd_init(bool scan)
{
DBUG_ENTER("ha_federated::rnd_init");
int num_fields, rows;
- DBUG_PRINT("ha_federated::rnd_init",
- ("share->select_query %s", share->select_query));
- if (mysql_real_query(mysql, share->select_query, strlen(share->select_query)))
+ /*
+ This '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
+ the foreign database.
+
+ When there is NO index in the query, either due to not having a WHERE
+ clause, or the WHERE clause is using columns that are not indexed, a
+ 'full table scan' done by rnd_init, which in this situation simply means
+ a 'select * from ...' on the foreign table.
+
+ In other words, this 'scan' flag gives us the means to ensure that if
+ there is an index involved in the query, we want index_read_idx to
+ retrieve the exact record (scan flag is 0), and do not want rnd_init
+ to do a 'full table scan' and wipe out that result set.
+
+ Prior to using this flag, the problem was most apparent with updates.
+
+ An initial query like 'UPDATE tablename SET anything = whatever WHERE
+ indexedcol = someval', index_read_idx would get called, using a query
+ constructed with a WHERE clause built from the values of index ('indexcol'
+ in this case, having a value of 'someval'). mysql_store_result would
+ then get called (this would be the result set we want to use).
+
+ After this rnd_init (from sql_update.cc) would be called, it would then
+ unecessarily call "select * from table" on the foreign table, then call
+ mysql_store_result, which would wipe out the correct previous result set
+ from the previous call of index_read_idx's that had the result set
+ containing the correct record, hence update the wrong row!
+
+ */
+ scan_flag= scan;
+ if (scan)
{
- my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql));
- DBUG_RETURN(ER_QUERY_ON_MASTER);
- }
- result= mysql_store_result(mysql);
+ DBUG_PRINT("ha_federated::rnd_init",
+ ("share->select_query %s", share->select_query));
+ if (result)
+ {
+ DBUG_PRINT("ha_federated::rnd_init",
+ ("mysql_free_result address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
- if (mysql_errno(mysql))
- DBUG_RETURN(mysql_errno(mysql));
+ 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_errno(mysql))
+ DBUG_RETURN(mysql_errno(mysql));
+ }
DBUG_RETURN(0);
}
int ha_federated::rnd_end()
{
DBUG_ENTER("ha_federated::rnd_end");
+ if (result)
+ {
+ DBUG_PRINT("ha_federated::index_end",
+ ("mysql_free_result address %lx", result));
+ mysql_free_result(result);
+ result= 0;
+ }
+
mysql_free_result(result);
DBUG_RETURN(index_end());
}
@@ -1486,17 +1570,20 @@ int ha_federated::index_end(void)
Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc,
sql_table.cc, and sql_update.cc.
*/
+
int ha_federated::rnd_next(byte *buf)
{
MYSQL_ROW row;
DBUG_ENTER("ha_federated::rnd_next");
- // Fetch a row, insert it back in a row format.
+ /* Fetch a row, insert it back in a row format. */
current_position= result->data_cursor;
- if (! (row= mysql_fetch_row(result)))
+ DBUG_PRINT("ha_federated::rnd_next",
+ ("current position %d", current_position));
+ if (!(row= mysql_fetch_row(result)))
DBUG_RETURN(HA_ERR_END_OF_FILE);
-
- DBUG_RETURN(convert_row_to_internal_format(buf,row));
+
+ DBUG_RETURN(convert_row_to_internal_format(buf, row));
}
@@ -1513,11 +1600,12 @@ int ha_federated::rnd_next(byte *buf)
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
*/
+
void ha_federated::position(const byte *record)
{
DBUG_ENTER("ha_federated::position");
- //my_store_ptr Add seek storage
- *(MYSQL_ROW_OFFSET *)ref=current_position; // ref is always aligned
+ /* my_store_ptr Add seek storage */
+ *(MYSQL_ROW_OFFSET *) ref= current_position; // ref is always aligned
DBUG_VOID_RETURN;
}
@@ -1532,14 +1620,25 @@ void ha_federated::position(const byte *record)
Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc.
*/
-int ha_federated::rnd_pos(byte * buf, byte *pos)
+int ha_federated::rnd_pos(byte *buf, byte *pos)
{
DBUG_ENTER("ha_federated::rnd_pos");
- 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));
+ /*
+ we do not need to do any of this if there has been a scan performed
+ already, or if this is an update and index_read_idx already has a result
+ set in which to build it's update query from
+ */
+ if (scan_flag)
+ {
+ 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));
+ }
+ DBUG_RETURN(0);
}
@@ -1586,11 +1685,12 @@ int ha_federated::rnd_pos(byte * buf, byte *pos)
sql_update.cc
*/
-// FIX: later version provide better information to the optimizer
+/* FIX: later version provide better information to the optimizer */
+
void ha_federated::info(uint flag)
{
DBUG_ENTER("ha_federated::info");
- records= 10000; // Fake!
+ records= 10000; // fix later
DBUG_VOID_RETURN;
}
@@ -1606,6 +1706,7 @@ void ha_federated::info(uint flag)
Called from sql_select.cc by JOIN::reinit().
Called from sql_union.cc by st_select_lex_unit::exec().
*/
+
int ha_federated::delete_all_rows()
{
DBUG_ENTER("ha_federated::delete_all_rows");
@@ -1618,9 +1719,10 @@ int ha_federated::delete_all_rows()
query.append("TRUNCATE ");
query.append(share->table_base_name);
- if (mysql_real_query(mysql, query.c_ptr_quick(), query.length())) {
- my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql));
- DBUG_RETURN(ER_QUERY_ON_MASTER);
+ 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);
}
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -1656,33 +1758,33 @@ int ha_federated::delete_all_rows()
Called from lock.cc by get_lock_data().
*/
+
THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
- THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
{
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
{
- /*
+ /*
Here is where we get into the guts of a row level lock.
- If TL_UNLOCK is set
+ If TL_UNLOCK is set
If we are not doing a LOCK TABLE or DISCARD/IMPORT
- TABLESPACE, then allow multiple writers
+ TABLESPACE, then allow multiple writers
*/
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 && !thd->tablespace_op)
lock_type= TL_WRITE_ALLOW_WRITE;
- /*
+ /*
In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
to t2. Convert the lock to a normal read lock to allow
- concurrent inserts to t2.
+ concurrent inserts to t2.
*/
- if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
+ if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
lock_type= TL_READ;
lock.type= lock_type;
@@ -1695,23 +1797,20 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
/*
create() does nothing, since we have no local setup of our own.
- FUTURE: We should potentially connect to the remote database and
- create tables if they do not exist.
+ FUTURE: We should potentially connect to the foreign database and
*/
+
int ha_federated::create(const char *name, TABLE *table_arg,
- HA_CREATE_INFO *create_info)
+ HA_CREATE_INFO *create_info)
{
- int retcode;
FEDERATED_SHARE tmp;
DBUG_ENTER("ha_federated::create");
- retcode= parse_url(&tmp, table_arg, 1);
- if (retcode < 0)
+ if (parse_url(&tmp, table_arg, 1))
{
- DBUG_PRINT("ha_federated::create",
- ("ERROR: on table creation for %s called parse_url, retcode %d",
- create_info->data_file_name, retcode));
+ my_error(ER_CANT_CREATE_TABLE, MYF(0));
DBUG_RETURN(ER_CANT_CREATE_TABLE);
}
+ my_free((gptr) tmp.scheme, MYF(0));
DBUG_RETURN(0);
}
#endif /* HAVE_FEDERATED_DB */
diff --git a/sql/ha_federated.h b/sql/ha_federated.h
index 75f2c227d45..22fc03e9eec 100755..100644
--- a/sql/ha_federated.h
+++ b/sql/ha_federated.h
@@ -32,13 +32,16 @@
FEDERATED_SHARE is a structure that will be shared amoung all open handlers
The example implements the minimum of what you will probably need.
*/
-//FIX document
typedef struct st_federated_share {
char *table_name;
char *table_base_name;
- // the primary select query to be used in rnd_init
+ /*
+ the primary select query to be used in rnd_init
+ */
char *select_query;
- // remote host info, parse_url supplies
+ /*
+ remote host info, parse_url supplies
+ */
char *scheme;
char *hostname;
char *username;
@@ -62,6 +65,7 @@ class ha_federated: public handler
FEDERATED_SHARE *share; /* Shared lock info */
MYSQL *mysql;
MYSQL_RES *result;
+ bool scan_flag;
uint ref_length;
uint fetch_num; // stores the fetch num
MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
@@ -72,11 +76,12 @@ private:
return errorcode otherwise
*/
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);
+ bool create_where_from_key(String *to, KEY *key_info,
+ const byte *key, uint key_length);
public:
ha_federated(TABLE *table): handler(table),
- mysql(0),
+ mysql(0), result(0), scan_flag(0),
ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
{
}
@@ -100,9 +105,9 @@ public:
*/
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_TABLE_SCAN_ON_INDEX | HA_CAN_INDEX_BLOBS);
+ 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);
}
/*
This is a bitmap of flags that says how the storage engine
@@ -126,11 +131,16 @@ public:
/*
Called in test_quick_select to determine if indexes should be used.
*/
- virtual double scan_time() { DBUG_PRINT("ha_federated::scan_time", ("rows %d", records)); return (double)(records*2); }
+ virtual double scan_time()
+ {
+ DBUG_PRINT("ha_federated::scan_time",
+ ("rows %d", records)); return (double)(records*2);
+ }
/*
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; }
+ virtual double read_time(uint index, uint ranges, ha_rows rows)
+ { return (double) rows / 20.0+1; }
/*
Everything below are methods that we implment in ha_federated.cc.
@@ -173,3 +183,6 @@ public:
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); //required
};
+
+bool federated_db_init(void);
+bool federated_db_end(void);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index f68ad99ac44..4dee14c27b4 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & Innobase Oy
+/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -336,14 +336,18 @@ innobase_release_temporary_latches(
/*===============================*/
THD *thd)
{
+ trx_t* trx;
+
if (!innodb_inited) {
return;
}
- trx_t *trx= (trx_t*) thd->ha_data[innobase_hton.slot];
- if (trx)
- innobase_release_stat_resources(trx);
+ trx = (trx_t*) thd->ha_data[innobase_hton.slot];
+
+ if (trx) {
+ innobase_release_stat_resources(trx);
+ }
}
/************************************************************************
@@ -743,14 +747,15 @@ transaction internally. */
static
void
register_trans(
-/*============*/
+/*===========*/
THD* thd) /* in: thd to use the handle */
{
- /* register the start of the statement */
+ /* Register the start of the statement */
trans_register_ha(thd, FALSE, &innobase_hton);
+
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
- /* no autocommit mode, register for a transaction */
+ /* No autocommit mode, register for a transaction */
trans_register_ha(thd, TRUE, &innobase_hton);
}
}
@@ -1051,7 +1056,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/*************************************************************************
Opens an InnoDB database. */
-handlerton *
+handlerton*
innobase_init(void)
/*===============*/
/* out: TRUE if error */
@@ -1220,7 +1225,7 @@ innobase_init(void)
srv_print_verbose_log = mysqld_embedded ? 0 : 1;
- /* Store the default charset-collation number of this MySQL
+ /* Store the default charset-collation number of this MySQL
installation */
data_mysql_default_charset_coll = (ulint)default_charset_info->number;
@@ -1346,14 +1351,16 @@ innobase_commit_low(
return;
}
-#ifdef DISABLE_HAVE_REPLICATION
- if (current_thd->slave_thread) {
+#ifdef HAVE_REPLICATION
+ THD *thd=current_thd;
+
+ if (thd && thd->slave_thread) {
/* Update the replication position info inside InnoDB */
trx->mysql_master_log_file_name
= active_mi->rli.group_master_log_name;
- trx->mysql_master_log_pos= ((ib_longlong)
- active_mi->rli.future_group_master_log_pos);
+ trx->mysql_master_log_pos = ((ib_longlong)
+ active_mi->rli.future_group_master_log_pos);
}
#endif /* HAVE_REPLICATION */
@@ -1456,7 +1463,8 @@ innobase_commit(
"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
}
- if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
+ if (all
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
/* We were instructed to commit the whole transaction, or
this is an SQL statement end and autocommit is on */
@@ -1489,10 +1497,9 @@ innobase_commit(
DBUG_RETURN(0);
}
-/*
- don't delete it - it may be re-enabled later
- as an optimization for the most common case InnoDB+binlog
-*/
+/* The following defined-out code will be enabled later when we put the
+MySQL-4.1 functionality back to 5.0. This is needed to get InnoDB Hot Backup
+to work. */
#if 0
/*********************************************************************
This is called when MySQL writes the binlog entry for the current
@@ -1627,7 +1634,8 @@ innobase_rollback(
row_unlock_table_autoinc_for_mysql(trx);
}
- if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
+ if (all
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
error = trx_rollback_for_mysql(trx);
trx->active_trans = 0;
@@ -1686,6 +1694,7 @@ innobase_rollback_to_savepoint(
ib_longlong mysql_binlog_cache_pos;
int error = 0;
trx_t* trx;
+ char name[64];
DBUG_ENTER("innobase_rollback_to_savepoint");
@@ -1698,8 +1707,8 @@ innobase_rollback_to_savepoint(
innobase_release_stat_resources(trx);
/* TODO: use provided savepoint data area to store savepoint data */
- char name[64];
- longlong2str((ulonglong)savepoint,name,36);
+
+ longlong2str((ulonglong)savepoint, name, 36);
error = trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
@@ -1708,26 +1717,27 @@ innobase_rollback_to_savepoint(
/*********************************************************************
Release transaction savepoint name. */
-
-static int
+static
+int
innobase_release_savepoint(
-/*===========================*/
+/*=======================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- void *savepoint) /* in: savepoint data */
+ void* savepoint) /* in: savepoint data */
{
int error = 0;
trx_t* trx;
+ char name[64];
DBUG_ENTER("innobase_release_savepoint");
trx = check_trx_exists(thd);
/* TODO: use provided savepoint data area to store savepoint data */
- char name[64];
- longlong2str((ulonglong)savepoint,name,36);
+
+ longlong2str((ulonglong)savepoint, name, 36);
error = trx_release_savepoint_for_mysql(trx, name);
@@ -1736,13 +1746,13 @@ innobase_release_savepoint(
/*********************************************************************
Sets a transaction savepoint. */
-
-static int
+static
+int
innobase_savepoint(
/*===============*/
/* out: always 0, that is, always succeeds */
THD* thd, /* in: handle to the MySQL thread */
- void *savepoint) /* in: savepoint data */
+ void* savepoint) /* in: savepoint data */
{
int error = 0;
trx_t* trx;
@@ -1911,7 +1921,8 @@ ha_innobase::open(
fields when packed actually became 1 byte longer, when we also
stored the string length as the first byte. */
- upd_and_key_val_buff_len = table->s->reclength + table->s->max_key_length
+ upd_and_key_val_buff_len =
+ table->s->reclength + table->s->max_key_length
+ MAX_REF_PARTS * 3;
if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME),
&upd_buff, upd_and_key_val_buff_len,
@@ -1963,7 +1974,8 @@ ha_innobase::open(
innobase_prebuilt = row_create_prebuilt(ib_table);
- ((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len = table->s->reclength;
+ ((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len =
+ table->s->reclength;
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
@@ -1985,13 +1997,11 @@ ha_innobase::open(
((row_prebuilt_t*)innobase_prebuilt)
->clust_index_was_generated = FALSE;
- /*
- MySQL allocates the buffer for ref. key_info->key_length
- includes space for all key columns + one byte for each column
- that may be NULL. ref_length must be as exact as possible to
- save space, because all row reference buffers are allocated
- based on ref_length.
- */
+ /* MySQL allocates the buffer for ref. key_info->key_length
+ includes space for all key columns + one byte for each column
+ that may be NULL. ref_length must be as exact as possible to
+ save space, because all row reference buffers are allocated
+ based on ref_length. */
ref_length = table->key_info[primary_key].key_length;
} else {
@@ -2013,15 +2023,13 @@ ha_innobase::open(
ref_length = DATA_ROW_ID_LEN;
- /*
- If we automatically created the clustered index, then
- MySQL does not know about it, and MySQL must NOT be aware
- of the index used on scan, to make it avoid checking if we
- update the column of the index. That is why we assert below
- that key_used_on_scan is the undefined value MAX_KEY.
- The column is the row id in the automatical generation case,
- and it will never be updated anyway.
- */
+ /* If we automatically created the clustered index, then
+ MySQL does not know about it, and MySQL must NOT be aware
+ of the index used on scan, to make it avoid checking if we
+ update the column of the index. That is why we assert below
+ that key_used_on_scan is the undefined value MAX_KEY.
+ The column is the row id in the automatical generation case,
+ and it will never be updated anyway. */
if (key_used_on_scan != MAX_KEY) {
fprintf(stderr,
@@ -2611,7 +2619,8 @@ ha_innobase::write_row(
"InnoDB: Dump of 200 bytes around transaction.all: ",
stderr);
ut_print_buf(stderr,
- ((byte*)(&(current_thd->ha_data[innobase_hton.slot]))) - 100, 200);
+ ((byte*)(&(current_thd->ha_data[innobase_hton.slot]))) - 100,
+ 200);
putc('\n', stderr);
ut_error;
}
@@ -2622,7 +2631,10 @@ ha_innobase::write_row(
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
- if (user_thd->lex->sql_command == SQLCOM_ALTER_TABLE
+ if ((user_thd->lex->sql_command == SQLCOM_ALTER_TABLE
+ || user_thd->lex->sql_command == SQLCOM_OPTIMIZE
+ || user_thd->lex->sql_command == SQLCOM_CREATE_INDEX
+ || user_thd->lex->sql_command == SQLCOM_DROP_INDEX)
&& num_write_row >= 10000) {
/* ALTER TABLE is COMMITted at every 10000 copied rows.
The IX table lock for the original table has to be re-issued.
@@ -2646,7 +2658,7 @@ ha_innobase::write_row(
src_table = lock_get_src_table(
prebuilt->trx, prebuilt->table, &mode);
if (!src_table) {
- no_commit:
+no_commit:
/* Unknown situation: do not commit */
/*
ut_print_timestamp(stderr);
@@ -2669,6 +2681,7 @@ ha_innobase::write_row(
} else {
/* Ensure that there are no other table locks than
LOCK_IX and LOCK_AUTO_INC on the destination table. */
+
if (!lock_is_table_exclusive(prebuilt->table,
prebuilt->trx)) {
goto no_commit;
@@ -2746,11 +2759,11 @@ ha_innobase::write_row(
if (error == DB_SUCCESS && auto_inc_used) {
- /* Fetch the value that was set in the autoincrement field */
+ /* Fetch the value that was set in the autoincrement field */
- auto_inc = table->next_number_field->val_int();
+ auto_inc = table->next_number_field->val_int();
- if (auto_inc != 0) {
+ if (auto_inc != 0) {
/* This call will calculate the max of the current
value and the value supplied by the user and
update the counter accordingly */
@@ -2762,15 +2775,15 @@ ha_innobase::write_row(
The lock is released at each SQL statement's
end. */
- error = row_lock_table_autoinc_for_mysql(prebuilt);
+ error = row_lock_table_autoinc_for_mysql(prebuilt);
- if (error != DB_SUCCESS) {
-
- error = convert_error_code_to_mysql(error, user_thd);
- goto func_exit;
- }
- dict_table_autoinc_update(prebuilt->table, auto_inc);
- }
+ if (error != DB_SUCCESS) {
+ error = convert_error_code_to_mysql(error,
+ user_thd);
+ goto func_exit;
+ }
+ dict_table_autoinc_update(prebuilt->table, auto_inc);
+ }
}
innodb_srv_conc_exit_innodb(prebuilt->trx);
@@ -2785,7 +2798,6 @@ func_exit:
DBUG_RETURN(error);
}
-
/******************************************************************
Converts field data for storage in an InnoDB update vector. */
inline
@@ -3071,9 +3083,6 @@ ha_innobase::unlock_row(void)
DBUG_ENTER("ha_innobase::unlock_row");
- ut_ad(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
-
if (last_query_id != user_thd->query_id) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -4256,8 +4265,6 @@ ha_innobase::delete_all_rows(void)
goto fallback;
}
- innobase_commit(thd, 1);
-
error = convert_error_code_to_mysql(error, NULL);
DBUG_RETURN(error);
@@ -4514,10 +4521,10 @@ ha_innobase::records_in_range(
dict_index_t* index;
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc(
table->s->reclength
- + table->s->max_key_length + 100,
+ + table->s->max_key_length + 100,
MYF(MY_WME));
ulint buff2_len = table->s->reclength
- + table->s->max_key_length + 100;
+ + table->s->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
ib_longlong n_rows;
@@ -4674,21 +4681,27 @@ ha_innobase::read_time(
ha_rows total_rows;
double time_for_scan;
- if (index != table->s->primary_key)
- return handler::read_time(index, ranges, rows); // Not clustered
+ if (index != table->s->primary_key) {
+ /* Not clustered */
+ return(handler::read_time(index, ranges, rows));
+ }
- if (rows <= 2)
- return (double) rows;
+ if (rows <= 2) {
+
+ return((double) rows);
+ }
/* Assume that the read time is proportional to the scan time for all
rows + at most one seek per range. */
time_for_scan = scan_time();
- if ((total_rows = estimate_rows_upper_bound()) < rows)
- return time_for_scan;
+ if ((total_rows = estimate_rows_upper_bound()) < rows) {
- return (ranges + (double) rows / (double) total_rows * time_for_scan);
+ return(time_for_scan);
+ }
+
+ return(ranges + (double) rows / (double) total_rows * time_for_scan);
}
/*************************************************************************
@@ -5106,7 +5119,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
tmp_buff, i, 1);
tmp_buff+= i + 1;
f_key_info.referenced_table= make_lex_string(thd, 0,
- tmp_buff, strlen(tmp_buff), 1);
+ tmp_buff, strlen(tmp_buff), 1);
for (i= 0;;)
{
@@ -5624,7 +5637,6 @@ innodb_export_status(void)
srv_export_innodb_status();
}
-
/****************************************************************************
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
Monitor to the client. */
@@ -5636,6 +5648,8 @@ innodb_show_status(
{
Protocol *protocol= thd->protocol;
trx_t* trx;
+ long flen;
+ char* str;
DBUG_ENTER("innodb_show_status");
@@ -5652,14 +5666,13 @@ innodb_show_status(
/* We let the InnoDB Monitor to output at most 64000 bytes of text. */
- long flen;
- char* str;
-
mutex_enter_noninline(&srv_monitor_file_mutex);
rewind(srv_monitor_file);
+
srv_printf_innodb_monitor(srv_monitor_file);
flen = ftell(srv_monitor_file);
os_file_set_eof(srv_monitor_file);
+
if (flen < 0) {
flen = 0;
} else if (flen > 64000 - 1) {
@@ -5669,10 +5682,10 @@ innodb_show_status(
/* allocate buffer for the string, and
read the contents of the temporary file */
- if (!(str = my_malloc(flen + 1, MYF(0))))
- {
- mutex_exit_noninline(&srv_monitor_file_mutex);
- DBUG_RETURN(TRUE);
+ if (!(str = my_malloc(flen + 1, MYF(0)))) {
+ mutex_exit_noninline(&srv_monitor_file_mutex);
+
+ DBUG_RETURN(TRUE);
}
rewind(srv_monitor_file);
@@ -5686,7 +5699,6 @@ innodb_show_status(
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF)) {
-
my_free(str, MYF(0));
DBUG_RETURN(TRUE);
@@ -5696,10 +5708,12 @@ innodb_show_status(
protocol->store(str, flen, system_charset_info);
my_free(str, MYF(0));
- if (protocol->write())
- DBUG_RETURN(TRUE);
+ if (protocol->write()) {
+ DBUG_RETURN(TRUE);
+ }
send_eof(thd);
+
DBUG_RETURN(FALSE);
}
@@ -6093,7 +6107,7 @@ ha_innobase::get_auto_increment()
if (error) {
- return(~(ulonglong) 0);
+ return(~(ulonglong) 0);
}
return((ulonglong) nr);
@@ -6115,7 +6129,8 @@ ha_innobase::cmp_ref(
/* Do type-aware comparison of Primary Key members. PK members
are always NOT NULL, so no checks for NULL are performed */
- KEY_PART_INFO *key_part= table->key_info[table->s->primary_key].key_part;
+ KEY_PART_INFO *key_part=
+ table->key_info[table->s->primary_key].key_part;
KEY_PART_INFO *key_part_end=
key_part + table->key_info[table->s->primary_key].key_parts;
for (; key_part != key_part_end; ++key_part) {
@@ -6260,19 +6275,21 @@ innobase_query_is_update(void)
thd = (THD *)innobase_current_thd();
- if ( thd->lex->sql_command == SQLCOM_REPLACE ||
- thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
- ( thd->lex->sql_command == SQLCOM_LOAD &&
- thd->lex->duplicates == DUP_REPLACE )) {
- return true;
+ if (thd->lex->sql_command == SQLCOM_REPLACE ||
+ thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
+ (thd->lex->sql_command == SQLCOM_LOAD &&
+ thd->lex->duplicates == DUP_REPLACE)) {
+
+ return(1);
}
- if ( thd->lex->sql_command == SQLCOM_INSERT &&
- thd->lex->duplicates == DUP_UPDATE ) {
- return true;
+ if (thd->lex->sql_command == SQLCOM_INSERT &&
+ thd->lex->duplicates == DUP_UPDATE) {
+
+ return(1);
}
- return false;
+ return(0);
}
}
@@ -6308,11 +6325,14 @@ innobase_xa_prepare(
"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
}
- if (all || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
+ if (all
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
/* We were instructed to prepare the whole transaction, or
this is an SQL statement end and autocommit is on */
+ ut_ad(trx->active_trans);
+
error = trx_prepare_for_mysql(trx);
} else {
/* We just mark the SQL statement ended and do not do a
@@ -6321,7 +6341,7 @@ innobase_xa_prepare(
if (trx->auto_inc_lock) {
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
-
+
row_unlock_table_autoinc_for_mysql(trx);
}
/* Store the current undo_no of the transaction so that we
@@ -6351,10 +6371,11 @@ innobase_xa_recover(
uint len) /* in: number of slots in xid_list */
{
if (len == 0 || xid_list == NULL) {
- return 0;
+
+ return(0);
}
- return (trx_recover_for_mysql(xid_list, len));
+ return(trx_recover_for_mysql(xid_list, len));
}
/***********************************************************************
@@ -6365,7 +6386,7 @@ int
innobase_commit_by_xid(
/*===================*/
/* out: 0 or error number */
- XID* xid) /* in: X/Open XA Transaction Identification */
+ XID* xid) /* in: X/Open XA transaction identification */
{
trx_t* trx;
@@ -6388,7 +6409,7 @@ int
innobase_rollback_by_xid(
/*=====================*/
/* out: 0 or error number */
- XID *xid) /* in : X/Open XA Transaction Idenfification */
+ XID *xid) /* in: X/Open XA transaction idenfification */
{
trx_t* trx;
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index e5a43a64df0..1c8063b9373 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -239,7 +239,6 @@ extern ulong srv_auto_extend_increment;
extern ulong srv_n_spin_wait_rounds;
extern ulong srv_n_free_tickets_to_enter;
extern ulong srv_thread_sleep_delay;
-extern ulong srv_max_purge_lag;
extern ulong srv_thread_concurrency;
}
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index ad7e775aacf..2179eaa7f8f 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -1350,7 +1350,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
HA_CREATE_INFO *info)
{
int error;
- uint i,j,recpos,minpos,fieldpos,temp_length,length;
+ uint i,j,recpos,minpos,fieldpos,temp_length,length, create_flags= 0;
bool found_real_auto_increment=0;
enum ha_base_keytype type;
char buff[FN_REFLEN];
@@ -1538,17 +1538,21 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
create_info.data_file_name= info->data_file_name;
create_info.index_file_name= info->index_file_name;
+ if (info->options & HA_LEX_CREATE_TMP_TABLE)
+ create_flags|= HA_CREATE_TMP_TABLE;
+ if (options & HA_OPTION_PACK_RECORD)
+ create_flags|= HA_PACK_RECORD;
+ if (options & HA_OPTION_CHECKSUM)
+ create_flags|= HA_CREATE_CHECKSUM;
+ if (options & HA_OPTION_DELAY_KEY_WRITE)
+ create_flags|= HA_CREATE_DELAY_KEY_WRITE;
+
/* TODO: Check that the following fn_format is really needed */
error=mi_create(fn_format(buff,name,"","",2+4),
share->keys,keydef,
(uint) (recinfo_pos-recinfo), recinfo,
0, (MI_UNIQUEDEF*) 0,
- &create_info,
- (((options & HA_OPTION_PACK_RECORD) ? HA_PACK_RECORD : 0) |
- ((options & HA_OPTION_CHECKSUM) ? HA_CREATE_CHECKSUM : 0) |
- ((options & HA_OPTION_DELAY_KEY_WRITE) ?
- HA_CREATE_DELAY_KEY_WRITE : 0)));
-
+ &create_info, create_flags);
my_free((gptr) recinfo,MYF(0));
DBUG_RETURN(error);
diff --git a/sql/handler.cc b/sql/handler.cc
index cd3656c6f0d..9077622dd8c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -395,6 +395,16 @@ int ha_init()
ha_was_inited_ok(ht++);
}
#endif
+#ifdef HAVE_FEDERATED_DB
+ if (have_federated_db == SHOW_OPTION_YES)
+ {
+ if (federated_db_init())
+ {
+ have_federated_db= SHOW_OPTION_DISABLED;
+ error= 1;
+ }
+ }
+#endif
#ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES)
{
@@ -441,6 +451,10 @@ int ha_panic(enum ha_panic_function flag)
if (have_ndbcluster == SHOW_OPTION_YES)
error|=ndbcluster_end();
#endif
+#ifdef HAVE_FEDERATED_DB
+ if (have_federated_db == SHOW_OPTION_YES)
+ error|= federated_db_end();
+#endif
#ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end();
@@ -1606,7 +1620,12 @@ int handler::rename_table(const char * from, const char * to)
}
/*
- Tell the handler to turn on or off transaction in the handler
+ Tell the storage engine that it is allowed to "disable transaction" in the
+ handler. It is a hint that ACID is not required - it is used in NDB for
+ ALTER TABLE, for example, when data are copied to temporary table.
+ A storage engine may treat this hint any way it likes. NDB for example
+ starts to commit every now and then automatically.
+ This hint can be safely ignored.
*/
int ha_enable_transaction(THD *thd, bool on)
@@ -1616,7 +1635,15 @@ int ha_enable_transaction(THD *thd, bool on)
DBUG_ENTER("ha_enable_transaction");
thd->transaction.on= on;
if (on)
- ha_commit(thd);
+ {
+ /*
+ Now all storage engines should have transaction handling enabled.
+ But some may have it enabled all the time - "disabling" transactions
+ is an optimization hint that storage engine is free to ignore.
+ So, let's commit an open transaction (if any) now.
+ */
+ error= end_trans(thd, COMMIT);
+ }
DBUG_RETURN(error);
}
diff --git a/sql/item.cc b/sql/item.cc
index 07d5200784d..ef3cc5105ef 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -724,7 +724,6 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
*/
bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
- nagg++;
if (!my_charset_same(collation, dt.collation))
{
/*
@@ -740,7 +739,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
else
{
set(dt);
- strong= nagg;
}
}
else if (dt.collation == &my_charset_bin)
@@ -748,7 +746,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
if (dt.derivation <= derivation)
{
set(dt);
- strong= nagg;
}
else
; // Do nothing
@@ -764,20 +761,18 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
dt.collation->state & MY_CS_UNICODE)
{
set(dt);
- strong= nagg;
}
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
derivation < dt.derivation &&
- dt.derivation >= DERIVATION_COERCIBLE)
+ dt.derivation >= DERIVATION_SYSCONST)
{
// Do nothing;
}
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
dt.derivation < derivation &&
- derivation >= DERIVATION_COERCIBLE)
+ derivation >= DERIVATION_SYSCONST)
{
set(dt);
- strong= nagg;
}
else
{
@@ -793,7 +788,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
else if (dt.derivation < derivation)
{
set(dt);
- strong= nagg;
}
else
{
@@ -3513,6 +3507,9 @@ Item_ref::Item_ref(Item **item, const char *table_name_par,
Item_field::fix_fields, here we first search the SELECT and GROUP BY
clauses, and then we search the FROM clause.
+ POSTCONDITION
+ Item_ref::ref is 0 or points to a valid item
+
RETURN
TRUE if error
FALSE on success
@@ -3534,168 +3531,155 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (ref == not_found_item) /* This reference was not resolved. */
{
+ TABLE_LIST *table_list;
+ Field *from_field;
+ SELECT_LEX *last;
+ ref= 0;
+
+ if (!outer_sel || (current_sel->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE))
+ {
+ /* The current reference cannot be resolved in this query. */
+ my_error(ER_BAD_FIELD_ERROR,MYF(0),
+ this->full_name(), current_thd->where);
+ return TRUE;
+ }
/*
If there is an outer select, and it is not a derived table (which do
not support the use of outer fields for now), try to resolve this
reference in the outer select(s).
-
+
We treat each subselect as a separate namespace, so that different
subselects may contain columns with the same names. The subselects are
searched starting from the innermost.
*/
- if (outer_sel && (current_sel->master_unit()->first_select()->linkage !=
- DERIVED_TABLE_TYPE))
+ from_field= (Field*) not_found_field;
+ last= 0;
+
+ /* The following loop will always be excuted at least once */
+ for ( ; outer_sel ;
+ outer_sel= (prev_unit= outer_sel->master_unit())->outer_select())
{
- TABLE_LIST *table_list;
- Field *from_field= (Field*) not_found_field;
- SELECT_LEX *last= 0;
+ last= outer_sel;
+ Item_subselect *prev_subselect_item= prev_unit->item;
- for ( ; outer_sel ;
- outer_sel= (prev_unit= outer_sel->master_unit())->outer_select())
+ /* Search in the SELECT and GROUP lists of the outer select. */
+ if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
{
- last= outer_sel;
- Item_subselect *prev_subselect_item= prev_unit->item;
-
- /* Search in the SELECT and GROUP lists of the outer select. */
- if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
+ if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
+ if (ref != not_found_item)
{
- if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occurred (e.g. ambiguous names). */
- if (ref != not_found_item)
- {
- DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
- break;
- }
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
+ prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ break;
}
-
- /* Search in the tables of the FROM clause of the outer select. */
- table_list= outer_sel->get_table_list();
- if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
- /*
- It is a primary INSERT st_select_lex => do not resolve against the
- first table.
- */
- table_list= table_list->next_local;
-
- place= prev_subselect_item->parsing_place;
/*
- Check table fields only if the subquery is used somewhere out of
- HAVING or the outer SELECT does not use grouping (i.e. tables are
- accessible).
- TODO:
- Here we could first find the field anyway, and then test this
- condition, so that we can give a better error message -
- ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
- ER_BAD_FIELD_ERROR which we produce now.
+ Set ref to 0 to ensure that we get an error in case we replaced
+ this item with another item and still use this item in some
+ other place of the parse tree.
*/
- if ((place != IN_HAVING ||
- (!outer_sel->with_sum_func &&
- outer_sel->group_list.elements == 0)))
- {
- /*
- In case of view, find_field_in_tables() write pointer to view
- field expression to 'reference', i.e. it substitute that
- expression instead of this Item_ref
- */
- if ((from_field= find_field_in_tables(thd, this, table_list,
- reference,
- IGNORE_EXCEPT_NON_UNIQUE,
- TRUE)) !=
- not_found_field)
- {
- if (from_field != view_ref_found)
- {
- prev_subselect_item->used_tables_cache|= from_field->table->map;
- prev_subselect_item->const_item_cache= 0;
- }
- else
- {
- Item::Type type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
- DBUG_ASSERT((*reference)->type() == REF_ITEM);
- mark_as_dependent(thd, last, current_sel, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
- (Item_ident*) (*reference) :
- 0));
- /*
- view reference found, we substituted it instead of this
- Item, so can quit
- */
- return FALSE;
- }
- break;
- }
- }
-
- /* Reference is not found => depend on outer (or just error). */
- prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
- prev_subselect_item->const_item_cache= 0;
-
- if (outer_sel->master_unit()->first_select()->linkage ==
- DERIVED_TABLE_TYPE)
- break; /* Do not consider derived tables. */
+ ref= 0;
}
- DBUG_ASSERT(ref != 0);
- if (!from_field)
- return TRUE;
- if (ref == not_found_item && from_field == not_found_field)
+ /* Search in the tables of the FROM clause of the outer select. */
+ table_list= outer_sel->get_table_list();
+ if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0),
- this->full_name(), current_thd->where);
- ref= 0; // Safety
- return TRUE;
+ /*
+ It is a primary INSERT st_select_lex => do not resolve against
+ the first table.
+ */
+ table_list= table_list->next_local;
}
- if (from_field != not_found_field)
+
+ place= prev_subselect_item->parsing_place;
+ /*
+ Check table fields only if the subquery is used somewhere out of
+ HAVING or the outer SELECT does not use grouping (i.e. tables are
+ accessible).
+ TODO:
+ Here we could first find the field anyway, and then test this
+ condition, so that we can give a better error message -
+ ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
+ ER_BAD_FIELD_ERROR which we produce now.
+ */
+ if ((place != IN_HAVING ||
+ (!outer_sel->with_sum_func &&
+ outer_sel->group_list.elements == 0)))
{
/*
- Set ref to 0 as we are replacing this item with the found item and
- this will ensure we get an error if this item would be used
- elsewhere
+ In case of view, find_field_in_tables() write pointer to view
+ field expression to 'reference', i.e. it substitute that
+ expression instead of this Item_ref
*/
- ref= 0; // Safety
- if (from_field != view_ref_found)
+ from_field= find_field_in_tables(thd, this, table_list,
+ reference,
+ IGNORE_EXCEPT_NON_UNIQUE,
+ TRUE);
+ if (! from_field)
+ return TRUE;
+ if (from_field == view_ref_found)
{
- Item_field* fld;
- if (!(fld= new Item_field(from_field)))
- return TRUE;
- thd->change_item_tree(reference, fld);
- mark_as_dependent(thd, last, thd->lex->current_select, this, fld);
+ Item::Type type= (*reference)->type();
+ prev_subselect_item->used_tables_cache|=
+ (*reference)->used_tables();
+ prev_subselect_item->const_item_cache&=
+ (*reference)->const_item();
+ DBUG_ASSERT((*reference)->type() == REF_ITEM);
+ mark_as_dependent(thd, last, current_sel, this,
+ ((type == REF_ITEM || type == FIELD_ITEM) ?
+ (Item_ident*) (*reference) :
+ 0));
+ /*
+ view reference found, we substituted it instead of this
+ Item, so can quit
+ */
return FALSE;
}
- /*
- We can leave expression substituted from view for next PS/SP
- re-execution (i.e. do not register this substitution for reverting
- on cleanup() (register_item_tree_changing())), because this subtree
- will be fix_field'ed during setup_tables()->setup_ancestor()
- (i.e. before all other expressions of query, and references on
- tables which do not present in query will not make problems.
-
- Also we suppose that view can't be changed during PS/SP life.
- */
- }
- else
- {
- /* Should be checked in resolve_ref_in_select_and_group(). */
- DBUG_ASSERT(*ref && (*ref)->fixed);
- mark_as_dependent(thd, last, current_sel, this, this);
+ if (from_field != not_found_field)
+ {
+ prev_subselect_item->used_tables_cache|= from_field->table->map;
+ prev_subselect_item->const_item_cache= 0;
+ break;
+ }
}
+ DBUG_ASSERT(from_field == not_found_field);
+
+ /* Reference is not found => depend on outer (or just error). */
+ prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
+ prev_subselect_item->const_item_cache= 0;
+
+ if (outer_sel->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; /* Do not consider derived tables. */
}
- else
+
+ DBUG_ASSERT(from_field != 0 && from_field != view_ref_found);
+ if (from_field != not_found_field)
{
- /* The current reference cannot be resolved in this query. */
- my_error(ER_BAD_FIELD_ERROR,MYF(0),
+ Item_field* fld;
+ if (!(fld= new Item_field(from_field)))
+ return TRUE;
+ thd->change_item_tree(reference, fld);
+ mark_as_dependent(thd, last, thd->lex->current_select, this, fld);
+ return FALSE;
+ }
+ if (ref == 0)
+ {
+ /* The item was not a table field and not a reference */
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
this->full_name(), current_thd->where);
return TRUE;
}
+ /* Should be checked in resolve_ref_in_select_and_group(). */
+ DBUG_ASSERT(*ref && (*ref)->fixed);
+ mark_as_dependent(thd, last, current_sel, this, this);
}
}
+ DBUG_ASSERT(*ref);
/*
Check if this is an incorrect reference in a group function or forward
reference. Do not issue an error if this is an unnamed reference inside an
@@ -3716,11 +3700,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
set_properties();
- if (ref && (*ref)->check_cols(1))
- return 1;
- return 0;
+ if ((*ref)->check_cols(1))
+ return TRUE;
+ return FALSE;
}
+
void Item_ref::set_properties()
{
max_length= (*ref)->max_length;
diff --git a/sql/item.h b/sql/item.h
index 4082e77efad..97913e40916 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -32,8 +32,9 @@ class Item_field;
enum Derivation
{
- DERIVATION_IGNORABLE= 4,
- DERIVATION_COERCIBLE= 3,
+ DERIVATION_IGNORABLE= 5,
+ DERIVATION_COERCIBLE= 4,
+ DERIVATION_SYSCONST= 3,
DERIVATION_IMPLICIT= 2,
DERIVATION_NONE= 1,
DERIVATION_EXPLICIT= 0
@@ -62,22 +63,16 @@ class DTCollation {
public:
CHARSET_INFO *collation;
enum Derivation derivation;
- uint nagg; // Total number of aggregated collations.
- uint strong; // Number of the strongest collation.
DTCollation()
{
collation= &my_charset_bin;
derivation= DERIVATION_NONE;
- nagg= 0;
- strong= 0;
}
DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
{
collation= collation_arg;
derivation= derivation_arg;
- nagg= 0;
- strong= 0;
}
void set(DTCollation &dt)
{
@@ -103,6 +98,7 @@ public:
case DERIVATION_IGNORABLE: return "IGNORABLE";
case DERIVATION_COERCIBLE: return "COERCIBLE";
case DERIVATION_IMPLICIT: return "IMPLICIT";
+ case DERIVATION_SYSCONST: return "SYSCONST";
case DERIVATION_EXPLICIT: return "EXPLICIT";
case DERIVATION_NONE: return "NONE";
default: return "UNKNOWN";
@@ -113,7 +109,7 @@ public:
typedef bool (Item::*Item_processor)(byte *arg);
typedef Item* (Item::*Item_transformer) (byte *arg);
-typedef void (*Item_cond_traverser) (const Item *item, void *arg);
+typedef void (*Cond_traverser) (const Item *item, void *arg);
class Item {
Item(const Item &); /* Prevent use of these */
@@ -393,18 +389,17 @@ public:
return (this->*processor)(arg);
}
- virtual Item* transform(Item_transformer transformer, byte *arg)
+ virtual Item* transform(Item_transformer transformer, byte *arg)
{
return (this->*transformer)(arg);
}
- virtual void traverse_cond(Item_cond_traverser traverser,
- void *arg,
- traverse_order order = POSTFIX)
+ virtual void traverse_cond(Cond_traverser traverser,
+ void *arg, traverse_order order)
{
(*traverser)(this, arg);
}
-
+
virtual bool remove_dependence_processor(byte * arg) { return 0; }
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
virtual bool cleanup_processor(byte *arg);
@@ -1243,6 +1238,8 @@ public:
The following class is used to optimize comparing of date and bigint columns
We need to save the original item, to be able to set the field to the
original value in 'opt_range'.
+ An instance of Item_int_with_ref may refer to a signed or an unsigned
+ integer.
*/
class Item_int_with_ref :public Item_int
@@ -1257,6 +1254,11 @@ public:
{
return ref->save_in_field(field, no_conversions);
}
+ Item *new_item()
+ {
+ return (ref->unsigned_flag)? new Item_uint(ref->name, ref->max_length) :
+ new Item_int(ref->name, ref->max_length);
+ }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index fd62581094f..c0cb0704852 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2289,6 +2289,21 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (check_stack_overrun(thd, buff))
return TRUE; // Fatal error flag is set!
+ /*
+ The following optimization reduces the depth of an AND-OR tree.
+ E.g. a WHERE clause like
+ F1 AND (F2 AND (F2 AND F4))
+ is parsed into a tree with the same nested structure as defined
+ by braces. This optimization will transform such tree into
+ AND (F1, F2, F3, F4).
+ Trees of OR items are flattened as well:
+ ((F1 OR F2) OR (F3 OR F4)) => OR (F1, F2, F3, F4)
+ Items for removed AND/OR levels will dangle until the death of the
+ entire statement.
+ The optimization is currently prepared statements and stored procedures
+ friendly as it doesn't allocate any memory and its effects are durable
+ (i.e. do not depend on PS/SP arguments).
+ */
while ((item=li++))
{
table_map tmp_table_map;
@@ -2369,9 +2384,8 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
return Item_func::transform(transformer, arg);
}
-void Item_cond::traverse_cond(Item_cond_traverser traverser,
- void *arg,
- traverse_order order)
+void Item_cond::traverse_cond(Cond_traverser traverser,
+ void *arg, traverse_order order)
{
List_iterator<Item> li(list);
Item *item;
@@ -3266,6 +3280,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
const_item= c;
}
+
Item_equal::Item_equal(Item_equal *item_equal)
: Item_bool_func(), eval_item(0), cond_false(0)
{
@@ -3302,12 +3317,7 @@ void Item_equal::add(Item_field *f)
uint Item_equal::members()
{
- uint count= 0;
- List_iterator_fast<Item_field> li(fields);
- Item_field *item;
- while ((item= li++))
- count++;
- return count;
+ return fields.elements;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 3ec7131aac1..5a87635a4dc 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1028,9 +1028,7 @@ public:
void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
- void traverse_cond(Item_cond_traverser,
- void *arg,
- traverse_order order = POSTFIX);
+ void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
};
@@ -1039,8 +1037,8 @@ public:
The class Item_equal is used to represent conjunctions of equality
predicates of the form field1 = field2, and field=const in where
conditions and on expressions.
-
- All equality predicates of the form field1=field2 contained in a
+
+ All equality predicates of the form field1=field2 contained in a
conjunction are substituted for a sequence of items of this class.
An item of this class Item_equal(f1,f2,...fk) represents a
multiple equality f1=f2=...=fk.
@@ -1097,6 +1095,12 @@ public:
predicates that can not be used to access tables in the investigated
plan for those, obtained by substitution of some fields for equal fields,
that can be used.
+
+ Prepared Statements/Stored Procedures note: instances of class
+ Item_equal are created only at the time a PS/SP is executed and
+ are deleted in the end of execution. All changes made to these
+ objects need not be registered in the list of changes of the parse
+ tree and do not harm PS/SP re-execution.
*/
class Item_equal: public Item_bool_func
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 6bd5c0c9a52..35cc46989f7 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -434,7 +434,7 @@ Item *create_func_version(void)
{
return new Item_static_string_func("version()", server_version,
(uint) strlen(server_version),
- system_charset_info, DERIVATION_IMPLICIT);
+ system_charset_info, DERIVATION_SYSCONST);
}
Item *create_func_weekday(Item* a)
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 19228108bfc..cc4d25bc5af 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -82,8 +82,6 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
uint flags)
{
uint i;
- c.nagg= 0;
- c.strong= 0;
c.set(av[0]->collation);
for (i= 1; i < count; i++)
{
@@ -360,9 +358,8 @@ bool Item_func::walk (Item_processor processor, byte *argument)
return (this->*processor)(argument);
}
-void Item_func::traverse_cond(Item_cond_traverser traverser,
- void *argument,
- traverse_order order)
+void Item_func::traverse_cond(Cond_traverser traverser,
+ void *argument, traverse_order order)
{
if (arg_count)
{
@@ -1630,13 +1627,25 @@ void Item_func_int_val::find_num_type()
longlong Item_func_ceiling::int_op()
{
- /*
- the volatile's for BUG #3051 to calm optimizer down (because of gcc's
- bug)
- */
- volatile double value= args[0]->val_real();
- null_value= args[0]->null_value;
- return (longlong) ceil(value);
+ longlong result;
+ switch (args[0]->result_type()) {
+ case INT_RESULT:
+ result= args[0]->val_int();
+ null_value= args[0]->null_value;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec;
+ if ((dec= Item_func_ceiling::decimal_op(&dec_buf)))
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ else
+ result= 0;
+ break;
+ }
+ default:
+ result= (longlong)Item_func_ceiling::real_op();
+ };
+ return result;
}
@@ -1665,13 +1674,25 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
longlong Item_func_floor::int_op()
{
- /*
- the volatile's for BUG #3051 to calm optimizer down (because of gcc's
- bug)
- */
- volatile double value= args[0]->val_real();
- null_value= args[0]->null_value;
- return (longlong) floor(value);
+ longlong result;
+ switch (args[0]->result_type()) {
+ case INT_RESULT:
+ result= args[0]->val_int();
+ null_value= args[0]->null_value;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec;
+ if ((dec= Item_func_floor::decimal_op(&dec_buf)))
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ else
+ result= 0;
+ break;
+ }
+ default:
+ result= (longlong)Item_func_floor::real_op();
+ };
+ return result;
}
@@ -2365,26 +2386,6 @@ longlong Item_func_bit_count::val_int()
#ifdef HAVE_DLOPEN
-udf_handler::~udf_handler()
-{
- if (!not_original)
- {
- if (initialized)
- {
- if (u_d->func_deinit != NULL)
- {
- void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
- u_d->func_deinit;
- (*deinit)(&initid);
- }
- free_udf(u_d);
- }
- if (buffers) // Because of bug in ecc
- delete [] buffers;
- }
-}
-
-
bool
udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
uint arg_count, Item **arguments)
@@ -2774,6 +2775,31 @@ String *Item_func_udf_str::val_str(String *str)
return res;
}
+
+/*
+ This has to come last in the udf_handler methods, or the compiler for IBM
+ AIX fails to compile with debugging enabled. (Yes, really.)
+ */
+
+udf_handler::~udf_handler()
+{
+ if (!not_original)
+ {
+ if (initialized)
+ {
+ if (u_d->func_deinit != NULL)
+ {
+ void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*))
+ u_d->func_deinit;
+ (*deinit)(&initid);
+ }
+ free_udf(u_d);
+ }
+ if (buffers) // Because of bug in ecc
+ delete [] buffers;
+ }
+}
+
#else
bool udf_handler::get_arguments() { return 0; }
#endif /* HAVE_DLOPEN */
@@ -2857,18 +2883,6 @@ void item_user_lock_free(void)
void item_user_lock_release(User_level_lock *ull)
{
ull->locked=0;
- if (mysql_bin_log.is_open())
- {
- char buf[256];
- const char *command="DO RELEASE_LOCK(\"";
- String tmp(buf,sizeof(buf), system_charset_info);
- tmp.copy(command, strlen(command), tmp.charset());
- tmp.append(ull->key,ull->key_length);
- tmp.append("\")", 2);
- Query_log_event qev(current_thd, tmp.ptr(), tmp.length(), 0, FALSE);
- qev.error_code=0; // this query is always safe to run on slave
- mysql_bin_log.write(&qev);
- }
if (--ull->count)
pthread_cond_signal(&ull->cond);
else
@@ -2992,6 +3006,16 @@ longlong Item_func_get_lock::val_int()
User_level_lock *ull;
int error=0;
+ /*
+ In slave thread no need to get locks, everything is serialized. Anyway
+ there is no way to make GET_LOCK() work on slave like it did on master
+ (i.e. make it return exactly the same value) because we don't have the
+ same other concurrent threads environment. No matter what we return here,
+ it's not guaranteed to be same as on master.
+ */
+ if (thd->slave_thread)
+ return 1;
+
pthread_mutex_lock(&LOCK_user_locks);
if (!res || !res->length())
@@ -4412,11 +4436,6 @@ Item_func_sp::execute(Item **itp)
}
#endif
- /*
- We don't need to suppress sending of OK packet here (by setting
- thd->net.no_send_ok to true), because we are not allowing statements
- in functions now.
- */
res= m_sp->execute_function(thd, args, arg_count, itp);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
diff --git a/sql/item_func.h b/sql/item_func.h
index b3fa73bb15b..b1ccbfeea53 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -163,9 +163,8 @@ public:
uint flags= 0);
bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
- void traverse_cond(Item_cond_traverser traverser,
- void * arg,
- traverse_order order = POSTFIX);
+ void traverse_cond(Cond_traverser traverser,
+ void * arg, traverse_order order);
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 536ee46f4db..03aa56128ca 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1515,6 +1515,23 @@ String *Item_func_decode::val_str(String *str)
}
+Item *Item_func_sysconst::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_string(cstr.ptr(), cstr.length(),
+ cstr.charset(),
+ collation.derivation)))
+ {
+ return NULL;
+ }
+ conv->str_value.copy();
+ return conv;
+}
+
+
String *Item_func_database::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index dc50c9a4ccd..ea8a78c528a 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -337,10 +337,18 @@ public:
};
-class Item_func_database :public Item_str_func
+class Item_func_sysconst :public Item_str_func
{
public:
- Item_func_database() { collation.set(system_charset_info,DERIVATION_IMPLICIT); }
+ Item_func_sysconst()
+ { collation.set(system_charset_info,DERIVATION_SYSCONST); }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
+};
+
+class Item_func_database :public Item_func_sysconst
+{
+public:
+ Item_func_database() :Item_func_sysconst() {}
String *val_str(String *);
void fix_length_and_dec()
{
@@ -350,10 +358,10 @@ public:
const char *func_name() const { return "database"; }
};
-class Item_func_user :public Item_str_func
+class Item_func_user :public Item_func_sysconst
{
public:
- Item_func_user() { collation.set(system_charset_info, DERIVATION_IMPLICIT); }
+ Item_func_user() :Item_func_sysconst() {}
String *val_str(String *);
void fix_length_and_dec()
{
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b4a53ba0f80..dbba02c3cf7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -22,6 +22,7 @@
#endif
#include "mysql_priv.h"
+#include "sql_select.h"
Item_sum::Item_sum(List<Item> &list)
:arg_count(list.elements)
@@ -303,6 +304,21 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return FALSE;
}
+Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ if (args[0]->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field*) args[0])->field;
+
+ if ((field= create_tmp_field_from_field(current_thd, field, this, table,
+ 0, convert_blob_length)))
+ field->flags&= ~NOT_NULL_FLAG;
+ return field;
+ }
+ return Item_sum::create_tmp_field(group, table, convert_blob_length);
+}
+
/***********************************************************************
** reset and add of sum_func
@@ -2075,8 +2091,6 @@ my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
** COUNT(DISTINCT ...)
****************************************************************************/
-#include "sql_select.h"
-
int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 81f5d45e42e..fead45f1881 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -94,7 +94,6 @@ public:
Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
-
bool walk (Item_processor processor, byte *argument);
};
@@ -525,6 +524,8 @@ protected:
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
+ Field *create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length);
};
diff --git a/sql/log.cc b/sql/log.cc
index 56d16c9c7cf..d5c7cd5464f 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1296,10 +1296,9 @@ void MYSQL_LOG::new_file(bool need_lock)
}
if (need_lock)
- {
pthread_mutex_lock(&LOCK_log);
- pthread_mutex_lock(&LOCK_index);
- }
+ pthread_mutex_lock(&LOCK_index);
+
safe_mutex_assert_owner(&LOCK_log);
safe_mutex_assert_owner(&LOCK_index);
@@ -1377,10 +1376,9 @@ void MYSQL_LOG::new_file(bool need_lock)
end:
if (need_lock)
- {
- pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
- }
+ pthread_mutex_unlock(&LOCK_index);
+
DBUG_VOID_RETURN;
}
@@ -1404,11 +1402,7 @@ bool MYSQL_LOG::append(Log_event* ev)
bytes_written+= ev->data_written;
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- {
- pthread_mutex_lock(&LOCK_index);
new_file(0);
- pthread_mutex_unlock(&LOCK_index);
- }
err:
pthread_mutex_unlock(&LOCK_log);
@@ -1423,9 +1417,9 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
DBUG_ENTER("MYSQL_LOG::appendv");
va_list(args);
va_start(args,len);
-
+
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
-
+
pthread_mutex_lock(&LOCK_log);
do
{
@@ -1438,11 +1432,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
DBUG_PRINT("info",("max_size: %lu",max_size));
if ((uint) my_b_append_tell(&log_file) > max_size)
- {
- pthread_mutex_lock(&LOCK_index);
new_file(0);
- pthread_mutex_unlock(&LOCK_index);
- }
err:
pthread_mutex_unlock(&LOCK_log);
@@ -1774,15 +1764,10 @@ err:
void MYSQL_LOG::rotate_and_purge(uint flags)
{
- if (!prepared_xids && // see new_file() for the explanation
- ((flags & RP_FORCE_ROTATE) ||
- (my_b_tell(&log_file) >= (my_off_t) max_size)))
+ if ((flags & RP_FORCE_ROTATE) ||
+ (my_b_tell(&log_file) >= (my_off_t) max_size))
{
- if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
- pthread_mutex_lock(&LOCK_index);
new_file(!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED));
- if (flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)
- pthread_mutex_unlock(&LOCK_index);
#ifdef HAVE_REPLICATION
// QQ why do we need #ifdef here ???
if (expire_logs_days)
@@ -1828,9 +1813,8 @@ uint MYSQL_LOG::next_file_id()
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
{
- bool error= 0;
- VOID(pthread_mutex_lock(&LOCK_log));
DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)");
+ VOID(pthread_mutex_lock(&LOCK_log));
if (likely(is_open())) // Should always be true
{
@@ -1888,12 +1872,22 @@ DBUG_skip_commit:
goto err;
}
signal_update();
- DBUG_PRINT("info",("max_size: %lu",max_size));
- rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
+ /*
+ if commit_event is Xid_log_event, increase the number of
+ prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
+ if there're prepared xids in it - see the comment in new_file() for
+ an explanation.
+ If the commit_event is not Xid_log_event (then it's a Query_log_event)
+ rotate binlog, if necessary.
+ */
+ if (commit_event->get_type_code() == XID_EVENT)
+ thread_safe_increment(prepared_xids, &LOCK_prep_xids);
+ else
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
VOID(pthread_mutex_unlock(&LOCK_log));
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
err:
if (!write_error)
@@ -2463,7 +2457,7 @@ void sql_print_information(const char *format, ...)
static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
-uint opt_tc_log_size=TC_LOG_MIN_SIZE;
+ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
ulong tc_log_max_pages_used=0, tc_log_page_size=0,
tc_log_page_waits=0, tc_log_cur_pages_used=0;
@@ -2992,7 +2986,6 @@ int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
{
Xid_log_event xle(thd, xid);
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
- thread_safe_increment(prepared_xids, &LOCK_prep_xids);
return !binlog_end_trans(thd, trans_log, &xle); // invert return value
}
@@ -3000,7 +2993,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
if (thread_safe_dec_and_test(prepared_xids, &LOCK_prep_xids))
pthread_cond_signal(&COND_prep_xids);
- rotate_and_purge(0); // in case ::write() was not able to rotate
+ rotate_and_purge(0); // as ::write() did not rotate
}
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7f92159208b..ff7445029d0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1616,9 +1616,9 @@ end:
probably, so data_buf will be freed, so the thd->... listed above will be
pointers to freed memory.
So we must set them to 0, so that those bad pointers values are not later
- used. Note that "cleanup" queries (automatic DO RELEASE_LOCK() and DROP
- TEMPORARY TABLE don't suffer from these assignments to 0 as DROP TEMPORARY
- TABLE uses the db.table syntax).
+ used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
+ don't suffer from these assignments to 0 as DROP TEMPORARY
+ TABLE uses the db.table syntax.
*/
thd->db= thd->catalog= 0; // prevent db from being freed
thd->query= 0; // just to be sure
@@ -1684,6 +1684,9 @@ void Start_log_event_v3::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
if (created)
fprintf(file," at startup");
fputc('\n', file);
+ if (flags & LOG_EVENT_BINLOG_IN_USE_F)
+ fprintf(file, "# Warning: this binlog was not closed properly. "
+ "Most probably mysqld crashed writing it.\n");
}
if (!artificial_event && created)
{
@@ -3663,8 +3666,8 @@ void Stop_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev
The master stopped.
We used to clean up all temporary tables but this is useless as, as the
- master has shut down properly, it has written all DROP TEMPORARY TABLE and DO
- RELEASE_LOCK (prepared statements' deletion is TODO).
+ master has shut down properly, it has written all DROP TEMPORARY TABLE
+ (prepared statements' deletion is TODO only when we binlog prep stmts).
We used to clean up slave_load_tmpdir, but this is useless as it has been
cleared at the end of LOAD DATA INFILE.
So we have nothing to do here.
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 58450014081..b978ffe175b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -453,6 +453,7 @@ bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name,
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
+bool check_some_routine_access(THD *thd, char *db, char *name);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool mysql_multi_update_prepare(THD *thd);
@@ -805,6 +806,7 @@ void mysql_stmt_free(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
void reset_stmt_for_execute(THD *thd, LEX *lex);
+void init_stmt_after_parse(THD*, LEX*);
/* sql_error.cc */
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
@@ -869,7 +871,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd);
-int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
+int open_tables(THD *thd, TABLE_LIST **tables, uint *counter);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables);
@@ -1037,7 +1039,7 @@ extern ulong query_cache_size, query_cache_min_res_unit;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
-extern ulong slave_net_timeout;
+extern ulong slave_net_timeout, slave_trans_retries;
extern uint max_user_connections;
extern ulong what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
@@ -1063,7 +1065,7 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
extern my_bool opt_safe_show_db, opt_local_infile;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_readonly, lower_case_file_system;
-extern my_bool opt_enable_named_pipe, opt_sync_frm;
+extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
extern my_bool sp_automatic_privileges;
extern my_bool opt_old_style_user_limits;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ef982e489c9..a70f83b78b9 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -305,7 +305,7 @@ const char *opt_ndb_mgmd;
ulong opt_ndb_nodeid;
#endif
my_bool opt_readonly, use_temp_pool, relay_log_purge;
-my_bool opt_sync_bdb_logs, opt_sync_frm;
+my_bool opt_sync_bdb_logs, opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
my_bool opt_short_log_format= 0;
my_bool opt_log_queries_not_using_indexes= 0;
@@ -334,7 +334,7 @@ ulong server_id, thd_startup_options;
ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
-ulong slave_net_timeout;
+ulong slave_net_timeout, slave_trans_retries;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong refresh_version, flush_version; /* Increments on each reload */
@@ -3147,13 +3147,11 @@ we force server id to 2, but this MySQL server will not act as a slave.");
create_shutdown_thread();
create_maintenance_thread();
- printf(ER(ER_READY),my_progname,server_version,
- ((unix_sock == INVALID_SOCKET) ? (char*) "" : mysqld_unix_port),
- mysqld_port);
- if (MYSQL_COMPILATION_COMMENT[0] != '\0')
- fputs(" " MYSQL_COMPILATION_COMMENT, stdout);
- putchar('\n');
- fflush(stdout);
+ sql_print_information(ER(ER_READY),my_progname,server_version,
+ ((unix_sock == INVALID_SOCKET) ? (char*) ""
+ : mysqld_unix_port),
+ mysqld_port,
+ MYSQL_COMPILATION_COMMENT);
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
@@ -3747,7 +3745,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
if (!(vio_tmp=vio_new(new_sock,
sock == unix_sock ? VIO_TYPE_SOCKET :
VIO_TYPE_TCPIP,
- sock == unix_sock)) ||
+ sock == unix_sock ? VIO_LOCALHOST: 0)) ||
my_net_init(&thd->net,vio_tmp))
{
if (vio_tmp)
@@ -4192,7 +4190,7 @@ enum options_mysqld
OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
- OPT_READONLY, OPT_DEBUGGING,
+ OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
OPT_SORT_BUFFER, OPT_TABLE_CACHE,
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
@@ -4222,7 +4220,7 @@ enum options_mysqld
OPT_BDB_MAX_LOCK,
OPT_ERROR_LOG_FILE,
OPT_DEFAULT_WEEK_FORMAT,
- OPT_RANGE_ALLOC_BLOCK_SIZE,
+ OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
OPT_SYNC_FRM, OPT_SYNC_BINLOG,
@@ -4268,8 +4266,15 @@ struct my_option my_long_options[] =
(gptr*) &abort_slave_event_count, (gptr*) &abort_slave_event_count,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
- {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax.", 0, 0, 0,
+ {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set transaction isolation level 'serializable'.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS,
+ "Allows use of UDFs consisting of only one symbol xxx() "
+ "without corresponding xxx_init() or xxx_deinit(). That also means "
+ "that one can load any function from any library, for example exit() "
+ "from libc.so",
+ (gptr*) &opt_allow_suspicious_udfs, (gptr*) &opt_allow_suspicious_udfs,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"auto-increment-increment", OPT_AUTO_INCREMENT,
"Auto-increment columns are incremented by this",
(gptr*) &global_system_variables.auto_increment_increment,
@@ -4566,7 +4571,7 @@ Disable with --skip-isam.",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
(gptr*) &opt_tc_log_size, (gptr*) &opt_tc_log_size, 0, GET_ULONG,
- REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0, 0, TC_LOG_PAGE_SIZE, 0},
+ REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0L, 0, TC_LOG_PAGE_SIZE, 0},
{"log-update", OPT_UPDATE_LOG,
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option justs turns on --log-bin instead.",
@@ -5222,7 +5227,7 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
- "If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 expected, the minimum value for this variable is 4096.",
+ "If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the minimum value for this variable is 4096.",
(gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
{ "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
@@ -5408,6 +5413,12 @@ The minimum value for this variable is 4096.",
"Number of seconds to wait for more data from a master/slave connection before aborting the read.",
(gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
+ {"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES,
+ "Number of times the slave SQL thread will retry a transaction in case "
+ "it failed with a deadlock or elapsed lock wait timeout, "
+ "before giving up and stopping.",
+ (gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
+ GET_ULONG, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
@@ -5793,7 +5804,7 @@ static void mysql_init_variables(void)
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
- opt_tc_log_file= "tc.log"; // no hostname in tc_log file name !
+ opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index ef9babf7713..134d3564ef8 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -638,7 +638,6 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
{
if (!(field->flags & PART_KEY_FLAG))
return 0; // Not key field
- *prefix_len= 0;
TABLE *table= field->table;
uint idx= 0;
@@ -651,6 +650,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
KEY_PART_INFO *part,*part_end;
key_part_map key_part_to_use= 0;
uint jdx= 0;
+ *prefix_len= 0;
for (part= keyinfo->key_part, part_end= part+keyinfo->key_parts ;
part != part_end ;
part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index fc0802bf185..ad8eaee10f2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -340,6 +340,8 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
#ifdef HAVE_REPLICATION
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
+sys_var_long_ptr sys_slave_trans_retries("slave_transaction_retries",
+ &slave_trans_retries);
#endif
sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
&slow_launch_time);
@@ -652,6 +654,7 @@ sys_var *sys_variables[]=
#ifdef HAVE_REPLICATION
&sys_slave_compressed_protocol,
&sys_slave_net_timeout,
+ &sys_slave_trans_retries,
&sys_slave_skip_counter,
#endif
&sys_slow_launch_time,
@@ -931,6 +934,7 @@ struct show_var_st init_vars[]= {
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
#ifdef HAVE_REPLICATION
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
+ {sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS},
#endif
{sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
#ifdef HAVE_SYS_UN_H
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index ba4ef70486b..f2772c29b32 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -1824,7 +1824,7 @@ ER_READY
cze "%s: p-Bøipraven na spojení"
dan "%s: klar til tilslutninger"
nla "%s: klaar voor verbindingen"
- eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
+ eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d %s"
jps "%s: €”õŠ®—¹",
est "%s: ootab ühendusi"
fre "%s: Prêt pour des connections"
@@ -1839,7 +1839,7 @@ ER_READY
pol "%s: gotowe do po³?czenia"
por "%s: Pronto para conexões"
rum "%s: sint gata pentru conectii"
- rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d"
+ rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d %s"
serbian "%s: Spreman za konekcije\n"
slo "%s: pripravený na spojenie"
spa "%s: preparado para conexiones"
diff --git a/sql/slave.cc b/sql/slave.cc
index 9849feaf6fa..ef88f103b63 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3228,6 +3228,53 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
delete ev;
}
+ if (slave_trans_retries)
+ {
+ if (exec_res &&
+ (thd->net.last_errno == ER_LOCK_DEADLOCK ||
+ thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) &&
+ !thd->is_fatal_error)
+ {
+ const char *errmsg;
+ /*
+ We were in a transaction which has been rolled back because of a
+ deadlock (currently, InnoDB deadlock detected by InnoDB) or lock
+ wait timeout (innodb_lock_wait_timeout exceeded); let's seek back to
+ BEGIN log event and retry it all again.
+ We have to not only seek but also
+ a) init_master_info(), to seek back to hot relay log's start for later
+ (for when we will come back to this hot log after re-processing the
+ possibly existing old logs where BEGIN is: check_binlog_magic() will
+ then need the cache to be at position 0 (see comments at beginning of
+ init_master_info()).
+ b) init_relay_log_pos(), because the BEGIN may be an older relay log.
+ */
+ if (rli->trans_retries--)
+ {
+ sql_print_information("Slave SQL thread retries transaction");
+ if (init_master_info(rli->mi, 0, 0, 0, SLAVE_SQL))
+ sql_print_error("Failed to initialize the master info structure");
+ else if (init_relay_log_pos(rli,
+ rli->group_relay_log_name,
+ rli->group_relay_log_pos,
+ 1, &errmsg, 1))
+ sql_print_error("Error initializing relay log position: %s",
+ errmsg);
+ else
+ {
+ exec_res= 0;
+ sleep(2); // chance for concurrent connection to get more locks
+ }
+ }
+ else
+ sql_print_error("Slave SQL thread retried transaction %lu time(s) "
+ "in vain, giving up. Consider raising the value of "
+ "the slave_transaction_retries variable.",
+ slave_trans_retries);
+ }
+ if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
+ rli->trans_retries= slave_trans_retries; // restart from fresh
+ }
return exec_res;
}
else
@@ -3642,6 +3689,7 @@ slave_begin:
pthread_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
pthread_mutex_unlock(&rli->log_space_lock);
+ rli->trans_retries= slave_trans_retries; // start from "no error"
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@@ -4188,7 +4236,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
master server shutdown. The only thing this does is cleaning. But
cleaning is already done on a per-master-thread basis (as the master
server is shutting down cleanly, it has written all DROP TEMPORARY TABLE
- and DO RELEASE_LOCK; prepared statements' deletion are TODO).
+ prepared statements' deletion are TODO only when we binlog prep stmts).
We don't even increment mi->master_log_pos, because we may be just after
a Rotate event. Btw, in a few milliseconds we are going to have a Start
diff --git a/sql/slave.h b/sql/slave.h
index 9e9e9070596..ee5541ffe08 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -293,7 +293,8 @@ typedef struct st_relay_log_info
} until_log_names_cmp_result;
char cached_charset[6];
-
+ ulong trans_retries;
+
st_relay_log_info();
~st_relay_log_info();
diff --git a/sql/sp.cc b/sql/sp.cc
index 46b08c3e847..3f6d4d0bf1b 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -288,12 +288,14 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
* in thd->lex (the unit and master stuff), and the easiest way to
* do it is, is to call mysql_init_query(), but this unfortunately
* resets teh value_list where we keep the CALL parameters. So we
- * copy the list and then restore it.
+ * copy the list and then restore it. (... and found_semicolon too).
*/
- List<Item> vals= thd->lex->value_list;
+ List<Item> tmpvals= thd->lex->value_list;
+ char *tmpfsc= thd->lex->found_semicolon;
lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
- thd->lex->value_list= vals;
+ thd->lex->value_list= tmpvals;
+ thd->lex->found_semicolon= tmpfsc;
}
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
@@ -305,8 +307,6 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
goto done;
if (sp)
{
- if (oldlex != newlex)
- sp->restore_lex(thd);
delete sp;
newlex->sphead= NULL;
}
@@ -718,8 +718,29 @@ sp_drop_db_routines(THD *thd, char *db)
PROCEDURE
******************************************************************************/
+/*
+ Obtain object representing stored procedure by its name from
+ stored procedures cache and looking into mysql.proc if needed.
+
+ SYNOPSIS
+ sp_find_procedure()
+ thd - thread context
+ name - name of procedure
+ cache_only - if true perform cache-only lookup
+ (Don't look in mysql.proc).
+
+ TODO
+ We should consider merging of sp_find_procedure() and
+ sp_find_function() into one sp_find_routine() function
+ (the same applies to other similarly paired functions).
+
+ RETURN VALUE
+ Non-0 pointer to sp_head object for the procedure, or
+ 0 - in case of error.
+*/
+
sp_head *
-sp_find_procedure(THD *thd, sp_name *name)
+sp_find_procedure(THD *thd, sp_name *name, bool cache_only)
{
sp_head *sp;
DBUG_ENTER("sp_find_procedure");
@@ -727,7 +748,7 @@ sp_find_procedure(THD *thd, sp_name *name)
name->m_db.length, name->m_db.str,
name->m_name.length, name->m_name.str));
- if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)))
+ if (!(sp= sp_cache_lookup(&thd->sp_proc_cache, name)) && !cache_only)
{
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, name, &sp) == SP_OK)
sp_cache_insert(&thd->sp_proc_cache, sp);
@@ -853,6 +874,25 @@ sp_show_status_procedure(THD *thd, const char *wild)
FUNCTION
******************************************************************************/
+/*
+ Obtain object representing stored function by its name from
+ stored functions cache and looking into mysql.proc if needed.
+
+ SYNOPSIS
+ sp_find_function()
+ thd - thread context
+ name - name of function
+ cache_only - if true perform cache-only lookup
+ (Don't look in mysql.proc).
+
+ NOTE
+ See TODO section for sp_find_procedure().
+
+ RETURN VALUE
+ Non-0 pointer to sp_head object for the function, or
+ 0 - in case of error.
+*/
+
sp_head *
sp_find_function(THD *thd, sp_name *name, bool cache_only)
{
@@ -986,79 +1026,120 @@ sp_add_to_hash(HASH *h, sp_name *fun)
}
-void
+/*
+ Merge contents of two hashes containing LEX_STRING's
+
+ SYNOPSIS
+ sp_merge_hash()
+ dst - hash to which elements should be added
+ src - hash from which elements merged
+
+ RETURN VALUE
+ TRUE - if we have added some new elements to destination hash.
+ FALSE - there were no new elements in src.
+*/
+
+bool
sp_merge_hash(HASH *dst, HASH *src)
{
+ bool res= FALSE;
for (uint i=0 ; i < src->records ; i++)
{
LEX_STRING *ls= (LEX_STRING *)hash_element(src, i);
if (! hash_search(dst, (byte *)ls->str, ls->length))
+ {
my_hash_insert(dst, (byte *)ls);
+ res= TRUE;
+ }
}
+ return res;
}
-int
-sp_cache_routines(THD *thd, LEX *lex, int type)
+/*
+ Cache all routines implicitly or explicitly used by query
+ (or whatever object is represented by LEX).
+
+ SYNOPSIS
+ sp_cache_routines()
+ thd - thread context
+ lex - LEX representing query
+
+ NOTE
+ If some function is missing this won't be reported here.
+ Instead this fact will be discovered during query execution.
+
+ TODO
+ Currently if after passing through routine hashes we discover
+ that we have added something to them, we do one more pass to
+ process all routines which were missed on previous pass because
+ of these additions. We can avoid this if along with hashes
+ we use lists holding routine names and iterate other these
+ lists instead of hashes (since addition to the end of list
+ does not reorder elements in it).
+*/
+
+void
+sp_cache_routines(THD *thd, LEX *lex)
{
- HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
- int ret= 0;
+ bool routines_added= TRUE;
- for (uint i=0 ; i < h->records ; i++)
+ DBUG_ENTER("sp_cache_routines");
+
+ while (routines_added)
{
- LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
- sp_name name(*ls);
+ routines_added= FALSE;
- name.m_qname= *ls;
- if (! sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
- &thd->sp_func_cache : &thd->sp_proc_cache),
- &name))
+ for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++)
{
- sp_head *sp;
- LEX *oldlex= thd->lex;
- LEX *newlex= new st_lex;
-
- thd->lex= newlex;
- newlex->proc_table= oldlex->proc_table; // hint if mysql.oper is opened
- newlex->current_select= NULL;
- name.m_name.str= strchr(name.m_qname.str, '.');
- name.m_db.length= name.m_name.str - name.m_qname.str;
- name.m_db.str= strmake_root(thd->mem_root,
- name.m_qname.str, name.m_db.length);
- name.m_name.str+= 1;
- name.m_name.length= name.m_qname.length - name.m_db.length - 1;
-
- if (db_find_routine(thd, type, &name, &sp) == SP_OK)
- {
- if (type == TYPE_ENUM_FUNCTION)
- sp_cache_insert(&thd->sp_func_cache, sp);
- else
- sp_cache_insert(&thd->sp_proc_cache, sp);
- ret= sp_cache_routines(thd, newlex, TYPE_ENUM_FUNCTION);
- if (!ret)
- {
- sp_merge_hash(&lex->spfuns, &newlex->spfuns);
- ret= sp_cache_routines(thd, newlex, TYPE_ENUM_PROCEDURE);
- }
- if (!ret)
- {
- sp_merge_hash(&lex->spprocs, &newlex->spprocs);
- sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
- }
- delete newlex;
- thd->lex= oldlex;
- if (ret)
- break;
- }
- else
+ HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
+
+ for (uint i=0 ; i < h->records ; i++)
{
- delete newlex;
- thd->lex= oldlex;
+ LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
+ sp_name name(*ls);
+ sp_head *sp;
+
+ name.m_qname= *ls;
+ if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
+ &thd->sp_func_cache : &thd->sp_proc_cache),
+ &name)))
+ {
+ LEX *oldlex= thd->lex;
+ LEX *newlex= new st_lex;
+
+ thd->lex= newlex;
+ /* Pass hint pointer to mysql.proc table */
+ newlex->proc_table= oldlex->proc_table;
+ newlex->current_select= NULL;
+ name.m_name.str= strchr(name.m_qname.str, '.');
+ name.m_db.length= name.m_name.str - name.m_qname.str;
+ name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
+ name.m_db.length);
+ name.m_name.str+= 1;
+ name.m_name.length= name.m_qname.length - name.m_db.length - 1;
+
+ if (db_find_routine(thd, type, &name, &sp) == SP_OK)
+ {
+ if (type == TYPE_ENUM_FUNCTION)
+ sp_cache_insert(&thd->sp_func_cache, sp);
+ else
+ sp_cache_insert(&thd->sp_proc_cache, sp);
+ }
+ delete newlex;
+ thd->lex= oldlex;
+ }
+
+ if (sp)
+ {
+ routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns);
+ routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs);
+ }
}
}
}
- return ret;
+ DBUG_VOID_RETURN;
}
/*
diff --git a/sql/sp.h b/sql/sp.h
index 6290324bb86..00dd8416c1d 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -34,7 +34,7 @@ int
sp_drop_db_routines(THD *thd, char *db);
sp_head *
-sp_find_procedure(THD *thd, sp_name *name);
+sp_find_procedure(THD *thd, sp_name *name, bool cache_only = 0);
int
sp_exists_routine(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
@@ -82,10 +82,10 @@ sp_function_exists(THD *thd, sp_name *name);
*/
void
sp_add_to_hash(HASH *h, sp_name *fun);
-void
+bool
sp_merge_hash(HASH *dst, HASH *src);
-int
-sp_cache_routines(THD *thd, LEX *lex, int type);
+void
+sp_cache_routines(THD *thd, LEX *lex);
//
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 06669e398ec..21ef89aea72 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -279,12 +279,16 @@ sp_head::sp_head()
{
extern byte *
sp_table_key(const byte *ptr, uint *plen, my_bool first);
+ extern byte
+ *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
state= INITIALIZED;
m_backpatch.empty();
m_lex.empty();
hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
+ hash_init(&m_spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
+ hash_init(&m_spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
DBUG_VOID_RETURN;
}
@@ -455,13 +459,25 @@ sp_head::destroy()
delete_dynamic(&m_instr);
m_pcont->destroy();
free_items(free_list);
+
+ /*
+ If we have non-empty LEX stack then we just came out of parser with
+ error. Now we should delete all auxilary LEXes and restore original
+ THD::lex (In this case sp_head::restore_thd_mem_root() was not called
+ too, so m_thd points to the current thread context).
+ It is safe to not update LEX::ptr because further query string parsing
+ and execution will be stopped anyway.
+ */
+ DBUG_ASSERT(m_lex.is_empty() || m_thd);
while ((lex= (LEX *)m_lex.pop()))
{
- if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
- delete lex;
+ delete m_thd->lex;
+ m_thd->lex= lex;
}
- if (m_sptabs.array.buffer)
- hash_free(&m_sptabs);
+
+ hash_free(&m_sptabs);
+ hash_free(&m_spfuns);
+ hash_free(&m_spprocs);
DBUG_VOID_RETURN;
}
@@ -475,6 +491,11 @@ sp_head::execute(THD *thd)
int ret= 0;
uint ip= 0;
Item_arena *old_arena;
+ query_id_t old_query_id;
+ TABLE *old_derived_tables;
+ LEX *old_lex;
+ Item_change_list old_change_list;
+ String old_packet;
#ifndef EMBEDDED_LIBRARY
@@ -495,6 +516,34 @@ sp_head::execute(THD *thd)
old_arena= thd->current_arena;
thd->current_arena= this;
+ /*
+ We have to save/restore this info when we are changing call level to
+ be able properly do close_thread_tables() in instructions.
+ */
+ old_query_id= thd->query_id;
+ old_derived_tables= thd->derived_tables;
+ thd->derived_tables= 0;
+ /*
+ It is also more efficient to save/restore current thd->lex once when
+ do it in each instruction
+ */
+ old_lex= thd->lex;
+ /*
+ We should also save Item tree change list to avoid rollback something
+ too early in the calling query.
+ */
+ old_change_list= thd->change_list;
+ thd->change_list.empty();
+ /*
+ Cursors will use thd->packet, so they may corrupt data which was prepared
+ for sending by upper level. OTOH cursors in the same routine can share this
+ buffer safely so let use use routine-local packet instead of having own
+ packet buffer for each cursor.
+
+ It is probably safe to use same thd->convert_buff everywhere.
+ */
+ old_packet.swap(thd->packet);
+
do
{
sp_instr *i;
@@ -506,7 +555,6 @@ sp_head::execute(THD *thd)
DBUG_PRINT("execute", ("Instruction %u", ip));
thd->set_time(); // Make current_time() et al work
ret= i->execute(thd, &ip);
- thd->rollback_item_tree_changes();
if (i->free_list)
cleanup_items(i->free_list);
// Check if an exception has occurred and a handler has been found
@@ -535,6 +583,17 @@ sp_head::execute(THD *thd)
}
} while (ret == 0 && !thd->killed);
+ /* Restore all saved */
+ old_packet.swap(thd->packet);
+ DBUG_ASSERT(thd->change_list.is_empty());
+ thd->change_list= old_change_list;
+ /* To avoid wiping out thd->change_list on old_change_list destruction */
+ old_change_list.empty();
+ thd->lex= old_lex;
+ thd->query_id= old_query_id;
+ DBUG_ASSERT(!thd->derived_tables);
+ thd->derived_tables= old_derived_tables;
+
cleanup_items(thd->current_arena->free_list);
thd->current_arena= old_arena;
@@ -592,14 +651,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
DBUG_RETURN(-1);
}
}
-#ifdef NOT_WORKING
- /*
- Close tables opened for subselect in argument list
- This can't be done as this will close all other tables used
- by the query.
- */
- close_thread_tables(thd);
-#endif
// The rest of the frame are local variables which are all IN.
// Default all variables to null (those with default clauses will
// be set by an set instruction).
@@ -705,10 +756,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
}
}
- // Clean up the joins before closing the tables.
- thd->lex->unit.cleanup();
- // Close tables opened for subselect in argument list
- close_thread_tables(thd);
// The rest of the frame are local variables which are all IN.
// Default all variables to null (those with default clauses will
@@ -819,6 +866,7 @@ sp_head::restore_lex(THD *thd)
LEX *sublex= thd->lex;
LEX *oldlex= (LEX *)m_lex.pop();
+ init_stmt_after_parse(thd, sublex);
if (! oldlex)
return; // Nothing to restore
@@ -827,11 +875,17 @@ sp_head::restore_lex(THD *thd)
oldlex->next_state= sublex->next_state;
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
- // Collect some data from the sub statement lex.
- sp_merge_hash(&oldlex->spfuns, &sublex->spfuns);
- sp_merge_hash(&oldlex->spprocs, &sublex->spprocs);
- // Merge used tables
- sp_merge_table_list(thd, &m_sptabs, sublex->query_tables, sublex);
+ /*
+ Add routines which are used by statement to respective sets for
+ this routine
+ */
+ sp_merge_hash(&m_spfuns, &sublex->spfuns);
+ sp_merge_hash(&m_spprocs, &sublex->spprocs);
+ /*
+ Merge tables used by this statement (but not by its functions or
+ procedures) to multiset of tables used by this routine.
+ */
+ merge_table_list(thd, sublex->query_tables, sublex);
if (! sublex->sp_lex_in_use)
delete sublex;
thd->lex= oldlex;
@@ -961,6 +1015,27 @@ sp_head::restore_thd_mem_root(THD *thd)
}
+bool check_show_routine_acceess(THD *thd, sp_head *sp, bool *full_access)
+{
+ TABLE_LIST tables;
+ bzero((char*) &tables,sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*) "proc";
+ *full_access= !check_table_access(thd, SELECT_ACL, &tables, 1);
+ if (!(*full_access))
+ *full_access= (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
+ !strcmp(sp->m_definer_host.str, thd->priv_host));
+ if (!(*full_access))
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ return check_some_routine_access(thd, (char * )sp->m_db.str,
+ (char * ) sp->m_name.str);
+#endif
+ }
+ return 0;
+}
+
+
int
sp_head::show_create_procedure(THD *thd)
{
@@ -973,11 +1048,15 @@ sp_head::show_create_procedure(THD *thd)
sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
+ bool full_access;
DBUG_ENTER("sp_head::show_create_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str));
LINT_INIT(sql_mode_str);
LINT_INIT(sql_mode_len);
+
+ if (check_show_routine_acceess(thd, this, &full_access))
+ return 1;
old_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode= m_sql_mode;
@@ -1004,7 +1083,8 @@ sp_head::show_create_procedure(THD *thd)
protocol->store(m_name.str, m_name.length, system_charset_info);
if (sql_mode_var)
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
@@ -1042,11 +1122,15 @@ sp_head::show_create_function(THD *thd)
sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
+ bool full_access;
DBUG_ENTER("sp_head::show_create_function");
DBUG_PRINT("info", ("procedure %s", m_name.str));
LINT_INIT(sql_mode_str);
LINT_INIT(sql_mode_len);
+ if (check_show_routine_acceess(thd, this, &full_access))
+ return 1;
+
old_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode= m_sql_mode;
sql_mode_var= find_sys_var("SQL_MODE", 8);
@@ -1071,7 +1155,8 @@ sp_head::show_create_function(THD *thd)
protocol->store(m_name.str, m_name.length, system_charset_info);
if (sql_mode_var)
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
@@ -1133,22 +1218,121 @@ sp_head::opt_mark(uint ip)
// ------------------------------------------------------------------
+
+/*
+ Prepare LEX and thread for execution of instruction, if requested open
+ and lock LEX's tables, execute instruction's core function, perform
+ cleanup afterwards.
+
+ SYNOPSIS
+ reset_lex_and_exec_core()
+ thd - thread context
+ nextp - out - next instruction
+ open_tables - if TRUE then check read access to tables in LEX's table
+ list and open and lock them (used in instructions which
+ need to calculate some expression and don't execute
+ complete statement).
+ sp_instr - instruction for which we prepare context, and which core
+ function execute by calling its exec_core() method.
+
+ NOTE
+ We are not saving/restoring some parts of THD which may need this because
+ we do this once for whole routine execution in sp_head::execute().
+
+ RETURN VALUE
+ 0/non-0 - Success/Failure
+*/
+
+int
+sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
+ bool open_tables, sp_instr* instr)
+{
+ int res= 0;
+
+ DBUG_ASSERT(!thd->derived_tables);
+ DBUG_ASSERT(thd->change_list.is_empty());
+ /*
+ Use our own lex.
+ We should not save old value since it is saved/restored in
+ sp_head::execute() when we are entering/leaving routine.
+ */
+ thd->lex= m_lex;
+
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id= next_query_id();
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ /*
+ FIXME. Resetting statement (and using it) is not reentrant, thus recursive
+ functions which try to use the same LEX twice will crash server.
+ We should prevent such situations by tracking if LEX is already
+ in use and throwing error about unallowed recursion if needed.
+ OTOH it is nice to allow recursion in cases when LEX is not really
+ used (e.g. in mathematical functions), so such tracking should be
+ implemented at the same time as ability not to store LEX for
+ instruction if it is not really used.
+ */
+ reset_stmt_for_execute(thd, m_lex);
+
+ /*
+ If requested check whenever we have access to tables in LEX's table list
+ and open and lock them before executing instructtions core function.
+ */
+ if (open_tables &&
+ (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
+ open_and_lock_tables(thd, m_lex->query_tables)))
+ res= -1;
+
+ if (!res)
+ res= instr->exec_core(thd, nextp);
+
+ m_lex->unit.cleanup();
+
+ thd->proc_info="closing tables";
+ close_thread_tables(thd);
+
+ thd->rollback_item_tree_changes();
+
+ /*
+ Unlike for PS we should not call Item's destructors for newly created
+ items after execution of each instruction in stored routine. This is
+ because SP often create Item (like Item_int, Item_string etc...) when
+ they want to store some value in local variable, pass return value and
+ etc... So their life time should be longer than one instruction.
+
+ Probably we can call destructors for most of them then we are leaving
+ routine. But this won't help much as they are allocated in main query
+ MEM_ROOT anyway. So they all go to global thd->free_list.
+
+ May be we can use some other MEM_ROOT for this purprose ???
+
+ What else should we do for cleanup ?
+ cleanup_items() is called in sp_head::execute()
+ */
+ return res;
+}
+
+
//
-// sp_instr_stmt
+// sp_instr
//
-sp_instr_stmt::~sp_instr_stmt()
+int sp_instr::exec_core(THD *thd, uint *nextp)
{
- if (m_lex)
- delete m_lex;
+ DBUG_ASSERT(0);
+ return 0;
}
+
+//
+// sp_instr_stmt
+//
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
char *query;
uint32 query_length;
DBUG_ENTER("sp_instr_stmt::execute");
- DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
+ DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
int res;
query= thd->query;
@@ -1158,13 +1342,14 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
if (query_cache_send_result_to_client(thd,
thd->query, thd->query_length) <= 0)
{
- res= exec_stmt(thd, m_lex);
+ res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
query_cache_end_of_result(thd);
}
+ else
+ *nextp= m_ip+1;
thd->query= query;
thd->query_length= query_length;
}
- *nextp = m_ip+1;
DBUG_RETURN(res);
}
@@ -1173,39 +1358,15 @@ sp_instr_stmt::print(String *str)
{
str->reserve(12);
str->append("stmt ");
- str->qs_append((uint)m_lex->sql_command);
+ str->qs_append((uint)m_lex_keeper.sql_command());
}
int
-sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
+sp_instr_stmt::exec_core(THD *thd, uint *nextp)
{
- LEX *olex; // The other lex
- int res;
-
- olex= thd->lex; // Save the other lex
- thd->lex= lex; // Use my own lex
- thd->lex->thd = thd; // QQ Not reentrant!
- thd->lex->unit.thd= thd; // QQ Not reentrant
- thd->free_list= NULL;
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id= next_query_id();
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- reset_stmt_for_execute(thd, lex);
-
- res= mysql_execute_command(thd);
-
- lex->unit.cleanup();
- if (thd->lock || thd->open_tables || thd->derived_tables)
- {
- thd->proc_info="closing tables";
- close_thread_tables(thd); /* Free tables */
- }
-
- thd->lex= olex; // Restore the other lex
-
+ int res= mysql_execute_command(thd);
+ *nextp= m_ip+1;
return res;
}
@@ -1217,14 +1378,16 @@ sp_instr_set::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_set::execute");
DBUG_PRINT("info", ("offset: %u", m_offset));
+
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+int
+sp_instr_set::exec_core(THD *thd, uint *nextp)
+{
Item *it;
int res;
- if (tables &&
- ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
- (res= open_and_lock_tables(thd, tables))))
- DBUG_RETURN(res);
-
it= sp_eval_func_item(thd, m_value, m_type);
if (! it)
res= -1;
@@ -1234,9 +1397,8 @@ sp_instr_set::execute(THD *thd, uint *nextp)
thd->spcont->set_item(m_offset, it);
}
*nextp = m_ip+1;
- if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
- close_thread_tables(thd);
- DBUG_RETURN(res);
+
+ return res;
}
void
@@ -1249,32 +1411,6 @@ sp_instr_set::print(String *str)
m_value->print(str);
}
-//
-// sp_instr_set_user_var
-//
-int
-sp_instr_set_user_var::execute(THD *thd, uint *nextp)
-{
- int res= 0;
-
- DBUG_ENTER("sp_instr_set_user_var::execute");
- /*
- It is ok to pass 0 as 3rd argument to fix_fields() since
- Item_func_set_user_var::fix_fields() won't use it.
- QQ: Still unsure what should we return in case of error 1 or -1 ?
- */
- if (!m_set_var_item.fixed && m_set_var_item.fix_fields(thd, 0, 0) ||
- m_set_var_item.check() || m_set_var_item.update())
- res= -1;
- *nextp= m_ip + 1;
- DBUG_RETURN(res);
-}
-
-void
-sp_instr_set_user_var::print(String *str)
-{
- m_set_var_item.print_as_stmt(str);
-}
//
// sp_instr_set_trigger_field
@@ -1367,19 +1503,21 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp)
//
// sp_instr_jump_if
//
+
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if::execute");
DBUG_PRINT("info", ("destination: %u", m_dest));
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+int
+sp_instr_jump_if::exec_core(THD *thd, uint *nextp)
+{
Item *it;
int res;
- if (tables &&
- ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
- (res= open_and_lock_tables(thd, tables))))
- DBUG_RETURN(res);
-
it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (!it)
res= -1;
@@ -1391,9 +1529,8 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
else
*nextp = m_ip+1;
}
- if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
- close_thread_tables(thd);
- DBUG_RETURN(res);
+
+ return res;
}
void
@@ -1429,14 +1566,16 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if_not::execute");
DBUG_PRINT("info", ("destination: %u", m_dest));
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
+{
Item *it;
int res;
- if (tables &&
- ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
- (res= open_and_lock_tables(thd, tables))))
- DBUG_RETURN(res);
-
it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (! it)
res= -1;
@@ -1448,9 +1587,8 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
else
*nextp = m_ip+1;
}
- if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
- close_thread_tables(thd);
- DBUG_RETURN(res);
+
+ return res;
}
void
@@ -1481,18 +1619,21 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
//
// sp_instr_freturn
//
+
int
sp_instr_freturn::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_freturn::execute");
+ DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this));
+}
+
+
+int
+sp_instr_freturn::exec_core(THD *thd, uint *nextp)
+{
Item *it;
int res;
- if (tables &&
- ((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
- (res= open_and_lock_tables(thd, tables))))
- DBUG_RETURN(res);
-
it= sp_eval_func_item(thd, m_value, m_type);
if (! it)
res= -1;
@@ -1502,7 +1643,8 @@ sp_instr_freturn::execute(THD *thd, uint *nextp)
thd->spcont->set_result(it);
}
*nextp= UINT_MAX;
- DBUG_RETURN(res);
+
+ return res;
}
void
@@ -1636,17 +1778,11 @@ int
sp_instr_cpush::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_cpush::execute");
- thd->spcont->push_cursor(m_lex);
+ thd->spcont->push_cursor(&m_lex_keeper);
*nextp= m_ip+1;
DBUG_RETURN(0);
}
-sp_instr_cpush::~sp_instr_cpush()
-{
- if (m_lex)
- delete m_lex;
-}
-
void
sp_instr_cpush::print(String *str)
{
@@ -1693,19 +1829,30 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
res= -1;
else
{
- LEX *lex= c->pre_open(thd);
+ sp_lex_keeper *lex_keeper= c->pre_open(thd);
- if (! lex)
+ if (!lex_keeper)
+ {
res= -1;
+ *nextp= m_ip+1;
+ }
else
- res= exec_stmt(thd, lex);
- c->post_open(thd, (lex ? TRUE : FALSE));
+ res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
+
+ c->post_open(thd, (lex_keeper ? TRUE : FALSE));
}
- *nextp= m_ip+1;
DBUG_RETURN(res);
}
+int
+sp_instr_copen::exec_core(THD *thd, uint *nextp)
+{
+ int res= mysql_execute_command(thd);
+ *nextp= m_ip+1;
+ return res;
+}
+
void
sp_instr_copen::print(String *str)
{
@@ -1857,14 +2004,17 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
/*
- * Table merge hash table
- *
- */
+ Structure that represent all instances of one table
+ in optimized multi-set of tables used by routine.
+*/
+
typedef struct st_sp_table
{
LEX_STRING qname;
bool temp;
TABLE_LIST *table;
+ uint lock_count;
+ uint query_lock_count;
} SP_TABLE;
byte *
@@ -1875,23 +2025,47 @@ sp_table_key(const byte *ptr, uint *plen, my_bool first)
return (byte *)tab->qname.str;
}
+
/*
- * Merge the table list into the hash table.
- * If the optional lex is provided, it's used to check and set
- * the flag for creation of a temporary table.
- */
+ Merge the list of tables used by some query into the multi-set of
+ tables used by routine.
+
+ SYNOPSIS
+ merge_table_list()
+ thd - thread context
+ table - table list
+ lex_for_tmp_check - LEX of the query for which we are merging
+ table list.
+
+ NOTE
+ This method will use LEX provided to check whenever we are creating
+ temporary table and mark it as such in target multi-set.
+
+ RETURN VALUE
+ TRUE - Success
+ FALSE - Error
+*/
+
bool
-sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
- LEX *lex_for_tmp_check)
+sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
{
+ SP_TABLE *tab;
+
+ if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE &&
+ lex_for_tmp_check->drop_temporary)
+ return TRUE;
+
+ for (uint i= 0 ; i < m_sptabs.records ; i++)
+ {
+ tab= (SP_TABLE *)hash_element(&m_sptabs, i);
+ tab->query_lock_count= 0;
+ }
+
for (; table ; table= table->next_global)
- if (!table->derived &&
- (!table->select_lex ||
- !(table->select_lex->options & OPTION_SCHEMA_TABLE)))
+ if (!table->derived && !table->schema_table)
{
char tname[64+1+64+1+64+1]; // db.table.alias\0
uint tlen, alen;
- SP_TABLE *tab;
tlen= table->db_length;
memcpy(tname, table->db, tlen);
@@ -1904,10 +2078,17 @@ sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
tlen+= alen;
tname[tlen]= '\0';
- if ((tab= (SP_TABLE *)hash_search(h, (byte *)tname, tlen)))
+ /*
+ It is safe to store pointer to table list elements in hash,
+ since they are supposed to have the same lifetime.
+ */
+ if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)))
{
if (tab->table->lock_type < table->lock_type)
tab->table= table; // Use the table with the highest lock type
+ tab->query_lock_count++;
+ if (tab->query_lock_count > tab->lock_count)
+ tab->lock_count++;
}
else
{
@@ -1917,152 +2098,102 @@ sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
tab->qname.str= (char *)thd->strmake(tname, tab->qname.length);
if (!tab->qname.str)
return FALSE;
- if (lex_for_tmp_check &&
- lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
+ if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
lex_for_tmp_check->query_tables == table &&
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
tab->temp= TRUE;
tab->table= table;
- my_hash_insert(h, (byte *)tab);
+ tab->lock_count= tab->query_lock_count= 1;
+ my_hash_insert(&m_sptabs, (byte *)tab);
}
}
return TRUE;
}
-void
-sp_merge_routine_tables(THD *thd, LEX *lex)
-{
- uint i;
- for (i= 0 ; i < lex->spfuns.records ; i++)
- {
- sp_head *sp;
- LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spfuns, i);
- sp_name name(*ls);
+/*
+ Add tables used by routine to the table list.
- name.m_qname= *ls;
- if ((sp= sp_cache_lookup(&thd->sp_func_cache, &name)))
- sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
- }
- for (i= 0 ; i < lex->spprocs.records ; i++)
- {
- sp_head *sp;
- LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spprocs, i);
- sp_name name(*ls);
+ SYNOPSIS
+ add_used_tables_to_table_list()
+ thd - thread context
+ query_tables_last_ptr - (in/out) pointer the next_global member of last
+ element of the list where tables will be added
+ (or to its root).
- name.m_qname= *ls;
- if ((sp= sp_cache_lookup(&thd->sp_proc_cache, &name)))
- sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
- }
-}
+ DESCRIPTION
+ Converts multi-set of tables used by this routine to table list and adds
+ this list to the end of table list specified by 'query_tables_last_ptr'.
-void
-sp_merge_table_hash(HASH *hdst, HASH *hsrc)
-{
- for (uint i=0 ; i < hsrc->records ; i++)
- {
- SP_TABLE *tabdst;
- SP_TABLE *tabsrc= (SP_TABLE *)hash_element(hsrc, i);
+ Elements of list will be allocated in PS memroot, so this list will be
+ persistent between PS executions.
- if (! (tabdst= (SP_TABLE *)hash_search(hdst,
- (byte *) tabsrc->qname.str,
- tabsrc->qname.length)))
- {
- my_hash_insert(hdst, (byte *)tabsrc);
- }
- else
- {
- if (tabdst->table->lock_type < tabsrc->table->lock_type)
- tabdst->table= tabsrc->table; // Use the highest lock type
- }
- }
-}
+ RETURN VALUE
+ TRUE - if some elements were added, FALSE - otherwise.
+*/
-TABLE_LIST *
-sp_hash_to_table_list(THD *thd, HASH *h)
+bool
+sp_head::add_used_tables_to_table_list(THD *thd,
+ TABLE_LIST ***query_tables_last_ptr)
{
uint i;
- TABLE_LIST *tables= NULL;
- DBUG_ENTER("sp_hash_to_table_list");
+ Item_arena *arena, backup;
+ bool result= FALSE;
+ DBUG_ENTER("sp_head::add_used_tables_to_table_list");
+
+ /*
+ Use persistent arena for table list allocation to be PS friendly.
+ */
+ arena= thd->change_arena_if_needed(&backup);
- for (i=0 ; i < h->records ; i++)
+ for (i=0 ; i < m_sptabs.records ; i++)
{
- SP_TABLE *stab= (SP_TABLE *)hash_element(h, i);
+ char *tab_buff;
+ TABLE_LIST *table, *otable;
+ SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
if (stab->temp)
continue;
- TABLE_LIST *table, *otable= stab->table;
-
- if (! (table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
- return NULL;
- table->db= otable->db;
- table->db_length= otable->db_length;
- table->alias= otable->alias;
- table->table_name= otable->table_name;
- table->table_name_length= otable->table_name_length;
- table->lock_type= otable->lock_type;
- table->updating= otable->updating;
- table->force_index= otable->force_index;
- table->ignore_leaves= otable->ignore_leaves;
- table->derived= otable->derived;
- table->schema_table= otable->schema_table;
- table->select_lex= otable->select_lex;
- table->cacheable_table= otable->cacheable_table;
- table->use_index= otable->use_index;
- table->ignore_index= otable->ignore_index;
- table->option= otable->option;
-
- table->next_global= tables;
- tables= table;
- }
- DBUG_RETURN(tables);
-}
-bool
-sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
-{
- DBUG_ENTER("sp_open_and_lock_tables");
- bool ret;
+ otable= stab->table;
- thd->in_lock_tables= 1;
- thd->options|= OPTION_TABLE_LOCK;
- if (simple_open_n_lock_tables(thd, tables))
- {
- thd->options&= ~(ulong)(OPTION_TABLE_LOCK);
- ret= FALSE;
- }
- else
- {
-#if 0
- // QQ What about this?
-#ifdef HAVE_QUERY_CACHE
- if (thd->variables.query_cache_wlock_invalidate)
- query_cache.invalidate_locked_for_write(first_table); // QQ first_table?
-#endif /* HAVE_QUERY_CACHE */
-#endif
- thd->locked_tables= thd->lock;
- thd->lock= 0;
- ret= TRUE;
- }
- thd->in_lock_tables= 0;
- DBUG_RETURN(ret);
-}
+ if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
+ stab->lock_count)))
+ DBUG_RETURN(FALSE);
-void
-sp_unlock_tables(THD *thd)
-{
- thd->lock= thd->locked_tables;
- thd->locked_tables= 0;
- close_thread_tables(thd); // Free tables
- if (thd->options & OPTION_TABLE_LOCK)
- {
-#if 0
- // QQ What about this?
- end_active_trans(thd);
-#endif
- thd->options&= ~(ulong)(OPTION_TABLE_LOCK);
+ for (uint j= 0; j < stab->lock_count; j++)
+ {
+ table= (TABLE_LIST *)tab_buff;
+
+ /*
+ It's enough to just copy the pointers as the data will not change
+ during the lifetime of the SP. If the SP is used by PS, we assume
+ that the PS will be invalidated if the functions is deleted or
+ changed.
+ */
+ table->db= otable->db;
+ table->db_length= otable->db_length;
+ table->alias= otable->alias;
+ table->table_name= otable->table_name;
+ table->table_name_length= otable->table_name_length;
+ table->lock_type= otable->lock_type;
+ table->cacheable_table= 1;
+ table->prelocking_placeholder= 1;
+
+ /* Everyting else should be zeroed */
+
+ **query_tables_last_ptr= table;
+ table->prev_global= *query_tables_last_ptr;
+ *query_tables_last_ptr= &table->next_global;
+
+ tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
+ result= TRUE;
+ }
}
- if (thd->global_read_lock)
- unlock_global_read_lock(thd);
+
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+
+ DBUG_RETURN(result);
}
/*
@@ -2094,3 +2225,73 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
lex->add_to_query_tables(table);
return table;
}
+
+
+/*
+ Auxilary function for adding tables used by routines used in query
+ to table lists.
+
+ SYNOPSIS
+ sp_add_sp_tables_to_table_list_aux()
+ thd - thread context
+ lex - LEX to which table list tables will be added
+ func_hash - routines for which tables should be added
+ func_cache- SP cache in which this routines should be looked up
+
+ NOTE
+ See sp_add_sp_tables_to_table_list() for more info.
+
+ RETURN VALUE
+ TRUE - some tables were added
+ FALSE - no tables were added.
+*/
+
+static bool
+sp_add_sp_tables_to_table_list_aux(THD *thd, LEX *lex, HASH *func_hash,
+ sp_cache **func_cache)
+{
+ uint i;
+ bool result= FALSE;
+
+ for (i= 0 ; i < func_hash->records ; i++)
+ {
+ sp_head *sp;
+ LEX_STRING *ls= (LEX_STRING *)hash_element(func_hash, i);
+ sp_name name(*ls);
+
+ name.m_qname= *ls;
+ if ((sp= sp_cache_lookup(func_cache, &name)))
+ result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last);
+ }
+
+ return result;
+}
+
+
+/*
+ Add tables used by routines used in query to table list.
+
+ SYNOPSIS
+ sp_add_sp_tables_to_table_list()
+ thd - thread context
+ lex - LEX to which table list tables will be added
+ func_lex - LEX for which functions we get tables
+ (useful for adding tables used by view routines)
+
+ NOTE
+ Elements of list will be allocated in PS memroot, so this
+ list will be persistent between PS execetutions.
+
+ RETURN VALUE
+ TRUE - some tables were added
+ FALSE - no tables were added.
+*/
+
+bool
+sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex)
+{
+ return (sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spfuns,
+ &thd->sp_func_cache) |
+ sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spprocs,
+ &thd->sp_proc_cache));
+}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 5df9c753048..60979a438cb 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -103,7 +103,14 @@ public:
LEX_STRING m_definer_host;
longlong m_created;
longlong m_modified;
- HASH m_sptabs; /* Merged table lists */
+ /*
+ Sets containing names of SP and SF used by this routine.
+
+ TODO Probably we should combine these two hashes in one. It will
+ decrease memory overhead ans simplify algorithms using them. The
+ same applies to similar hashes in LEX.
+ */
+ HASH m_spfuns, m_spprocs;
// Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end,
*m_body_begin;
@@ -225,6 +232,10 @@ public:
return ip;
}
+ /* Add tables used by routine to the table list. */
+ bool add_used_tables_to_table_list(THD *thd,
+ TABLE_LIST ***query_tables_last_ptr);
+
private:
MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
@@ -240,10 +251,20 @@ private:
sp_instr *instr;
} bp_t;
List<bp_t> m_backpatch; // Instructions needing backpatching
+ /*
+ Multi-set representing optimized list of tables to be locked by this
+ routine. Does not include tables which are used by invoked routines.
+ */
+ HASH m_sptabs;
int
execute(THD *thd);
+ /*
+ Merge the list of tables used by query into the multi-set of tables used
+ by routine.
+ */
+ bool merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check);
}; // class sp_head : public Sql_alloc
@@ -277,6 +298,17 @@ public:
// Returns 0 on success, non-zero if some error occured.
virtual int execute(THD *thd, uint *nextp) = 0;
+ /*
+ Execute core function of instruction after all preparations (e.g.
+ setting of proper LEX, saving part of the thread context have been
+ done).
+
+ Should be implemented for instructions using expressions or whole
+ statements (thus having to have own LEX). Used in concert with
+ sp_lex_keeper class and its descendants.
+ */
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str) = 0;
virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
@@ -301,6 +333,60 @@ public:
}; // class sp_instr : public Sql_alloc
+/*
+ Auxilary class to which instructions delegate responsibility
+ for handling LEX and preparations before executing statement
+ or calculating complex expression.
+
+ Exist mainly to avoid having double hierarchy between instruction
+ classes.
+
+ TODO: Add ability to not store LEX and do any preparations if
+ expression used is simple.
+*/
+
+class sp_lex_keeper
+{
+ /* Prevent use of these */
+ sp_lex_keeper(const sp_lex_keeper &);
+ void operator=(sp_lex_keeper &);
+public:
+
+ sp_lex_keeper(LEX *lex, bool lex_resp)
+ : m_lex(lex), m_lex_resp(lex_resp)
+ {
+ lex->sp_lex_in_use= TRUE;
+ }
+ virtual ~sp_lex_keeper()
+ {
+ if (m_lex_resp)
+ delete m_lex;
+ }
+
+ /*
+ Prepare execution of instruction using LEX, if requested check whenever
+ we have read access to tables used and open/lock them, call instruction's
+ exec_core() method, perform cleanup afterwards.
+ */
+ int reset_lex_and_exec_core(THD *thd, uint *nextp, bool open_tables,
+ sp_instr* instr);
+
+ inline uint sql_command() const
+ {
+ return (uint)m_lex->sql_command;
+ }
+
+private:
+
+ LEX *m_lex;
+ /*
+ Indicates whenever this sp_lex_keeper instance responsible
+ for LEX deletion.
+ */
+ bool m_lex_resp;
+};
+
+
//
// Call out to some prepared SQL statement.
//
@@ -313,38 +399,25 @@ public:
LEX_STRING m_query; // For thd->query
- sp_instr_stmt(uint ip, sp_pcontext *ctx)
- : sp_instr(ip, ctx), m_lex(NULL)
+ sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex)
+ : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
{
m_query.str= 0;
m_query.length= 0;
}
- virtual ~sp_instr_stmt();
+ virtual ~sp_instr_stmt()
+ {};
virtual int execute(THD *thd, uint *nextp);
- virtual void print(String *str);
-
- inline void
- set_lex(LEX *lex)
- {
- m_lex= lex;
- }
-
- inline LEX *
- get_lex()
- {
- return m_lex;
- }
+ virtual int exec_core(THD *thd, uint *nextp);
-protected:
-
- int exec_stmt(THD *thd, LEX *lex); // Execute a statement
+ virtual void print(String *str);
private:
- LEX *m_lex; // My own lex
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_stmt : public sp_instr
@@ -356,12 +429,11 @@ class sp_instr_set : public sp_instr
public:
- TABLE_LIST *tables;
-
sp_instr_set(uint ip, sp_pcontext *ctx,
- uint offset, Item *val, enum enum_field_types type)
- : sp_instr(ip, ctx),
- tables(NULL), m_offset(offset), m_value(val), m_type(type)
+ uint offset, Item *val, enum enum_field_types type,
+ LEX *lex, bool lex_resp)
+ : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
+ m_lex_keeper(lex, lex_resp)
{}
virtual ~sp_instr_set()
@@ -369,6 +441,8 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
private:
@@ -376,42 +450,12 @@ private:
uint m_offset; // Frame offset
Item *m_value;
enum enum_field_types m_type; // The declared type
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_set : public sp_instr
/*
- Set user variable instruction.
- Used in functions and triggers to set user variables because we don't
- want use sp_instr_stmt + "SET @a:=..." statement in this case since
- latter will close all tables and thus will ruin execution of statement
- calling/invoking this function/trigger.
-*/
-class sp_instr_set_user_var : public sp_instr
-{
- sp_instr_set_user_var(const sp_instr_set_user_var &);
- void operator=(sp_instr_set_user_var &);
-
-public:
-
- sp_instr_set_user_var(uint ip, sp_pcontext *ctx, LEX_STRING var, Item *val)
- : sp_instr(ip, ctx), m_set_var_item(var, val)
- {}
-
- virtual ~sp_instr_set_user_var()
- {}
-
- virtual int execute(THD *thd, uint *nextp);
-
- virtual void print(String *str);
-
-private:
-
- Item_func_set_user_var m_set_var_item;
-}; // class sp_instr_set_user_var : public sp_instr
-
-
-/*
Set NEW/OLD row field value instruction. Used in triggers.
*/
class sp_instr_set_trigger_field : public sp_instr
@@ -492,14 +536,12 @@ class sp_instr_jump_if : public sp_instr_jump
public:
- TABLE_LIST *tables;
-
- sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i)
- : sp_instr_jump(ip, ctx), tables(NULL), m_expr(i)
+ sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
+ : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
{}
- sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest)
- : sp_instr_jump(ip, ctx, dest), tables(NULL), m_expr(i)
+ sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
+ : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_jump_if()
@@ -507,6 +549,8 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
virtual uint opt_mark(sp_head *sp);
@@ -519,6 +563,7 @@ public:
private:
Item *m_expr; // The condition
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_jump_if : public sp_instr_jump
@@ -530,14 +575,12 @@ class sp_instr_jump_if_not : public sp_instr_jump
public:
- TABLE_LIST *tables;
-
- sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i)
- : sp_instr_jump(ip, ctx), tables(NULL), m_expr(i)
+ sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex)
+ : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE)
{}
- sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest)
- : sp_instr_jump(ip, ctx, dest), tables(NULL), m_expr(i)
+ sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex)
+ : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_jump_if_not()
@@ -545,6 +588,8 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
virtual uint opt_mark(sp_head *sp);
@@ -557,6 +602,7 @@ public:
private:
Item *m_expr; // The condition
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_jump_if_not : public sp_instr_jump
@@ -568,11 +614,9 @@ class sp_instr_freturn : public sp_instr
public:
- TABLE_LIST *tables;
-
sp_instr_freturn(uint ip, sp_pcontext *ctx,
- Item *val, enum enum_field_types type)
- : sp_instr(ip, ctx), tables(NULL), m_value(val), m_type(type)
+ Item *val, enum enum_field_types type, LEX *lex)
+ : sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_freturn()
@@ -580,6 +624,8 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
virtual uint opt_mark(sp_head *sp)
@@ -592,6 +638,7 @@ protected:
Item *m_value;
enum enum_field_types m_type;
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_freturn : public sp_instr
@@ -710,10 +757,11 @@ class sp_instr_cpush : public sp_instr
public:
sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex)
- : sp_instr(ip, ctx), m_lex(lex)
+ : sp_instr(ip, ctx), m_lex_keeper(lex, TRUE)
{}
- virtual ~sp_instr_cpush();
+ virtual ~sp_instr_cpush()
+ {}
virtual int execute(THD *thd, uint *nextp);
@@ -721,7 +769,7 @@ public:
private:
- LEX *m_lex;
+ sp_lex_keeper m_lex_keeper;
}; // class sp_instr_cpush : public sp_instr
@@ -760,7 +808,7 @@ private:
}; // class sp_instr_cpop : public sp_instr
-class sp_instr_copen : public sp_instr_stmt
+class sp_instr_copen : public sp_instr
{
sp_instr_copen(const sp_instr_copen &); /* Prevent use of these */
void operator=(sp_instr_copen &);
@@ -768,7 +816,7 @@ class sp_instr_copen : public sp_instr_stmt
public:
sp_instr_copen(uint ip, sp_pcontext *ctx, uint c)
- : sp_instr_stmt(ip, ctx), m_cursor(c)
+ : sp_instr(ip, ctx), m_cursor(c)
{}
virtual ~sp_instr_copen()
@@ -776,6 +824,8 @@ public:
virtual int execute(THD *thd, uint *nextp);
+ virtual int exec_core(THD *thd, uint *nextp);
+
virtual void print(String *str);
private:
@@ -893,22 +943,11 @@ void
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-bool
-sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
- LEX *lex_for_tmp_check = 0);
-void
-sp_merge_routine_tables(THD *thd, LEX *lex);
-void
-sp_merge_table_hash(HASH *hdst, HASH *hsrc);
-TABLE_LIST *
-sp_hash_to_table_list(THD *thd, HASH *h);
-bool
-sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
-void
-sp_unlock_tables(THD *thd);
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
thr_lock_type locktype);
+bool
+sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex);
#endif /* _SP_HEAD_H_ */
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 5b177650726..9b29c173856 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -125,9 +125,9 @@ sp_rcontext::restore_variables(uint fp)
}
void
-sp_rcontext::push_cursor(LEX *lex)
+sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper)
{
- m_cstack[m_ccount++]= new sp_cursor(lex);
+ m_cstack[m_ccount++]= new sp_cursor(lex_keeper);
}
void
@@ -148,7 +148,7 @@ sp_rcontext::pop_cursors(uint count)
// We have split this in two to make it easy for sp_instr_copen
// to reuse the sp_instr::exec_stmt() code.
-LEX *
+sp_lex_keeper*
sp_cursor::pre_open(THD *thd)
{
if (m_isopen)
@@ -168,7 +168,7 @@ sp_cursor::pre_open(THD *thd)
m_nseof= thd->net.no_send_eof;
thd->net.no_send_eof= TRUE;
- return m_lex;
+ return m_lex_keeper;
}
void
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 8e818ab76d1..37d718048a0 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -25,6 +25,7 @@
struct sp_cond_type;
class sp_cursor;
struct sp_pvar;
+class sp_lex_keeper;
#define SP_HANDLER_NONE 0
#define SP_HANDLER_EXIT 1
@@ -164,7 +165,7 @@ class sp_rcontext : public Sql_alloc
restore_variables(uint fp);
void
- push_cursor(LEX *lex);
+ push_cursor(sp_lex_keeper *lex_keeper);
void
pop_cursors(uint count);
@@ -207,8 +208,8 @@ class sp_cursor : public Sql_alloc
{
public:
- sp_cursor(LEX *lex)
- : m_lex(lex), m_prot(NULL), m_isopen(0), m_current_row(NULL)
+ sp_cursor(sp_lex_keeper *lex_keeper)
+ : m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL)
{
/* Empty */
}
@@ -220,7 +221,7 @@ public:
// We have split this in two to make it easy for sp_instr_copen
// to reuse the sp_instr::exec_stmt() code.
- LEX *
+ sp_lex_keeper *
pre_open(THD *thd);
void
post_open(THD *thd, my_bool was_opened);
@@ -240,7 +241,7 @@ public:
private:
MEM_ROOT m_mem_root; // My own mem_root
- LEX *m_lex;
+ sp_lex_keeper *m_lex_keeper;
Protocol_cursor *m_prot;
my_bool m_isopen;
my_bool m_nseof; // Original no_send_eof
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index f5c69269231..3db219b5fdc 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -138,7 +138,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
TABLE_LIST tables[3];
TABLE *table;
READ_RECORD read_record_info;
- MYSQL_LOCK *lock;
my_bool return_val=1;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
@@ -176,20 +175,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
tables[0].db=tables[1].db=tables[2].db=thd->db;
- uint counter;
- if (open_tables(thd, tables, &counter))
- {
- sql_print_error("Fatal error: Can't open privilege tables: %s",
- thd->net.last_error);
- goto end;
- }
- TABLE *ptr[3]; // Lock tables for quick update
- ptr[0]= tables[0].table;
- ptr[1]= tables[1].table;
- ptr[2]= tables[2].table;
- if (!(lock=mysql_lock_tables(thd,ptr,3)))
+ if (simple_open_n_lock_tables(thd, tables))
{
- sql_print_error("Fatal error: Can't lock privilege tables: %s",
+ sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
thd->net.last_error);
goto end;
}
@@ -459,7 +447,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
freeze_size(&acl_dbs);
init_check_host();
- mysql_unlock_tables(thd, lock);
initialized=1;
thd->version--; // Force close to free memory
return_val=0;
@@ -1928,7 +1915,8 @@ static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
class GRANT_NAME :public Sql_alloc
{
public:
- char *host,*db, *user, *tname, *hash_key, *orig_host;
+ acl_host_and_ip host;
+ char *db, *user, *tname, *hash_key;
ulong privs;
ulong sort;
uint key_length;
@@ -1960,12 +1948,10 @@ GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
:privs(p)
{
/* Host given by user */
- orig_host= strdup_root(&memex,h);
- /* Convert empty hostname to '%' for easy comparison */
- host= orig_host[0] ? orig_host : (char*) "%";
+ update_hostname(&host, strdup_root(&memex, h));
db = strdup_root(&memex,d);
user = strdup_root(&memex,u);
- sort= get_sort(3,host,db,user);
+ sort= get_sort(3,host.hostname,db,user);
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
@@ -1989,17 +1975,12 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
GRANT_NAME::GRANT_NAME(TABLE *form)
{
- orig_host= host= get_field(&memex, form->field[0]);
+ update_hostname(&host, get_field(&memex, form->field[0]));
db= get_field(&memex,form->field[1]);
user= get_field(&memex,form->field[2]);
if (!user)
user= (char*) "";
- if (!orig_host)
- {
- orig_host= (char*) "";
- host= (char*) "%";
- }
- sort= get_sort(3, orig_host, db, user);
+ sort= get_sort(3, host.hostname, db, user);
tname= get_field(&memex,form->field[3]);
if (!db || !tname)
{
@@ -2042,7 +2023,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
{
uint key_prefix_len;
KEY_PART_INFO *key_part= col_privs->key_info->key_part;
- col_privs->field[0]->store(orig_host,(uint) strlen(orig_host),
+ col_privs->field[0]->store(host.hostname,(uint) strlen(host.hostname),
system_charset_info);
col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
@@ -2128,17 +2109,12 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
{
if (exact)
{
- if ((host &&
- !my_strcasecmp(system_charset_info, host, grant_name->host)) ||
- (ip && !strcmp(ip,grant_name->host)))
+ if (compare_hostname(&grant_name->host, host, ip))
return grant_name;
}
else
{
- if (((host && !wild_case_compare(system_charset_info,
- host,grant_name->host)) ||
- (ip && !wild_case_compare(system_charset_info,
- ip,grant_name->host))) &&
+ if (compare_hostname(&grant_name->host, host, ip) &&
(!found || found->sort < grant_name->sort))
found=grant_name; // Host ok
}
@@ -3123,7 +3099,6 @@ my_bool grant_init(THD *org_thd)
{
THD *thd;
TABLE_LIST tables[3];
- MYSQL_LOCK *lock;
MEM_ROOT *memex_ptr;
my_bool return_val= 1;
TABLE *t_table, *c_table, *p_table;
@@ -3157,15 +3132,7 @@ my_bool grant_init(THD *org_thd)
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
tables[0].db=tables[1].db=tables[2].db=thd->db;
- uint counter;
- if (open_tables(thd, tables, &counter))
- goto end;
-
- TABLE *ptr[3]; // Lock tables for quick update
- ptr[0]= tables[0].table;
- ptr[1]= tables[1].table;
- ptr[2]= tables[2].table;
- if (!(lock=mysql_lock_tables(thd,ptr,3)))
+ if (simple_open_n_lock_tables(thd, tables))
goto end;
t_table = tables[0].table; c_table = tables[1].table;
@@ -3189,7 +3156,7 @@ my_bool grant_init(THD *org_thd)
if (check_no_resolve)
{
- if (hostname_requires_resolving(mem_check->host))
+ if (hostname_requires_resolving(mem_check->host.hostname))
{
sql_print_warning("'tables_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
@@ -3227,7 +3194,7 @@ my_bool grant_init(THD *org_thd)
if (check_no_resolve)
{
- if (hostname_requires_resolving(mem_check->host))
+ if (hostname_requires_resolving(mem_check->host.hostname))
{
sql_print_warning("'procs_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
@@ -3255,7 +3222,6 @@ my_bool grant_init(THD *org_thd)
end_unlock:
t_table->file->ha_index_end();
p_table->file->ha_index_end();
- mysql_unlock_tables(thd, lock);
thd->version--; // Force close to free memory
end:
@@ -3541,10 +3507,7 @@ bool check_grant_db(THD *thd,const char *db)
idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
- (thd->host && !wild_case_compare(system_charset_info,
- thd->host,grant_table->host) ||
- (thd->ip && !wild_case_compare(system_charset_info,
- thd->ip,grant_table->host))))
+ compare_hostname(&grant_table->host, thd->host, thd->ip))
{
error=0; // Found match
break;
@@ -3620,6 +3583,37 @@ err:
}
+/*
+ Check if routine has any of the
+ procedure level grants
+
+ SYNPOSIS
+ bool check_routine_level_acl()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 1 error
+ 0 Ok
+*/
+
+bool check_routine_level_acl(THD *thd, char *db, char *name)
+{
+ bool no_routine_acl= 1;
+ if (grant_option)
+ {
+ GRANT_NAME *grant_proc;
+ rw_rdlock(&LOCK_grant);
+ if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db,
+ thd->priv_user, name, 0)))
+ no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
+ rw_unlock(&LOCK_grant);
+ }
+ return no_routine_acl;
+}
+
+
/*****************************************************************************
Functions to retrieve the grant for a table/column (for SHOW functions)
*****************************************************************************/
@@ -3964,7 +3958,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str,
- grant_table->orig_host))
+ grant_table->host.hostname))
{
ulong table_access= grant_table->privs;
if ((table_access | grant_table->cols) != 0)
@@ -4071,7 +4065,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str,
- grant_proc->orig_host))
+ grant_proc->host.hostname))
{
ulong proc_access= grant_proc->privs;
if (proc_access != 0)
@@ -4557,19 +4551,22 @@ static int handle_grant_struct(uint struct_no, bool drop,
case 1:
acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
user= acl_db->user;
- host= acl_db->host.hostname;
+ if (!(host= acl_db->host.hostname))
+ host= "%";
break;
case 2:
grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx);
user= grant_name->user;
- host= grant_name->host;
+ if (!(host= grant_name->host.hostname))
+ host= "%";
break;
case 3:
grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx);
user= grant_name->user;
- host= grant_name->host;
+ if (!(host= grant_name->host.hostname))
+ host= "%";
break;
}
if (! user)
@@ -4624,7 +4621,8 @@ static int handle_grant_struct(uint struct_no, bool drop,
case 2:
case 3:
grant_name->user= strdup_root(&mem, user_to->user.str);
- grant_name->host= strdup_root(&mem, user_to->host.str);
+ update_hostname(&grant_name->host,
+ strdup_root(&mem, user_to->host.str));
break;
}
}
@@ -5035,7 +5033,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
counter);
if (!(user=grant_table->user))
user= "";
- if (!(host=grant_table->host))
+ if (!(host=grant_table->host.hostname))
host= "";
if (!strcmp(lex_user->user.str,user) &&
@@ -5081,7 +5079,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
counter);
if (!(user=grant_proc->user))
user= "";
- if (!(host=grant_proc->host))
+ if (!(host=grant_proc->host.hostname))
host= "";
if (!strcmp(lex_user->user.str,user) &&
@@ -5153,8 +5151,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
LEX_USER lex_user;
lex_user.user.str= grant_proc->user;
lex_user.user.length= strlen(grant_proc->user);
- lex_user.host.str= grant_proc->host;
- lex_user.host.length= strlen(grant_proc->host);
+ lex_user.host.str= grant_proc->host.hostname;
+ lex_user.host.length= strlen(grant_proc->host.hostname);
if (!replace_proc_table(thd,grant_proc,tables[4].table,lex_user,
grant_proc->db, grant_proc->tname, ~0, 1))
{
@@ -5438,7 +5436,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
if (!(table_access & GRANT_ACL))
is_grantable= "NO";
- strxmov(buff,"'",user,"'@'",grant_table->orig_host,"'",NullS);
+ strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
if (!test_access)
update_schema_privilege(table, buff, grant_table->db, grant_table->tname,
0, 0, "USAGE", 5, is_grantable);
@@ -5485,7 +5483,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
is_grantable= "NO";
ulong test_access= table_access & ~GRANT_ACL;
- strxmov(buff,"'",user,"'@'",grant_table->orig_host,"'",NullS);
+ strxmov(buff,"'",user,"'@'",grant_table->host.hostname,"'",NullS);
if (!test_access)
continue;
else
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 3a9df84a35d..30e335c7afd 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -63,6 +63,9 @@
#define PROC_ACLS \
(ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL)
+#define SHOW_PROC_ACLS \
+(ALTER_PROC_ACL | EXECUTE_ACL | CREATE_PROC_ACL)
+
#define GLOBAL_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | GRANT_ACL | \
@@ -216,6 +219,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name);
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name);
+bool check_routine_level_acl(THD *thd, char *db, char *name);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 6b75fd1847b..4fd943c08f4 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -20,6 +20,7 @@
#include "mysql_priv.h"
#include "sql_select.h"
#include "sp_head.h"
+#include "sp.h"
#include "sql_trigger.h"
#include <m_ctype.h>
#include <my_dir.h>
@@ -359,7 +360,30 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
/*
- Close all tables used by thread
+ Mark all tables in the list which were used by current substatement
+ as free for reuse.
+
+ SYNOPSIS
+ mark_used_tables_as_free_for_reuse()
+ thd - thread context
+ table - head of the list of tables
+
+ DESCRIPTION
+ Marks all tables in the list which were used by current substatement
+ (they are marked by its query_id) as free for reuse.
+*/
+
+static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
+{
+ for (; table ; table= table->next)
+ if (table->query_id == thd->query_id)
+ table->query_id= 0;
+}
+
+
+/*
+ Close all tables used by the current substatement, or all tables
+ used by this thread if we are on the upper level.
SYNOPSIS
close_thread_tables()
@@ -372,14 +396,31 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
IMPLEMENTATION
Unlocks tables and frees derived tables.
Put all normal tables used by thread in free list.
+
+ When in prelocked mode it will only close/mark as free for reuse
+ tables opened by this substatement, it will also check if we are
+ closing tables after execution of complete query (i.e. we are on
+ upper level) and will leave prelocked mode if needed.
*/
void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
TABLE *stopper)
{
bool found_old_table;
+ prelocked_mode_type prelocked_mode= thd->prelocked_mode;
DBUG_ENTER("close_thread_tables");
+ /*
+ We are assuming here that thd->derived_tables contains ONLY derived
+ tables for this substatement. i.e. instead of approach which uses
+ query_id matching for determining which of the derived tables belong
+ to this substatement we rely on the ability of substatements to
+ save/restore thd->derived_tables during their execution.
+
+ TODO: Probably even better approach is to simply associate list of
+ derived tables with (sub-)statement instead of thread and destroy
+ them at the end of its execution.
+ */
if (thd->derived_tables && !skip_derived)
{
TABLE *table, *next;
@@ -394,10 +435,50 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
}
thd->derived_tables= 0;
}
- if (thd->locked_tables)
+
+ if (prelocked_mode)
{
- ha_commit_stmt(thd); // If select statement
- DBUG_VOID_RETURN; // LOCK TABLES in use
+ /*
+ Mark all temporary tables used by this substatement as free for reuse.
+ */
+ mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
+ }
+
+ if (thd->locked_tables || prelocked_mode)
+ {
+ /*
+ TODO: It is not 100% clear whenever we should do ha_commit_stmt() for
+ sub-statements. This issue needs additional investigation.
+ */
+ ha_commit_stmt(thd);
+
+ /* We are under simple LOCK TABLES so should not do anything else. */
+ if (!prelocked_mode)
+ DBUG_VOID_RETURN;
+
+ if (!thd->lex->requires_prelocking())
+ {
+ /*
+ If we are executing one of substatements we have to mark
+ all tables which it used as free for reuse.
+ */
+ mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
+ DBUG_VOID_RETURN;
+ }
+
+ DBUG_ASSERT(prelocked_mode);
+ /*
+ We are in prelocked mode, so we have to leave it now with doing
+ implicit UNLOCK TABLES if need.
+ */
+ thd->prelocked_mode= NON_PRELOCKED;
+
+ if (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES)
+ DBUG_VOID_RETURN;
+
+ thd->lock= thd->locked_tables;
+ thd->locked_tables= 0;
+ /* Fallthrough */
}
if (thd->lock)
@@ -441,6 +522,17 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
if (!lock_in_use)
VOID(pthread_mutex_unlock(&LOCK_open));
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
+
+ if (prelocked_mode == PRELOCKED)
+ {
+ /*
+ If we are here then we are leaving normal prelocked mode, so it is
+ good idea to turn off OPTION_TABLE_LOCK flag.
+ */
+ DBUG_ASSERT(thd->lex->requires_prelocking());
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ }
+
DBUG_VOID_RETURN;
}
@@ -635,14 +727,14 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
{
- DBUG_ENTER("unique_table");
- DBUG_PRINT("enter", ("table alias: %s", table->alias));
TABLE_LIST *res;
const char *d_name= table->db, *t_name= table->table_name;
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
+ DBUG_ENTER("unique_table");
+ DBUG_PRINT("enter", ("table alias: %s", table->alias));
/* temporary table is always unique */
if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
- return 0;
+ DBUG_RETURN(0);
if (table->view)
{
/* it is view and table opened */
@@ -910,7 +1002,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
!memcmp(table->s->table_cache_key, key,
key_length + TMP_TABLE_KEY_EXTRA))
{
- if (table->query_id == thd->query_id)
+ if (table->query_id == thd->query_id ||
+ thd->prelocked_mode && table->query_id)
{
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
DBUG_RETURN(0);
@@ -924,16 +1017,17 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
}
- if (thd->locked_tables)
+ if (thd->locked_tables || thd->prelocked_mode)
{ // Using table locks
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->key_length == key_length &&
- !memcmp(table->s->table_cache_key,key,key_length) &&
- !my_strcasecmp(system_charset_info, table->alias, alias))
+ !memcmp(table->s->table_cache_key, key, key_length) &&
+ !my_strcasecmp(system_charset_info, table->alias, alias) &&
+ table->query_id != thd->query_id && /* skip tables already used by this query */
+ !(thd->prelocked_mode && table->query_id))
{
- if (table->query_id != thd->query_id)
- table->query_id=thd->query_id;
+ table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
goto reset;
}
@@ -1625,21 +1719,34 @@ err:
SYNOPSIS
open_tables()
thd - thread handler
- start - list of tables
+ start - list of tables in/out
counter - number of opened tables will be return using this parameter
+ NOTE
+ Unless we are already in prelocked mode, this function will also precache
+ all SP/SFs explicitly or implicitly (via views and triggers) used by the
+ query and add tables needed for their execution to table list. If resulting
+ tables list will be non empty it will mark query as requiring precaching.
+ Prelocked mode will be enabled for such query during lock_tables() call.
+
+ If query for which we are opening tables is already marked as requiring
+ prelocking it won't do such precaching and will simply reuse table list
+ which is already built.
+
RETURN
0 - OK
-1 - error
*/
-int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
+int open_tables(THD *thd, TABLE_LIST **start, uint *counter)
{
TABLE_LIST *tables;
bool refresh;
int result=0;
- DBUG_ENTER("open_tables");
MEM_ROOT new_frm_mem;
+ /* Also used for indicating that prelocking is need */
+ TABLE_LIST **query_tables_last_own;
+ DBUG_ENTER("open_tables");
/*
temporary mem_root for new .frm parsing.
TODO: variables for size
@@ -1649,8 +1756,51 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
thd->current_tablenr= 0;
restart:
*counter= 0;
+ query_tables_last_own= 0;
thd->proc_info="Opening tables";
- for (tables= start; tables ;tables= tables->next_global)
+
+ /*
+ If we are not already executing prelocked statement and don't have
+ statement for which table list for prelocking is already built, let
+ us cache routines and try to build such table list.
+
+ NOTE: If we want queries with functions to work under explicit
+ LOCK TABLES we have to additionaly lock mysql.proc table in it.
+ At least until Monty will fix SP loading :)
+
+ NOTE: We can't delay prelocking until we will met some sub-statement
+ which really uses tables, since this will imply that we have to restore
+ its table list to be able execute it in some other context.
+ And current views implementation assumes that view tables are added to
+ global table list only once during PS preparing/first SP execution.
+ Also locking at earlier stage is probably faster altough may decrease
+ concurrency a bit.
+
+ NOTE: We will mark statement as requiring prelocking only if we will
+ have non empty table list. But this does not guarantee that in prelocked
+ mode we will have some locked tables, because queries which use only
+ derived/information schema tables and views possible. Thus "counter"
+ may be still zero for prelocked statement...
+ */
+ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+ (thd->lex->spfuns.records || thd->lex->spprocs.records))
+ {
+ TABLE_LIST **save_query_tables_last;
+
+ sp_cache_routines(thd, thd->lex);
+ save_query_tables_last= thd->lex->query_tables_last;
+
+ DBUG_ASSERT(thd->lex->query_tables == *start);
+
+ if (sp_add_sp_tables_to_table_list(thd, thd->lex, thd->lex) ||
+ *start)
+ {
+ query_tables_last_own= save_query_tables_last;
+ *start= thd->lex->query_tables;
+ }
+ }
+
+ for (tables= *start; tables ;tables= tables->next_global)
{
/*
Ignore placeholders for derived tables. After derived tables
@@ -1671,8 +1821,27 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
if (tables->view)
{
+ /* VIEW placeholder */
(*counter)--;
- continue; //VIEW placeholder
+ /*
+ Again if needed we have to get cache all routines used by this view
+ and add tables used by them to table list.
+ */
+ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+ (tables->view->spfuns.records || tables->view->spprocs.records))
+ {
+ // FIXME We should catch recursion for both views and funcs here
+ sp_cache_routines(thd, tables->view);
+
+ /* We have at least one table in TL here */
+ if (!query_tables_last_own)
+ query_tables_last_own= thd->lex->query_tables_last;
+ sp_add_sp_tables_to_table_list(thd, thd->lex, tables->view);
+ }
+ /* Cleanup hashes because destructo for this LEX is never called */
+ hash_free(&tables->view->spfuns);
+ hash_free(&tables->view->spprocs);
+ continue;
}
if (refresh) // Refresh in progress
@@ -1684,7 +1853,12 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
thd->version=refresh_version;
TABLE **prev_table= &thd->open_tables;
bool found=0;
- for (TABLE_LIST *tmp= start; tmp; tmp= tmp->next_global)
+ /*
+ QQ: What we should do if we have started building of table list
+ for prelocking ??? Probably throw it away ? But before we should
+ mark all temporary tables as free? How about locked ?
+ */
+ for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global)
{
/* Close normal (not temporary) changed tables */
if (tmp->table && ! tmp->table->s->tmp_table)
@@ -1713,7 +1887,27 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
break;
}
else
+ {
+ /*
+ If we are not already in prelocked mode and extended table list is not
+ yet built and we have trigger for table being opened then we should
+ cache all routines used by its triggers and add their tables to
+ prelocking list.
+ If we lock table for reading we won't update it so there is no need to
+ process its triggers since they never will be activated.
+
+ FIXME Now we are simply turning on prelocking. Proper integration
+ and testing is to be done later.
+ */
+ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
+ tables->table->triggers &&
+ tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ if (!query_tables_last_own)
+ query_tables_last_own= thd->lex->query_tables_last;
+ }
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+ }
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
tables->table->reginfo.lock_type=tables->lock_type;
@@ -1721,6 +1915,10 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
}
thd->proc_info=0;
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
+
+ if (query_tables_last_own)
+ thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
+
DBUG_RETURN(result);
}
@@ -1769,6 +1967,11 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
table_list Table to open is first table in this list
lock_type Lock to use for open
+ NOTE
+ This function don't do anything like SP/SF/views/triggers analysis done
+ in open_tables(). It is intended for opening of only one concrete table.
+ And used only in special contexts.
+
RETURN VALUES
table Opened table
0 Error
@@ -1843,7 +2046,7 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("simple_open_n_lock_tables");
uint counter;
- if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
+ if (open_tables(thd, &tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(-1); /* purecov: inspected */
DBUG_RETURN(0);
}
@@ -1870,7 +2073,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
uint counter;
DBUG_ENTER("open_and_lock_tables");
- if (open_tables(thd, tables, &counter) ||
+ if (open_tables(thd, &tables, &counter) ||
lock_tables(thd, tables, counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
@@ -1903,7 +2106,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
uint counter;
DBUG_ENTER("open_normal_and_derived_tables");
DBUG_ASSERT(!thd->fill_derived_tables());
- if (open_tables(thd, tables, &counter) ||
+ if (open_tables(thd, &tables, &counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd); // Not really needed, but
@@ -1937,6 +2140,27 @@ static void relink_tables_for_multidelete(THD *thd)
/*
+ Mark all real tables in the list as free for reuse.
+
+ SYNOPSIS
+ mark_real_tables_as_free_for_reuse()
+ thd - thread context
+ table - head of the list of tables
+
+ DESCRIPTION
+ Marks all real tables in the list (i.e. not views, derived
+ or schema tables) as free for reuse.
+*/
+
+static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
+{
+ for (; table; table= table->next_global)
+ if (!table->placeholder() && !table->schema_table)
+ table->table->query_id= 0;
+}
+
+
+/*
Lock all tables in list
SYNOPSIS
@@ -1950,6 +2174,10 @@ static void relink_tables_for_multidelete(THD *thd)
handling thr_lock gives us. You most always get all needed locks at
once.
+ If query for which we are calling this function marked as requring
+ prelocking, this function will do implicit LOCK TABLES and change
+ thd::prelocked_mode accordingly.
+
RETURN VALUES
0 ok
-1 Error
@@ -1958,36 +2186,125 @@ static void relink_tables_for_multidelete(THD *thd)
int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
{
TABLE_LIST *table;
+
+ DBUG_ENTER("lock_tables");
+ /*
+ We can't meet statement requiring prelocking if we already
+ in prelocked mode.
+ */
+ DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
+ /*
+ If statement requires prelocking then it has non-empty table list.
+ So it is safe to shortcut.
+ */
+ DBUG_ASSERT(!thd->lex->requires_prelocking() || tables);
+
if (!tables)
- return 0;
+ DBUG_RETURN(0);
- if (!thd->locked_tables)
+ /*
+ We need this extra check for thd->prelocked_mode because we want to avoid
+ attempts to lock tables in substatements. Checking for thd->locked_tables
+ is not enough in some situations. For example for SP containing
+ "drop table t3; create temporary t3 ..; insert into t3 ...;"
+ thd->locked_tables may be 0 after drop tables, and without this extra
+ check insert will try to lock temporary table t3, that will lead
+ to memory leak...
+ */
+ if (!thd->locked_tables && !thd->prelocked_mode)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
+
if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
- return -1;
+ DBUG_RETURN(-1);
for (table= tables; table; table= table->next_global)
{
if (!table->placeholder() && !table->schema_table)
*(ptr++)= table->table;
}
+
+ /* We have to emulate LOCK TABLES if we are statement needs prelocking. */
+ if (thd->lex->requires_prelocking())
+ {
+ thd->in_lock_tables=1;
+ thd->options|= OPTION_TABLE_LOCK;
+ }
+
if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
- return -1; /* purecov: inspected */
+ {
+ if (thd->lex->requires_prelocking())
+ {
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ thd->in_lock_tables=0;
+ }
+ DBUG_RETURN(-1);
+ }
+ if (thd->lex->requires_prelocking() &&
+ thd->lex->sql_command != SQLCOM_LOCK_TABLES)
+ {
+ TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+ /*
+ We just have done implicit LOCK TABLES, and now we have
+ to emulate first open_and_lock_tables() after it.
+
+ Note that "LOCK TABLES" can also be marked as requiring prelocking
+ (e.g. if one locks view which uses functions). We should not emulate
+ such open_and_lock_tables() in this case. We also should not set
+ THD::prelocked_mode or first close_thread_tables() call will do
+ "UNLOCK TABLES".
+ */
+ thd->locked_tables= thd->lock;
+ thd->lock= 0;
+ thd->in_lock_tables=0;
+
+ for (table= tables; table != first_not_own; table= table->next_global)
+ {
+ if (!table->placeholder() && !table->schema_table)
+ {
+ table->table->query_id= thd->query_id;
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ {
+ ha_rollback_stmt(thd);
+ mysql_unlock_tables(thd, thd->locked_tables);
+ thd->locked_tables= 0;
+ thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ /*
+ Let us mark all tables which don't belong to the statement itself,
+ and was marked as occupied during open_tables() as free for reuse.
+ */
+ mark_real_tables_as_free_for_reuse(first_not_own);
+ thd->prelocked_mode= PRELOCKED;
+ }
}
else
{
- for (table= tables; table; table= table->next_global)
+ TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+ for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() &&
+ if (!table->placeholder() && !table->schema_table &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
- return -1;
+ DBUG_RETURN(-1);
}
}
+ /*
+ If we are under explicit LOCK TABLES and our statement requires
+ prelocking, we should mark all "additional" tables as free for use
+ and enter prelocked mode.
+ */
+ if (thd->lex->requires_prelocking())
+ {
+ mark_real_tables_as_free_for_reuse(first_not_own);
+ thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES;
+ }
}
- return 0;
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index eb98b96c9ec..bac3e42ed62 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -183,6 +183,7 @@ THD::THD()
lock=locked_tables=0;
used_tables=0;
cuted_fields= sent_row_count= 0L;
+ limit_found_rows= 0;
statement_id_counter= 0UL;
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
@@ -250,8 +251,9 @@ THD::THD()
protocol_prep.init(this);
tablespace_op=FALSE;
- ulong tmp=sql_rnd_with_mutex();
- randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ ulong tmp=sql_rnd_with_mutex();
+ randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ prelocked_mode= NON_PRELOCKED;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2cd525f54bc..fa2bcc4d478 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -45,7 +45,7 @@ extern const char **errmesg;
#define TC_LOG_PAGE_SIZE 8192
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
-extern uint opt_tc_log_size;
+extern ulong opt_tc_log_size;
extern ulong tc_log_max_pages_used;
extern ulong tc_log_page_size;
extern ulong tc_log_page_waits;
@@ -926,6 +926,15 @@ typedef I_List<Item_change_record> Item_change_list;
/*
+ Type of prelocked mode.
+ See comment for THD::prelocked_mode for complete description.
+*/
+
+enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
+ PRELOCKED_UNDER_LOCK_TABLES= 2};
+
+
+/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
@@ -1025,7 +1034,13 @@ public:
See also lock_tables() for details.
*/
MYSQL_LOCK *lock; /* Current locks */
- MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */
+ /*
+ Tables that were locked with explicit or implicit LOCK TABLES.
+ (Implicit LOCK TABLES happens when we are prelocking tables for
+ execution of statement which uses stored routines. See description
+ THD::prelocked_mode for more info.)
+ */
+ MYSQL_LOCK *locked_tables;
HASH handler_tables_hash;
/*
One thread can hold up to one named user-level lock. This variable
@@ -1061,9 +1076,9 @@ public:
SAVEPOINT *savepoints;
THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement
- bool on;
- XID xid;
- enum xa_states xa_state;
+ bool on; // see ha_enable_transaction()
+ XID xid; // transaction identifier
+ enum xa_states xa_state; // used by external XA only
/*
Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query
@@ -1192,8 +1207,6 @@ public:
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
- bool shortcut_make_view; /* Don't do full mysql_make_view()
- during pre-opening of tables. */
/*
If we do a purge of binary logs, log index info of the threads
@@ -1209,6 +1222,31 @@ public:
long long_value;
} sys_var_tmp;
+ /*
+ prelocked_mode_type enum and prelocked_mode member are used for
+ indicating whenever "prelocked mode" is on, and what type of
+ "prelocked mode" is it.
+
+ Prelocked mode is used for execution of queries which explicitly
+ or implicitly (via views or triggers) use functions, thus may need
+ some additional tables (mentioned in query table list) for their
+ execution.
+
+ First open_tables() call for such query will analyse all functions
+ used by it and add all additional tables to table its list. It will
+ also mark this query as requiring prelocking. After that lock_tables()
+ will issue implicit LOCK TABLES for the whole table list and change
+ thd::prelocked_mode to non-0. All queries called in functions invoked
+ by the main query will use prelocked tables. Non-0 prelocked_mode
+ will also surpress mentioned analysys in those queries thus saving
+ cycles. Prelocked mode will be turned off once close_thread_tables()
+ for the main query will be called.
+
+ Note: Since not all "tables" present in table list are really locked
+ thd::relocked_mode does not imply thd::locked_tables.
+ */
+ prelocked_mode_type prelocked_mode;
+
THD();
~THD();
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index dd2ac3c013b..bb48b7ada77 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -187,7 +187,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
/* for now HANDLER can be used only for real TABLES */
tables->required_type= FRMTYPE_TABLE;
- error= open_tables(thd, tables, &counter);
+ error= open_tables(thd, &tables, &counter);
HANDLER_TABLES_HACK(thd);
if (error)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 79996ffb65c..91c4dc40c01 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -169,13 +169,12 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->sphead= NULL;
lex->spcont= NULL;
lex->proc_list.first= 0;
+ lex->query_tables_own_last= 0;
if (lex->spfuns.records)
my_hash_reset(&lex->spfuns);
if (lex->spprocs.records)
my_hash_reset(&lex->spprocs);
- if (lex->sptabs.records)
- my_hash_reset(&lex->sptabs);
DBUG_VOID_RETURN;
}
@@ -1837,8 +1836,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
select_limit_cnt= values->select_limit+values->offset_limit;
if (select_limit_cnt < values->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR)
- sl->options&= ~OPTION_FOUND_ROWS;
}
@@ -1870,6 +1867,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
*/
if ((query_tables= query_tables->next_global))
query_tables->prev_global= &query_tables;
+ else
+ query_tables_last= &query_tables;
first->next_global= 0;
/*
@@ -1975,6 +1974,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
{
if ((first->next_global= query_tables))
query_tables->prev_global= &first->next_global;
+ else
+ query_tables_last= &first->next_global;
query_tables= first;
if (link_to_local)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a0145dcaccf..3588f376d2f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -784,7 +784,6 @@ typedef struct st_lex
sp_pcontext *spcont;
HASH spfuns; /* Called functions */
HASH spprocs; /* Called procedures */
- HASH sptabs; /* Merged table lists */
st_sp_chistics sp_chistics;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
@@ -803,23 +802,25 @@ typedef struct st_lex
*/
SQL_LIST trg_table_fields;
- st_lex() :result(0), sql_command(SQLCOM_END)
+ /*
+ If non-0 then indicates that query requires prelocking and points to
+ next_global member of last own element in query table list (i.e. last
+ table which was not added to it as part of preparation to prelocking).
+ 0 - indicates that this query does not need prelocking.
+ */
+ TABLE_LIST **query_tables_own_last;
+
+ st_lex() :result(0), sql_command(SQLCOM_END), query_tables_own_last(0)
{
extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
- extern byte *sp_table_key(const byte *ptr, uint *plen, my_bool first);
hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
- hash_init(&sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
}
-
- ~st_lex()
+
+ virtual ~st_lex()
{
- if (spfuns.array.buffer)
- hash_free(&spfuns);
- if (spprocs.array.buffer)
- hash_free(&spprocs);
- if (sptabs.array.buffer)
- hash_free(&sptabs);
+ hash_free(&spfuns);
+ hash_free(&spprocs);
}
inline void uncacheable(uint8 cause)
@@ -856,6 +857,21 @@ typedef struct st_lex
bool can_not_use_merged();
bool only_view_structure();
bool need_correct_ident();
+
+ inline bool requires_prelocking()
+ {
+ return query_tables_own_last;
+ }
+ inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last)
+ {
+ query_tables_own_last= tables_own_last;
+ }
+ /* Return pointer to first not-own table in query-tables or 0 */
+ TABLE_LIST* first_not_own_table()
+ {
+ return ( query_tables_own_last ? *query_tables_own_last : 0);
+ }
+
} LEX;
struct st_lex_local: public st_lex
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2f38f96c976..f328d31161a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1453,105 +1453,6 @@ bool do_command(THD *thd)
}
#endif /* EMBEDDED_LIBRARY */
-static void release_local_lock(THD *thd, TABLE_LIST *locked_tables,
- bool old_innodb_table_locks)
-{
- if (locked_tables)
- {
-#ifdef HAVE_INNOBASE_DB
- thd->variables.innodb_table_locks= old_innodb_table_locks;
-#endif
- if (thd->locked_tables)
- sp_unlock_tables(thd);
- }
-
-}
-
-static bool process_nested_sp(THD *thd, LEX *lex, TABLE_LIST** locked_tables)
-{
- DBUG_ENTER("process_nested_sp");
- while (1)
- {
- if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
- DBUG_RETURN(TRUE);
- if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
- DBUG_RETURN(TRUE);
- if (!thd->locked_tables &&
- lex->sql_command != SQLCOM_CREATE_TABLE &&
- lex->sql_command != SQLCOM_CREATE_VIEW)
- {
- MEM_ROOT *thdmemroot= NULL;
-
- sp_merge_routine_tables(thd, lex);
- // QQ Preopen tables to find views and triggers.
- // This means we open, close and open again, which sucks, but
- // right now it's the easiest way to get it to work. A better
- // solution will hopefully be found soon...
- if (lex->sptabs.records || lex->query_tables)
- {
- uint procs, funs, tabs;
-
- if (thd->mem_root != thd->current_arena->mem_root)
- {
- thdmemroot= thd->mem_root;
- thd->mem_root= thd->current_arena->mem_root;
- }
- if (!sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
- DBUG_RETURN(TRUE);
- procs= lex->spprocs.records;
- funs= lex->spfuns.records;
- tabs= lex->sptabs.records;
-
- if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
- {
- // We don't want these updated now
- uint ctmpdtabs= thd->status_var.created_tmp_disk_tables;
- uint ctmptabs= thd->status_var.created_tmp_tables;
- uint count;
-
- thd->shortcut_make_view= TRUE;
- open_tables(thd, *locked_tables, &count);
- thd->shortcut_make_view= FALSE;
- close_thread_tables(thd);
- thd->status_var.created_tmp_disk_tables= ctmpdtabs;
- thd->status_var.created_tmp_tables= ctmptabs;
- thd->clear_error();
- mysql_reset_errors(thd);
- (*locked_tables)= NULL;
- }
- // A kludge: Decrease all temp. table's query ids to allow a
- // second opening.
- for (TABLE *table= thd->temporary_tables; table ; table=table->next)
- table->query_id-= 1;
- if (procs < lex->spprocs.records ||
- funs < lex->spfuns.records ||
- tabs < lex->sptabs.records)
- {
- if (thdmemroot)
- thd->mem_root= thdmemroot;
- continue; // Found more SPs or tabs, try again
- }
- }
- if (lex->sptabs.records &&
- (lex->spfuns.records || lex->spprocs.records) &&
- sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
- {
- if (((*locked_tables)= sp_hash_to_table_list(thd, &lex->sptabs)))
- {
-#ifdef HAVE_INNOBASE_DB
- thd->variables.innodb_table_locks= FALSE;
-#endif
- sp_open_and_lock_tables(thd, *locked_tables);
- }
- }
- if (thdmemroot)
- thd->mem_root= thdmemroot;
- }
- break;
- } // while (1)
- DBUG_RETURN(FALSE);
-}
-
/*
Perform one connection-level (COM_XXXX) command.
@@ -1752,7 +1653,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
in embedded server - just store them to be executed later
*/
#ifndef EMBEDDED_LIBRARY
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
close_thread_tables(thd);
#endif
ulong length= (ulong)(packet_end-packet);
@@ -1855,19 +1757,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
select_lex.table_list.link_in_list((byte*) &table_list,
(byte**) &table_list.next_local);
thd->lex->query_tables= &table_list;
- thd->shortcut_make_view= 0;
- process_nested_sp(thd, thd->lex, &locked_tables);
/* switch on VIEW optimisation: do not fill temporary tables */
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
mysqld_list_fields(thd,&table_list,fields);
thd->lex->unit.cleanup();
thd->cleanup_after_query();
-#ifdef HAVE_INNOBASE_DB
- release_local_lock(thd, locked_tables, old_innodb_table_locks);
-#else
- release_local_lock(thd, locked_tables, false);
-#endif
break;
}
#endif
@@ -2089,7 +1984,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables ||
+ thd->prelocked_mode)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
@@ -2334,11 +2230,7 @@ mysql_execute_command(THD *thd)
TABLE_LIST *all_tables;
/* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
- /* Locked closure of all tables */
- TABLE_LIST *locked_tables= NULL;
/* Saved variable value */
- my_bool old_innodb_table_locks=
- IF_INNOBASE_DB(thd->variables.innodb_table_locks, FALSE);
DBUG_ENTER("mysql_execute_command");
thd->net.no_send_error= 0;
@@ -2361,26 +2253,14 @@ mysql_execute_command(THD *thd)
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
- thd->shortcut_make_view= 0;
- if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
- lex->sql_command != SQLCOM_CREATE_SPFUNCTION &&
- lex->sql_command != SQLCOM_LOCK_TABLES &&
- lex->sql_command != SQLCOM_UNLOCK_TABLES)
- {
- thd->no_warnings_for_error= 1;
- res= process_nested_sp(thd, lex, &locked_tables);
- thd->no_warnings_for_error= 0;
- if (res)
- DBUG_RETURN(TRUE);
- }
-
/*
Reset warning count for each query that uses tables
A better approach would be to reset this for any commands
that is not a SHOW command or a select that only access local
variables, but for now this is probably good enough.
*/
- if (all_tables || &lex->select_lex != lex->all_selects_list)
+ if (all_tables || &lex->select_lex != lex->all_selects_list ||
+ lex->spfuns.records || lex->spprocs.records)
mysql_reset_errors(thd);
#ifdef HAVE_REPLICATION
@@ -2614,9 +2494,8 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_DO:
- if (all_tables &&
- (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
- open_and_lock_tables(thd, all_tables)))
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
goto error;
res= mysql_do(thd, *lex->insert_list);
@@ -3485,8 +3364,7 @@ unsent_create_error:
case SQLCOM_SET_OPTION:
{
List<set_var_base> *lex_var_list= &lex->var_list;
- if (all_tables &&
- (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
open_and_lock_tables(thd, all_tables)))
goto error;
if (lex->one_shot_set && not_all_support_one_shot(lex_var_list))
@@ -3532,7 +3410,7 @@ unsent_create_error:
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
- if (!(res= open_and_lock_tables(thd, all_tables)))
+ if (!(res= simple_open_n_lock_tables(thd, all_tables)))
{
#ifdef HAVE_QUERY_CACHE
if (thd->variables.query_cache_wlock_invalidate)
@@ -4115,7 +3993,20 @@ unsent_create_error:
{
sp_head *sp;
- if (!(sp= sp_find_procedure(thd, lex->spname)))
+ /*
+ This will cache all SP and SF and open and lock all tables
+ required for execution.
+ */
+ if (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
+ open_and_lock_tables(thd, all_tables))
+ goto error;
+
+ /*
+ By this moment all needed SPs should be in cache so no need
+ to look into DB. Moreover we may be unable to do it becuase
+ we may don't have read lock on mysql.proc
+ */
+ if (!(sp= sp_find_procedure(thd, lex->spname, TRUE)))
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE",
lex->spname->m_qname.str);
@@ -4130,12 +4021,6 @@ unsent_create_error:
/* bits that should be cleared in thd->server_status */
uint bits_to_be_cleared= 0;
- /* In case the arguments are subselects... */
- if (all_tables &&
- (check_table_access(thd, SELECT_ACL, all_tables, 0) ||
- open_and_lock_tables(thd, all_tables)))
- goto error;
-
#ifndef EMBEDDED_LIBRARY
my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE;
@@ -4606,11 +4491,6 @@ cleanup:
if (thd->lock == thd->locked_tables)
thd->lock= 0;
}
-#ifdef HAVE_INNOBASE_DB
- release_local_lock(thd, locked_tables, old_innodb_table_locks);
-#else
- release_local_lock(thd, locked_tables, false);
-#endif
DBUG_RETURN(res || thd->net.report_error);
}
@@ -4865,6 +4745,38 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
return FALSE;
}
+
+/*
+ Check if the routine has any of the routine privileges
+
+ SYNOPSIS
+ check_some_routine_access()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool check_some_routine_access(THD *thd, char *db, char *name)
+{
+ ulong save_priv;
+ if (thd->master_access & SHOW_PROC_ACLS)
+ return FALSE;
+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
+ (save_priv & SHOW_PROC_ACLS))
+ return FALSE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option)
+ return check_routine_level_acl(thd, db, name);
+#endif
+
+ return FALSE;
+}
+
+
/*
Check if the given table has any of the asked privileges
@@ -5203,8 +5115,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
{
if (thd->lex->sphead)
{
- if (lex != thd->lex)
- thd->lex->sphead->restore_lex(thd);
delete thd->lex->sphead;
thd->lex->sphead= NULL;
}
@@ -5240,8 +5150,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
if (thd->lex->sphead)
{
/* Clean up after failed stored procedure/function */
- if (lex != thd->lex)
- thd->lex->sphead->restore_lex(thd);
delete thd->lex->sphead;
thd->lex->sphead= NULL;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7da5c13e18a..8006c61f233 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1004,7 +1004,7 @@ static int mysql_test_update(Prepared_statement *stmt,
if (update_precheck(thd, table_list))
DBUG_RETURN(1);
- if (!open_tables(thd, table_list, &table_count))
+ if (!open_tables(thd, &table_list, &table_count))
{
if (table_list->ancestor && table_list->ancestor->next_local)
{
@@ -1545,22 +1545,6 @@ static int check_prepared_statement(Prepared_statement *stmt,
lex->first_lists_tables_same();
tables= lex->query_tables;
- /*
- Preopen 'proc' system table and cache all functions used in this
- statement. We must do that before we open ordinary tables to avoid
- deadlocks. We can't open and lock any table once query tables were
- opened.
- */
- if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
- lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
- {
- /* The error is printed inside */
- if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
- DBUG_RETURN(-1);
- if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
- DBUG_RETURN(-1);
- }
-
switch (sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
@@ -1787,15 +1771,13 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
if (error && thd->lex->sphead)
{
- if (lex != thd->lex)
- thd->lex->sphead->restore_lex(thd);
delete thd->lex->sphead;
thd->lex->sphead= NULL;
}
lex_end(lex);
+ close_thread_tables(thd);
thd->restore_backup_statement(stmt, &thd->stmt_backup);
cleanup_items(stmt->free_list);
- close_thread_tables(thd);
thd->rollback_item_tree_changes();
thd->cleanup_after_query();
thd->current_arena= thd;
@@ -1809,20 +1791,33 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
else
{
stmt->setup_set_params();
- SELECT_LEX *sl= stmt->lex->all_selects_list;
- /*
- Save WHERE clause pointers, because they may be changed during query
- optimisation.
- */
- for (; sl; sl= sl->next_select_in_list())
- sl->prep_where= sl->where;
+ init_stmt_after_parse(thd, stmt->lex);
stmt->state= Item_arena::PREPARED;
}
DBUG_RETURN(!stmt);
}
-/* Reinit statement before execution */
+/*
+ Init PS/SP specific parse tree members.
+*/
+
+void init_stmt_after_parse(THD *thd, LEX *lex)
+{
+ SELECT_LEX *sl= lex->all_selects_list;
+ /*
+ Save WHERE clause pointers, because they may be changed during query
+ optimisation.
+ */
+ for (; sl; sl= sl->next_select_in_list())
+ sl->prep_where= sl->where;
+
+ for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
+ table->prep_on_expr= table->on_expr;
+}
+
+
+/* Reinit prepared statement/stored procedure before execution */
void reset_stmt_for_execute(THD *thd, LEX *lex)
{
@@ -1872,6 +1867,11 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
+ /*
+ NOTE: We should reset whole table list here including all tables added
+ by prelocking algorithm (it is not a problem for substatements since
+ they have their own table list).
+ */
for (TABLE_LIST *tables= lex->query_tables;
tables;
tables= tables->next_global)
@@ -1883,6 +1883,12 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
tables->table= 0;
if (tables->nested_join)
tables->nested_join->counter= 0;
+
+ if (tables->prep_on_expr)
+ {
+ tables->on_expr= tables->prep_on_expr->copy_andor_structure(thd);
+ tables->on_expr->cleanup();
+ }
}
lex->current_select= &lex->select_lex;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 95417c9face..fb583448535 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1271,7 +1271,7 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
bool mysql_show_binlog_events(THD* thd)
{
Protocol *protocol= thd->protocol;
- DBUG_ENTER("show_binlog_events");
+ DBUG_ENTER("mysql_show_binlog_events");
List<Item> field_list;
const char *errmsg = 0;
bool ret = TRUE;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7521de854d9..76d8ec1740a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -664,7 +664,7 @@ JOIN::optimize()
!(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */
my_message(ER_TOO_BIG_SELECT, ER(ER_TOO_BIG_SELECT), MYF(0));
- error= 1; /* purecov: inspected */
+ error= -1;
DBUG_RETURN(1);
}
if (const_tables && !thd->locked_tables &&
@@ -1194,7 +1194,9 @@ JOIN::exec()
else
error=(int) result->send_eof();
}
- thd->limit_found_rows= thd->examined_row_count= 0;
+ /* Single select (without union and limit) always returns 1 row */
+ thd->limit_found_rows= 1;
+ thd->examined_row_count= 0;
DBUG_VOID_RETURN;
}
thd->limit_found_rows= thd->examined_row_count= 0;
@@ -6190,9 +6192,9 @@ finish:
For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)])
and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]).
For b=2 it will be called with *cond_equal=(ptr(CE),[])
- and will transform *cond_equal into (ptr(CE,[Item_equal(2,a,b,c)]).
+ and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]).
For f=e it will be called with *cond_equal=(ptr(CE), [])
- and will transform *cond_equal into (ptr(CE,[Item_equal(f,e)]).
+ and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]).
NOTES
Now only fields that have the same type defintions (verified by
@@ -6461,6 +6463,11 @@ static COND *build_equal_items_for_cond(COND *cond,
*/
while ((item= li++))
{
+ /*
+ PS/SP note: we can safely remove a node from AND-OR
+ structure here because it's restored before each
+ re-execution of any prepared statement/stored procedure.
+ */
if (check_equality(item, &cond_equal))
li.remove();
}
@@ -6499,6 +6506,11 @@ static COND *build_equal_items_for_cond(COND *cond,
if ((new_item = build_equal_items_for_cond(item, inherited))!= item)
{
/* This replacement happens only for standalone equalities */
+ /*
+ This is ok with PS/SP as the replacement is done for
+ arguments of an AND/OR item, which are restored for each
+ execution of PS/SP.
+ */
li.replace(new_item);
}
}
@@ -6634,10 +6646,12 @@ static COND *build_equal_items(THD *thd, COND *cond,
Item *expr;
List<TABLE_LIST> *join_list= table->nested_join ?
&table->nested_join->join_list : NULL;
- expr= build_equal_items(thd, table->on_expr, inherited, join_list,
- &table->cond_equal);
- if (expr != table->on_expr)
- thd->change_item_tree(&table->on_expr, expr);
+ /*
+ We can modify table->on_expr because its old value will
+ be restored before re-execution of PS/SP.
+ */
+ table->on_expr= build_equal_items(thd, table->on_expr, inherited,
+ join_list, &table->cond_equal);
}
}
}
@@ -6864,10 +6878,14 @@ static COND* substitute_for_best_equal_field(COND *cond,
while ((item= li++))
{
Item *new_item =substitute_for_best_equal_field(item, cond_equal,
- table_join_idx);
+ table_join_idx);
+ /*
+ This works OK with PS/SP re-execution as changes are made to
+ the arguments of AND/OR items only
+ */
if (new_item != item)
li.replace(new_item);
- }
+ }
if (and_level)
{
@@ -7196,7 +7214,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
*/
expr= simplify_joins(join, &nested_join->join_list,
table->on_expr, FALSE);
- table->on_expr= expr;
+ table->prep_on_expr= table->on_expr= expr;
}
nested_join->used_tables= (table_map) 0;
nested_join->not_null_tables=(table_map) 0;
@@ -7236,7 +7254,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
else
conds= table->on_expr;
- table->on_expr= 0;
+ table->prep_on_expr= table->on_expr= 0;
}
}
@@ -7317,10 +7335,7 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
DBUG_ENTER("optimize_cond");
if (!conds)
- {
*cond_value= Item::COND_TRUE;
- select->prep_where= 0;
- }
else
{
/*
@@ -7591,10 +7606,10 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
new_created field
*/
-static Field* create_tmp_field_from_field(THD *thd, Field* org_field,
- Item *item, TABLE *table,
- bool modify_item,
- uint convert_blob_length)
+Field* create_tmp_field_from_field(THD *thd, Field* org_field,
+ Item *item, TABLE *table,
+ bool modify_item,
+ uint convert_blob_length)
{
Field *new_field;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 0f26207b391..1b7893dbc7c 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -399,6 +399,10 @@ void copy_funcs(Item **func_ptr);
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int error, bool ignore_last_dupp_error);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
+Field* create_tmp_field_from_field(THD *thd, Field* org_field,
+ Item *item, TABLE *table,
+ bool modify_item,
+ uint convert_blob_length);
/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1339b5e5ed0..4ffe7110cfa 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1649,6 +1649,10 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
strlen(item_field->field_name), 0)))
return 0;
}
+ if (item->type() == Item::SUBSELECT_ITEM &&
+ !item->const_item())
+ return 0;
+
return 1;
}
@@ -2464,32 +2468,41 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
}
-void store_schema_proc(THD *thd, TABLE *table,
- TABLE *proc_table,
- const char *wild)
+void store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
+ const char *wild, bool full_access, const char *sp_user)
{
String tmp_string;
TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
- restore_record(table, s->default_values);
+ const char *sp_db, *sp_name, *definer;
+ sp_db= get_field(thd->mem_root, proc_table->field[0]);
+ sp_name= get_field(thd->mem_root, proc_table->field[1]);
+ definer= get_field(thd->mem_root, proc_table->field[11]);
+ if (!full_access)
+ full_access= !strcmp(sp_user, definer);
+ if (!full_access)
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_some_routine_access(thd, (char * )sp_db, (char * )sp_name))
+ return;
+#endif
+ }
+
if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
lex->orig_sql_command == SQLCOM_SHOW_STATUS_FUNC &&
proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION ||
lex->orig_sql_command == SQLCOM_END)
{
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[1], &tmp_string);
- if (!wild || !wild[0] || !wild_compare(tmp_string.ptr(), wild, 0))
+ restore_record(table, s->default_values);
+ if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
{
- table->field[3]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[3]->store(sp_name, strlen(sp_name), cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[3], &tmp_string);
table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[0], &tmp_string);
- table->field[2]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[2]->store(sp_db, strlen(sp_db), cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[2], &tmp_string);
table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
@@ -2500,10 +2513,13 @@ void store_schema_proc(THD *thd, TABLE *table,
table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[5]->set_notnull();
}
+ if (full_access)
+ {
+ tmp_string.length(0);
+ get_field(thd->mem_root, proc_table->field[10], &tmp_string);
+ table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ }
table->field[6]->store("SQL", 3, cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[10], &tmp_string);
- table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[10]->store("SQL", 3, cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[6], &tmp_string);
@@ -2527,9 +2543,7 @@ void store_schema_proc(THD *thd, TABLE *table,
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[15], &tmp_string);
table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[11], &tmp_string);
- table->field[19]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[19]->store(definer, strlen(definer), cs);
table->file->write_row(table->record[0]);
}
}
@@ -2543,14 +2557,18 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
int res= 0;
TABLE *table= tables->table, *old_open_tables= thd->open_tables;
+ bool full_access;
+ char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
DBUG_ENTER("fill_schema_proc");
+ strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
bzero((char*) &proc_tables,sizeof(proc_tables));
proc_tables.db= (char*) "mysql";
proc_tables.db_length= 5;
proc_tables.table_name= proc_tables.alias= (char*) "proc";
proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
+ full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
{
DBUG_RETURN(1);
@@ -2561,9 +2579,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
goto err;
}
- store_schema_proc(thd, table, proc_table, wild);
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer);
while (!proc_table->file->index_next(proc_table->record[0]))
- store_schema_proc(thd, table, proc_table, wild);
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer);
err:
proc_table->file->ha_index_end();
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index f61ff12f365..110841e8fd4 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -415,9 +415,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
*/
if (lex.sphead)
{
- if (&lex != thd->lex)
- thd->lex->sphead->restore_lex(thd);
delete lex.sphead;
+ lex.sphead= 0;
}
goto err_with_lex_cleanup;
}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 82e7c1ce023..7dd6734eb89 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -42,14 +42,21 @@ public:
if (bodies[event][time_type])
{
- /*
- Similar to function invocation we don't need to surpress sending of
- ok packets here because don't allow execute statements from trigger.
+#ifndef EMBEDDED_LIBRARY
+ /* Surpress OK packets in case if we will execute statements */
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+ /*
FIXME: We should juggle with security context here (because trigger
should be invoked with creator rights).
*/
res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
}
return res;
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index ec47fb055e2..1d14d037c47 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -17,15 +17,15 @@
/* This implements 'user defined functions' */
/*
-** Known bugs:
-**
-** Memory for functions are never freed!
-** Shared libraries are not closed before mysqld exists;
-** - This is because we can't be sure if some threads is using
-** a functions.
-**
-** The buggs only affects applications that creates and frees a lot of
-** dynamic functions, so this shouldn't be a real problem.
+ Known bugs:
+
+ Memory for functions is never freed!
+ Shared libraries are not closed before mysqld exits;
+ - This is because we can't be sure if some threads are using
+ a function.
+
+ The bugs only affect applications that create and free a lot of
+ dynamic functions, so this shouldn't be a real problem.
*/
#ifdef __GNUC__
@@ -74,32 +74,49 @@ static HASH udf_hash;
static rw_lock_t THR_LOCK_udf;
-static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
- Item_udftype typ);
+static udf_func *add_udf(LEX_STRING *name, Item_result ret,
+ char *dl, Item_udftype typ);
static void del_udf(udf_func *udf);
static void *find_udf_dl(const char *dl);
-
-static void init_syms(udf_func *tmp)
+static char *init_syms(udf_func *tmp, char *nm)
{
- char nm[MAX_FIELD_NAME+16],*end;
+ char *end;
+
+ if (!((tmp->func= dlsym(tmp->dlhandle, tmp->name.str))))
+ return tmp->name.str;
- tmp->func = dlsym(tmp->dlhandle, tmp->name.str);
end=strmov(nm,tmp->name.str);
- (void) strmov(end,"_init");
- tmp->func_init = dlsym(tmp->dlhandle, nm);
- (void) strmov(end,"_deinit");
- tmp->func_deinit = dlsym(tmp->dlhandle, nm);
+
if (tmp->type == UDFTYPE_AGGREGATE)
{
- (void)strmov( end, "_clear" );
- tmp->func_clear = dlsym( tmp->dlhandle, nm );
- (void)strmov( end, "_add" );
- tmp->func_add = dlsym( tmp->dlhandle, nm );
- /* Give error if _clear and _add doesn't exists */
- if (!tmp->func_clear || ! tmp->func_add)
- tmp->func= 0;
+ (void)strmov(end, "_clear");
+ if (!((tmp->func_clear= dlsym(tmp->dlhandle, nm))))
+ return nm;
+ (void)strmov(end, "_add");
+ if (!((tmp->func_add= dlsym(tmp->dlhandle, nm))))
+ return nm;
+ }
+
+ (void) strmov(end,"_deinit");
+ tmp->func_deinit= dlsym(tmp->dlhandle, nm);
+
+ (void) strmov(end,"_init");
+ tmp->func_init= dlsym(tmp->dlhandle, nm);
+
+ /*
+ to prefent loading "udf" from, e.g. libc.so
+ let's ensure that at least one auxiliary symbol is defined
+ */
+ if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
+ {
+ if (opt_allow_suspicious_udfs)
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
+ else
+ return nm;
}
+
+ return 0;
}
extern "C" byte* get_hash_key(const byte *buff,uint *length,
@@ -111,7 +128,7 @@ extern "C" byte* get_hash_key(const byte *buff,uint *length,
}
/*
-** Read all predeclared functions from func@mysql and accept all that
+** Read all predeclared functions from mysql.func and accept all that
** can be used.
*/
@@ -153,7 +170,7 @@ void udf_init()
if (simple_open_n_lock_tables(new_thd, &tables))
{
DBUG_PRINT("error",("Can't open udf table"));
- sql_print_error("Can't open the mysql/func table. Please run the mysql_install_db script to create it.");
+ sql_print_error("Can't open the mysql.func table. Please run the mysql_install_db script to create it.");
goto end;
}
@@ -171,10 +188,23 @@ void udf_init()
if (table->s->fields >= 4) // New func table
udftype=(Item_udftype) table->field[3]->val_int();
- if (!(tmp = add_udf(&name,(Item_result) table->field[1]->val_int(),
- dl_name, udftype)))
+ /*
+ Ensure that the .dll doesn't have a path
+ This is done to ensure that only approved dll from the system
+ directories are used (to make this even remotely secure).
+ */
+ if (strchr(dl_name, '/') || name.length > NAME_LEN)
+ {
+ sql_print_error("Invalid row in mysql.func table for function '%.64s'",
+ name.str);
+ continue;
+ }
+
+
+ if (!(tmp= add_udf(&name,(Item_result) table->field[1]->val_int(),
+ dl_name, udftype)))
{
- sql_print_error("Can't alloc memory for udf function: name");
+ sql_print_error("Can't alloc memory for udf function: '%.64s'", name.str);
continue;
}
@@ -191,13 +221,15 @@ void udf_init()
new_dl=1;
}
tmp->dlhandle = dl;
- init_syms(tmp);
- if (!tmp->func)
{
- sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name);
- del_udf(tmp);
- if (new_dl)
- dlclose(dl);
+ char buf[MAX_FIELD_NAME+16], *missing;
+ if ((missing= init_syms(tmp, buf)))
+ {
+ sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
+ del_udf(tmp);
+ if (new_dl)
+ dlclose(dl);
+ }
}
}
if (error > 0)
@@ -239,7 +271,7 @@ void udf_free()
{
initialized= 0;
rwlock_destroy(&THR_LOCK_udf);
- }
+ }
DBUG_VOID_RETURN;
}
@@ -407,12 +439,13 @@ int mysql_create_function(THD *thd,udf_func *udf)
new_dl=1;
}
udf->dlhandle=dl;
- init_syms(udf);
-
- if (udf->func == NULL)
{
- my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), udf->name);
- goto err;
+ char buf[MAX_FIELD_NAME+16], *missing;
+ if ((missing= init_syms(udf, buf)))
+ {
+ my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
+ goto err;
+ }
}
udf->name.str=strdup_root(&mem,udf->name.str);
udf->dl=strdup_root(&mem,udf->dl);
@@ -425,7 +458,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
u_d->func_clear=udf->func_clear;
u_d->func_add=udf->func_add;
- /* create entry in mysql/func table */
+ /* create entry in mysql.func table */
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
@@ -445,7 +478,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
close_thread_tables(thd);
if (error)
{
- my_error(ER_ERROR_ON_WRITE, MYF(0), "func@mysql", error);
+ my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
del_udf(u_d);
goto err;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 455c83e1718..13c7f0a40b7 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -217,8 +217,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= sl;
set_limit(sl, sl);
- if (sl->braces)
- sl->options&= ~OPTION_FOUND_ROWS;
can_skip_order_by= is_union &&
(!sl->braces || select_limit_cnt == HA_POS_ERROR);
@@ -342,10 +340,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (arena->is_stmt_prepare())
{
/* prepare fake select to initialize it correctly */
- ulong options_tmp= init_prepare_fake_select_lex(thd);
+ (void) init_prepare_fake_select_lex(thd);
/*
- it should be done only once (because item_list builds only onece
- per statement)
+ Should be done only once (the only item_list per statement).
*/
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
@@ -452,21 +449,14 @@ bool st_select_lex_unit::exec()
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
- /*
- When using braces, SQL_CALC_FOUND_ROWS affects the whole query.
- We don't calculate found_rows() per union part
- */
- if (select_limit_cnt == HA_POS_ERROR || sl->braces)
- sl->options&= ~OPTION_FOUND_ROWS;
- else
- {
- /*
- We are doing an union without braces. In this case
- SQL_CALC_FOUND_ROWS should be done on all sub parts
- */
- sl->options|= found_rows_for_union;
- }
- sl->join->select_options=sl->options;
+ /*
+ When using braces, SQL_CALC_FOUND_ROWS affects the whole query:
+ we don't calculate found_rows() per union part.
+ Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts.
+ */
+ sl->join->select_options=
+ (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
res= sl->join->optimize();
}
if (!res)
@@ -498,7 +488,8 @@ bool st_select_lex_unit::exec()
}
/* Needed for the following test and for records_at_start in next loop */
table->file->info(HA_STATUS_VARIABLE);
- if (found_rows_for_union & sl->options)
+ if (found_rows_for_union && !sl->braces &&
+ select_limit_cnt != HA_POS_ERROR)
{
/*
This is a union without braces. Remember the number of rows that
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 54a976fe2b0..477a283448a 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -136,7 +136,7 @@ int mysql_update(THD *thd,
LINT_INIT(timestamp_query_id);
- if (open_tables(thd, table_list, &table_count))
+ if (open_tables(thd, &table_list, &table_count))
DBUG_RETURN(1);
if (table_list->ancestor && table_list->ancestor->next_local)
@@ -635,7 +635,7 @@ bool mysql_multi_update_prepare(THD *thd)
thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
/* open tables and create derived ones, but do not lock and fill them */
- if ((original_multiupdate && open_tables(thd, table_list, & table_count)) ||
+ if ((original_multiupdate && open_tables(thd, &table_list, & table_count)) ||
mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE);
/*
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 96a0dc2f636..31277452118 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -19,6 +19,7 @@
#include "sql_select.h"
#include "parse_file.h"
#include "sp.h"
+#include "sp_head.h"
#define MD5_BUFF_LENGTH 33
@@ -615,10 +616,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length);
view_select= &lex->select_lex;
- /* Only if we're not in the pre-open phase */
- if (!thd->shortcut_make_view)
- view_select->select_number= ++thd->select_number;
- old_lex->derived_tables|= DERIVED_VIEW;
+ view_select->select_number= ++thd->select_number;
{
ulong options= thd->options;
/* switch off modes which can prevent normal parsing of VIEW
@@ -662,35 +660,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
TABLE_LIST *view_tables_tail= 0;
TABLE_LIST *tbl;
- /* move SP to main LEX */
- if (lex->spfuns.records)
- sp_merge_hash(&old_lex->spfuns, &lex->spfuns);
-
- /* cleanup LEX */
- if (lex->spfuns.array.buffer)
- hash_free(&lex->spfuns);
- if (lex->spprocs.array.buffer)
- hash_free(&lex->spprocs);
- if (lex->sptabs.array.buffer)
- hash_free(&lex->sptabs);
-
- /* If we're pre-opening tables to find SPs and tables we need
- not go any further; doing so will cause an infinite loop. */
- if (thd->shortcut_make_view)
- {
- extern bool
- sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
- LEX *lex_for_tmp_check = 0);
-
- sp_merge_table_list(thd, &old_lex->sptabs, view_tables);
- goto ok;
- }
-
/*
- check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
- underlying tables
+ Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
+ underlying tables.
+ Skip this step if we are opening view for prelocking only.
*/
- if ((old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
+ if (!table->prelocking_placeholder &&
+ (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
{
if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
check_table_access(thd, SHOW_VIEW_ACL, table, 1))
@@ -699,7 +675,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto err;
}
}
- else if (old_lex->sql_command == SQLCOM_SHOW_CREATE)
+ else if (!table->prelocking_placeholder &&
+ old_lex->sql_command == SQLCOM_SHOW_CREATE)
{
if (check_table_access(thd, SHOW_VIEW_ACL, table, 0))
goto err;
@@ -717,13 +694,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
tbl->belong_to_view= top_view;
}
- /* move SQL_NO_CACHE & Co to whole query */
- old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
- lex->safe_to_cache_query);
- /* move SQL_CACHE to whole query */
- if (view_select->options & OPTION_TO_QUERY_CACHE)
- old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
-
/*
Put tables of VIEW after VIEW TABLE_LIST
@@ -740,13 +710,30 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
}
else
{
- lex->query_tables_last= &view_tables_tail->next_global;
+ old_lex->query_tables_last= &view_tables_tail->next_global;
}
view_tables->prev_global= &table->next_global;
table->next_global= view_tables;
}
/*
+ If we are opening this view as part of implicit LOCK TABLES, then
+ this view serves as simple placeholder and we should not continue
+ further processing.
+ */
+ if (table->prelocking_placeholder)
+ goto ok2;
+
+ old_lex->derived_tables|= DERIVED_VIEW;
+
+ /* move SQL_NO_CACHE & Co to whole query */
+ old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
+ lex->safe_to_cache_query);
+ /* move SQL_CACHE to whole query */
+ if (view_select->options & OPTION_TO_QUERY_CACHE)
+ old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+
+ /*
check MERGE algorithm ability
- algorithm is not explicit TEMPORARY TABLE
- VIEW SELECT allow merging
@@ -850,8 +837,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto err;
ok:
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
/* global SELECT list linking */
end= view_select; // primary SELECT_LEX is always last
end->link_next= old_lex->all_selects_list;
@@ -860,12 +845,16 @@ ok:
lex->all_selects_list->link_prev=
(st_select_lex_node**)&old_lex->all_selects_list;
+ok2:
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
thd->lex= old_lex;
DBUG_RETURN(0);
err:
if (arena)
thd->restore_backup_item_arena(arena, &backup);
+ delete table->view;
table->view= 0; // now it is not VIEW placeholder
thd->lex= old_lex;
DBUG_RETURN(1);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a69b6a96982..fae01502a8d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1548,12 +1548,12 @@ sp_opt_inout:
sp_proc_stmts:
/* Empty */ {}
- | sp_proc_stmts { Lex->query_tables= 0; } sp_proc_stmt ';'
+ | sp_proc_stmts sp_proc_stmt ';'
;
sp_proc_stmts1:
sp_proc_stmt ';' {}
- | sp_proc_stmts1 { Lex->query_tables= 0; } sp_proc_stmt ';'
+ | sp_proc_stmts1 sp_proc_stmt ';'
;
sp_decls:
@@ -1587,13 +1587,15 @@ sp_decls:
;
sp_decl:
- DECLARE_SYM sp_decl_idents type sp_opt_default
+ DECLARE_SYM sp_decl_idents type
+ { Lex->sphead->reset_lex(YYTHD); }
+ sp_opt_default
{
LEX *lex= Lex;
sp_pcontext *ctx= lex->spcont;
uint max= ctx->context_pvars();
enum enum_field_types type= (enum enum_field_types)$3;
- Item *it= $4;
+ Item *it= $5;
for (uint i = max-$2 ; i < max ; i++)
{
@@ -1605,15 +1607,19 @@ sp_decl:
sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
ctx,
ctx->pvar_context2index(i),
- it, type);
+ it, type, lex,
+ (i == max - 1));
- in->tables= lex->query_tables;
- lex->query_tables= 0;
+ /*
+ The last instruction is assigned to be responsible for
+ freeing LEX.
+ */
lex->sphead->add_instr(in);
ctx->set_isset(i, TRUE);
ctx->set_default(i, it);
}
}
+ lex->sphead->restore_lex(YYTHD);
$$.vars= $2;
$$.conds= $$.hndlrs= $$.curs= 0;
}
@@ -1865,36 +1871,39 @@ sp_proc_stmt:
my_message(ER_SP_NO_USE, ER(ER_SP_NO_USE), MYF(0));
YYABORT;
}
- /* Don't add an instruction for empty SET statements.
- ** (This happens if the SET only contained local variables,
- ** which get their set instructions generated separately.)
+ /*
+ Don't add an instruction for SET statements, since all
+ instructions for them were already added during processing
+ of "set" rule.
*/
- if (lex->sql_command != SQLCOM_SET_OPTION ||
- ! lex->var_list.is_empty())
+ DBUG_ASSERT(lex->sql_command != SQLCOM_SET_OPTION ||
+ lex->var_list.is_empty());
+ if (lex->sql_command != SQLCOM_SET_OPTION)
{
- sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
- lex->spcont);
-
- /* Extract the query statement from the tokenizer:
- The end is either lex->tok_end or tok->ptr. */
- if (lex->ptr - lex->tok_end > 1)
- i->m_query.length= lex->ptr - sp->m_tmp_query;
- else
- i->m_query.length= lex->tok_end - sp->m_tmp_query;
- i->m_query.str= strmake_root(YYTHD->mem_root,
- (char *)sp->m_tmp_query,
- i->m_query.length);
- i->set_lex(lex);
- sp->add_instr(i);
- lex->sp_lex_in_use= TRUE;
- }
+ sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
+ lex->spcont, lex);
+
+ /* Extract the query statement from the tokenizer:
+ The end is either lex->tok_end or tok->ptr. */
+ if (lex->ptr - lex->tok_end > 1)
+ i->m_query.length= lex->ptr - sp->m_tmp_query;
+ else
+ i->m_query.length= lex->tok_end - sp->m_tmp_query;
+ i->m_query.str= strmake_root(YYTHD->mem_root,
+ (char *)sp->m_tmp_query,
+ i->m_query.length);
+ sp->add_instr(i);
+ }
sp->restore_lex(YYTHD);
}
- | RETURN_SYM expr
+ | RETURN_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr
{
LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
- if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE)
+ if (sp->m_type == TYPE_ENUM_PROCEDURE)
{
my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
YYABORT;
@@ -1903,12 +1912,12 @@ sp_proc_stmt:
{
sp_instr_freturn *i;
- i= new sp_instr_freturn(lex->sphead->instructions(),
- lex->spcont,
- $2, lex->sphead->m_returns);
- lex->sphead->add_instr(i);
- lex->sphead->m_has_return= TRUE;
+ i= new sp_instr_freturn(sp->instructions(), lex->spcont,
+ $3, sp->m_returns, lex);
+ sp->add_instr(i);
+ sp->m_has_return= TRUE;
}
+ sp->restore_lex(YYTHD);
}
| IF sp_if END IF {}
| CASE_SYM WHEN_SYM
@@ -1916,7 +1925,9 @@ sp_proc_stmt:
Lex->sphead->m_simple_case= FALSE;
}
sp_case END CASE_SYM {}
- | CASE_SYM expr WHEN_SYM
+ | CASE_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr WHEN_SYM
{
/* We "fake" this by using an anonymous variable which we
set to the expression. Note that all WHENs are evaluate
@@ -1925,15 +1936,14 @@ sp_proc_stmt:
LEX *lex= Lex;
uint offset= lex->spcont->current_pvars();
sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
- lex->spcont,
- offset, $2, MYSQL_TYPE_STRING);
+ lex->spcont, offset, $3,
+ MYSQL_TYPE_STRING, lex, TRUE);
LEX_STRING dummy={(char*)"", 0};
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
- i->tables= lex->query_tables;
- lex->query_tables= 0;
lex->sphead->add_instr(i);
lex->sphead->m_simple_case= TRUE;
+ lex->sphead->restore_lex(YYTHD);
}
sp_case END CASE_SYM
{
@@ -2187,18 +2197,19 @@ sp_fetch_list:
;
sp_if:
- expr THEN_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr THEN_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
uint ip= sp->instructions();
- sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $1);
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
+ $2, lex);
- i->tables= lex->query_tables;
- lex->query_tables= 0;
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_instr(i);
+ sp->restore_lex(YYTHD);
}
sp_proc_stmts1
{
@@ -2226,7 +2237,8 @@ sp_elseifs:
;
sp_case:
- expr THEN_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr THEN_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -2235,7 +2247,7 @@ sp_case:
sp_instr_jump_if_not *i;
if (! sp->m_simple_case)
- i= new sp_instr_jump_if_not(ip, ctx, $1);
+ i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
else
{ /* Simple case: <caseval> = <whenval> */
LEX_STRING ivar;
@@ -2244,15 +2256,14 @@ sp_case:
ivar.length= 5;
Item *var= (Item*) new Item_splocal(ivar,
ctx->current_pvars()-1);
- Item *expr= new Item_func_eq(var, $1);
+ Item *expr= new Item_func_eq(var, $2);
- i= new sp_instr_jump_if_not(ip, ctx, expr);
+ i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
lex->variables_used= 1;
}
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- i->tables= lex->query_tables;
- lex->query_tables= 0;
sp->add_instr(i);
+ sp->restore_lex(YYTHD);
}
sp_proc_stmts1
{
@@ -2368,19 +2379,20 @@ sp_unlabeled_control:
lex->sphead->add_instr(i);
}
- | WHILE_SYM expr DO_SYM
+ | WHILE_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr DO_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
- $2);
+ $3, lex);
/* Jumping forward */
sp->push_backpatch(i, lex->spcont->last_label());
- i->tables= lex->query_tables;
- lex->query_tables= 0;
sp->add_instr(i);
+ sp->restore_lex(YYTHD);
}
sp_proc_stmts1 END WHILE_SYM
{
@@ -2391,17 +2403,18 @@ sp_unlabeled_control:
lex->sphead->add_instr(i);
}
- | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM expr END REPEAT_SYM
+ | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
+ { Lex->sphead->reset_lex(YYTHD); }
+ expr END REPEAT_SYM
{
LEX *lex= Lex;
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
- $4, lab->ip);
-
- i->tables= lex->query_tables;
- lex->query_tables= 0;
+ $5, lab->ip,
+ lex);
lex->sphead->add_instr(i);
+ lex->sphead->restore_lex(YYTHD);
}
;
@@ -7168,8 +7181,75 @@ opt_option:
| OPTION {};
option_value_list:
+ option_type_value
+ | option_value_list ',' option_type_value;
+
+option_type_value:
+ {
+ if (Lex->sphead)
+ {
+ /*
+ If we are in SP we want have own LEX for each assignment.
+ This is mostly because it is hard for several sp_instr_set
+ and sp_instr_set_trigger instructions share one LEX.
+ (Well, it is theoretically possible but adds some extra
+ overhead on preparation for execution stage and IMO less
+ robust).
+
+ QQ: May be we should simply prohibit group assignments in SP?
+ */
+ LEX *lex;
+ Lex->sphead->reset_lex(YYTHD);
+ lex= Lex;
+
+ /* Set new LEX as if we at start of set rule. */
+ lex->sql_command= SQLCOM_SET_OPTION;
+ mysql_init_select(lex);
+ lex->option_type=OPT_SESSION;
+ lex->var_list.empty();
+ lex->one_shot_set= 0;
+ lex->sphead->m_tmp_query= lex->tok_start;
+ }
+ }
option_type option_value
- | option_value_list ',' option_type option_value;
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ sp_head *sp= lex->sphead;
+
+ if (!lex->var_list.is_empty())
+ {
+ /*
+ We have assignment to user or system variable or
+ option setting, so we should construct sp_instr_stmt
+ for it.
+ */
+ LEX_STRING qbuff;
+ sp_instr_stmt *i;
+
+ if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
+ lex)))
+ YYABORT;
+
+ if (lex->ptr - lex->tok_end > 1)
+ qbuff.length= lex->ptr - sp->m_tmp_query;
+ else
+ qbuff.length= lex->tok_end - sp->m_tmp_query;
+
+ if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
+ YYABORT;
+
+ strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
+ qbuff.length);
+ qbuff.length+= 4;
+ i->m_query= qbuff;
+ sp->add_instr(i);
+ }
+ lex->sphead->restore_lex(YYTHD);
+ }
+ };
option_type:
/* empty */ {}
@@ -7196,31 +7276,7 @@ opt_var_ident_type:
option_value:
'@' ident_or_text equal expr
{
- LEX *lex= Lex;
-
- if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
- {
- /*
- We have to use special instruction in functions and triggers
- because sp_instr_stmt will close all tables and thus ruin
- execution of statement invoking function or trigger.
-
- We also do not want to allow expression with subselects in
- this case.
- */
- if (lex->query_tables)
- {
- my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
- MYF(0));
- YYABORT;
- }
- sp_instr_set_user_var *i=
- new sp_instr_set_user_var(lex->sphead->instructions(),
- lex->spcont, $2, $4);
- lex->sphead->add_instr(i);
- }
- else
- lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
+ Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
}
| internal_variable_name equal set_expr_or_default
{
@@ -7281,9 +7337,7 @@ option_value:
else
it= new Item_null();
i= new sp_instr_set(lex->sphead->instructions(), ctx,
- spv->offset, it, spv->type);
- i->tables= lex->query_tables;
- lex->query_tables= 0;
+ spv->offset, it, spv->type, lex, TRUE);
lex->sphead->add_instr(i);
spv->isset= TRUE;
}
diff --git a/sql/table.cc b/sql/table.cc
index 31d20271707..63da10c687a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1276,6 +1276,10 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
uint key_length;
ulong length;
char fill[IO_SIZE];
+ int create_flags= O_RDWR | O_TRUNC;
+
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ create_flags|= O_EXCL | O_NOFOLLOW;
#if SIZEOF_OFF_T > 4
/* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */
@@ -1290,7 +1294,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
*/
set_if_smaller(create_info->raid_chunks, 255);
- if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0)
{
bzero((char*) fileinfo,64);
/* header */
diff --git a/sql/table.h b/sql/table.h
index 5ab1f900195..49ead2cb0b7 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -339,6 +339,15 @@ typedef struct st_table_list
char *db, *alias, *table_name, *schema_table_name;
char *option; /* Used by cache index */
Item *on_expr; /* Used with outer join */
+ /*
+ The scturcture of ON expression presented in the member above
+ can be changed during certain optimizations. This member
+ contains a snapshot of AND-OR structure of the ON expression
+ made after permanent transformations of the parse tree, and is
+ used to restore ON clause before every reexecution of a prepared
+ statement or stored procedure.
+ */
+ Item *prep_on_expr;
COND_EQUAL *cond_equal; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
@@ -420,6 +429,11 @@ typedef struct st_table_list
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
char timestamp_buffer[20]; /* buffer for timestamp (19+1) */
+ /*
+ This TABLE_LIST object is just placeholder for prelocking, it will be
+ used for implicit LOCK TABLES only and won't be used in real statement.
+ */
+ bool prelocking_placeholder;
void calc_md5(char *buffer);
void set_ancestor();
diff --git a/sql/tztime.cc b/sql/tztime.cc
index b2b3576e221..bd9d49f0ab0 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1524,7 +1524,6 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
TZ_NAMES_ENTRY *tmp_tzname;
my_bool return_val= 1;
int res;
- uint counter;
DBUG_ENTER("my_tz_init");
/*
@@ -1593,8 +1592,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
last_global_next_ptr= &(tables_buff[0].next_global);
tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
- if (open_tables(thd, tables_buff, &counter) ||
- lock_tables(thd, tables_buff, counter))
+ if (simple_open_n_lock_tables(thd, tables_buff))
{
sql_print_warning("Can't open and lock time zone table: %s "
"trying to live without them", thd->net.last_error);
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 916ef6d271b..9f0e334d3a9 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -67,6 +67,13 @@ static uchar bin_char_array[] =
};
+static my_bool
+my_coll_init_8bit_bin(CHARSET_INFO *cs,
+ void *(*alloc)(uint) __attribute__((unused)))
+{
+ cs->max_sort_char=255;
+ return FALSE;
+}
static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
const uchar *s, uint slen,
@@ -443,7 +450,7 @@ skip:
MY_COLLATION_HANDLER my_collation_8bit_bin_handler =
{
- NULL, /* init */
+ my_coll_init_8bit_bin,
my_strnncoll_8bit_bin,
my_strnncollsp_8bit_bin,
my_strnxfrm_8bit_bin,
diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c
index 37611a5bd20..8c58520f965 100644
--- a/strings/ctype-win1250ch.c
+++ b/strings/ctype-win1250ch.c
@@ -416,7 +416,7 @@ static struct wordvalue doubles[] = {
#define NEXT_CMP_VALUE(src, p, pass, value, len) \
while (1) { \
if (IS_END(p, src, len)) { \
- if (pass == 0) { p = src; pass++; } \
+ if (pass == 0 && len > 0) { p= src; pass++; } \
else { value = 0; break; } \
} \
value = ((pass == 0) ? _sort_order_win1250ch1[*p] \
diff --git a/vio/vio.c b/vio/vio.c
index ea254e2ed5a..6227493b994 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -27,20 +27,23 @@
* Helper to fill most of the Vio* with defaults.
*/
-void vio_reset(Vio* vio, enum enum_vio_type type,
- my_socket sd, HANDLE hPipe,
- my_bool localhost)
+static void vio_init(Vio* vio, enum enum_vio_type type,
+ my_socket sd, HANDLE hPipe, uint flags)
{
- DBUG_ENTER("vio_reset");
- DBUG_PRINT("enter", ("type: %d sd: %d localhost: %d", type, sd,
- localhost));
+ DBUG_ENTER("vio_init");
+ DBUG_PRINT("enter", ("type: %d sd: %d flags: %d", type, sd, flags));
+#ifndef HAVE_VIO_READ_BUFF
+ flags&= ~VIO_BUFFERED_READ;
+#endif
bzero((char*) vio, sizeof(*vio));
vio->type = type;
vio->sd = sd;
vio->hPipe = hPipe;
- vio->localhost= localhost;
-#ifdef HAVE_VIO
+ vio->localhost= flags & VIO_LOCALHOST;
+ if ((flags & VIO_BUFFERED_READ) &&
+ !(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
+ flags&= ~VIO_BUFFERED_READ;
#ifdef __WIN__
if (type == VIO_TYPE_NAMEDPIPE)
{
@@ -101,7 +104,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
{
vio->viodelete =vio_delete;
vio->vioerrno =vio_errno;
- vio->read =vio_read;
+ vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read;
vio->write =vio_write;
vio->fastsend =vio_fastsend;
vio->viokeepalive =vio_keepalive;
@@ -113,21 +116,30 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
vio->is_blocking =vio_is_blocking;
vio->timeout =vio_timeout;
}
-#endif /* HAVE_VIO */
DBUG_VOID_RETURN;
}
+/* Reset initialized VIO to use with another transport type */
+
+void vio_reset(Vio* vio, enum enum_vio_type type,
+ my_socket sd, HANDLE hPipe, uint flags)
+{
+ my_free(vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ vio_init(vio, type, sd, hPipe, flags);
+}
+
+
/* Open the socket or TCP/IP connection and read the fnctl() status */
-Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
+Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
{
Vio *vio;
DBUG_ENTER("vio_new");
DBUG_PRINT("enter", ("sd: %d", sd));
if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
{
- vio_reset(vio, type, sd, 0, localhost);
+ vio_init(vio, type, sd, 0, flags);
sprintf(vio->desc,
(vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
vio->sd);
@@ -163,7 +175,7 @@ Vio *vio_new_win32pipe(HANDLE hPipe)
DBUG_ENTER("vio_new_handle");
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
{
- vio_reset(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, TRUE);
+ vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, VIO_LOCALHOST);
strmov(vio->desc, "named pipe");
}
DBUG_RETURN(vio);
@@ -179,7 +191,7 @@ Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_m
DBUG_ENTER("vio_new_win32shared_memory");
if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
{
- vio_reset(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, TRUE);
+ vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, VIO_LOCALHOST);
vio->handle_file_map= handle_file_map;
vio->handle_map= handle_map;
vio->event_server_wrote= event_server_wrote;
@@ -204,11 +216,8 @@ void vio_delete(Vio* vio)
if (vio)
{
if (vio->type != VIO_CLOSED)
-#ifdef HAVE_VIO /*WAX*/
vio->vioclose(vio);
-#else
- vio_close(vio);
-#endif
+ my_free((gptr) vio->read_buffer, MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) vio,MYF(0));
}
}
diff --git a/vio/viosocket.c b/vio/viosocket.c
index 43bd4e82013..ea85a69e2d4 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -35,6 +35,8 @@ int vio_read(Vio * vio, gptr buf, int size)
DBUG_ENTER("vio_read");
DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+ /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
+ DBUG_ASSERT(vio->read_end == vio->read_pos);
#ifdef __WIN__
r = recv(vio->sd, buf, size,0);
#else
@@ -52,6 +54,50 @@ int vio_read(Vio * vio, gptr buf, int size)
}
+/*
+ Buffered read: if average read size is small it may
+ reduce number of syscalls.
+*/
+
+int vio_read_buff(Vio *vio, gptr buf, int size)
+{
+ int rc;
+#define VIO_UNBUFFERED_READ_MIN_SIZE 2048
+ DBUG_ENTER("vio_read_buff");
+ DBUG_PRINT("enter", ("sd: %d, buf: 0x%p, size: %d", vio->sd, buf, size));
+
+ if (vio->read_pos < vio->read_end)
+ {
+ rc= min(vio->read_end - vio->read_pos, size);
+ memcpy(buf, vio->read_pos, rc);
+ vio->read_pos+= rc;
+ /*
+ Do not try to read from the socket now even if rc < size:
+ vio_read can return -1 due to an error or non-blocking mode, and
+ the safest way to handle it is to move to a separate branch.
+ */
+ }
+ else if (size < VIO_UNBUFFERED_READ_MIN_SIZE)
+ {
+ rc= vio_read(vio, vio->read_buffer, VIO_READ_BUFFER_SIZE);
+ if (rc > 0)
+ {
+ if (rc > size)
+ {
+ vio->read_pos= vio->read_buffer + size;
+ vio->read_end= vio->read_buffer + rc;
+ rc= size;
+ }
+ memcpy(buf, vio->read_buffer, rc);
+ }
+ }
+ else
+ rc= vio_read(vio, buf, size);
+ DBUG_RETURN(rc);
+#undef VIO_UNBUFFERED_READ_MIN_SIZE
+}
+
+
int vio_write(Vio * vio, const gptr buf, int size)
{
int r;